Zabbix Server内存泄漏排查及优化实践
作为当下主流开源监控系统之一,Zabbix通常被用来监控各类基础设施和应用程序的性能指标。但是当Zabbix Server自身出现内存泄漏时,监控者反而成为被监控对象。这篇文章将基于生产环境案例,来谈一谈Zabbix Server内存发生泄漏时的排查过程与优化方案。
1.1 异常现象观察
最近再在排查监控系统时,发现平台持续推送Zabbix Server内存使用率超标的告警。经初步观察发现:
内存使用率由正常的40%逐步攀升至95%以上
Zabbix Server响应延迟明显增加
Web界面数据刷新也变得缓慢
1.2 初步诊断流程
# 检查系统整体内存状况$ free -htotal used free shared buff/cache availableMem: 16Gi 15Gi 512Mi 128Mi 512Mi 128MiSwap: 4Gi 3.5Gi 512Mi# 定位内存占用最高进程$ ps aux --sort=-%mem | head -10USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMANDzabbix 1234 45.2 58.3 4681232 3824564 ? Ssl Jun01 120:45 /usr/sbin/zabbix_server -c /etc/zabbix/zabbix_server.conf
通过pmap命令进一步分析进程内存分布:
pmap -x 1234 | sort -k3 -n -r | head -20Address Kbytes RSS Dirty Mode Mapping00007f8a5b400000 1048576 786432 786432 rw--- [ anon ]00007f8a4b400000 524288 262144 262144 rw--- [ anon ]00007f8a53400000 262144 131072 131072 rw--- [ anon ]
观察发现,匿名映射内存区域([ anon ])占用异常高,暗示可能存在内存泄漏。
2.1 日志分析
检查Zabbix Server日志,发现规律性警告:
2025-12-15 14:23:45.1232025-12-15 14:23:46.4562025-12-15 14:23:47.789
日志显示历史数据处理队列持续增长,处理速率低于数据产生速率。
2.2 内存泄漏检测工具应用
2.2.1 使用Valgrind进行内存分析
在测试环境复现问题并进行内存分析:
配置调试版本Zabbix Server./configure --enable-debug --enable-server --with-mysql使用Valgrind运行Zabbix Servervalgrind --tool=memcheck \--leak-check=full \--show-leak-kinds=all \--track-origins=yes \--log-file=/var/log/zabbix/valgrind.log \/usr/sbin/zabbix_server -c /etc/zabbix/zabbix_server.conf
2.2.2 分析结果
Valgrind报告显示多处内存泄漏,其中一处关键发现:
==12345== 24,576 bytes in 24 blocks are definitely lost in loss record 15 of 35==12345== at 0x483877F: malloc (vg_replace_malloc.c:307)==12345== by 0x567890A: zbx_malloc (zbxcommon.c:123)==12345== by 0x678901B: history_sync_thread (history.c:789)==12345== by 0x456789C: ZBX_THREAD_ENTRY (threads.c:345)
2.3 源码级问题定位
根据Valgrind报告定位到具体源码文件。以下是存在问题的代码段:
/* src/zabbix_server/history/history.c */static int process_history_batch(zbx_vector_ptr_t *history_items){int processed = 0;for (int i = 0; i < history_items->values_num; i++){zbx_history_record_t *record = history_items->values[i];/* 问题点:每次迭代都创建新缓存但未释放 */char *processing_buffer = zbx_malloc(NULL, PROCESSING_BUFFER_SIZE);if (NULL == processing_buffer){zabbix_log(LOG_LEVEL_WARNING, "memory allocation failed");return FAIL;}/* 数据处理逻辑 */int ret = transform_history_record(record, processing_buffer);if (SUCCEED == ret){processed++;}/* 内存泄漏:缺少 zbx_free(processing_buffer) */}return processed;}
问题分析:
(1)在循环内部动态分配内存(zbx_malloc)
(2)每次迭代分配PROCESSING_BUFFER_SIZE字节(通常为1KB)
(3)缺少相应的内存释放操作
(4)随着历史数据处理量的增加,未释放内存持续累积
3.1 临时应急措施
对于生产环境,立即采取以下措施控制问题影响:
# 调整Zabbix Server配置参数$ vi /etc/zabbix/zabbix_server.conf# 优化配置参数StartPollers=30 # 原值:100StartPreprocessors=5 # 原值:10StartHistoryPollers=4 # 原值:8HistoryCacheSize=128M # 原值:256MTrendCacheSize=32M # 原值:128MValueCacheSize=256M # 原值:512M# 重启服务应用配置$ systemctl restart zabbix-server# 监控内存回收情况$ watch -n 1 'ps -p $(pidof zabbix_server) -o %mem,rss,cmd'
3.2 代码级修复方案
3.2.1 修复策略选择
针对发现的内存泄漏问题,设计两种修复方案:
方案A:循环内分配释放(简单修复)
# 调整Zabbix Server配置参数$ vi /etc/zabbix/zabbix_server.conf# 优化配置参数StartPollers=30 # 原值:100StartPreprocessors=5 # 原值:10StartHistoryPollers=4 # 原值:8HistoryCacheSize=128M # 原值:256MTrendCacheSize=32M # 原值:128MValueCacheSize=256M # 原值:512M# 重启服务应用配置$ systemctl restart zabbix-server# 监控内存回收情况$ watch -n 1 'ps -p $(pidof zabbix_server) -o %mem,rss,cmd'
方案B:预分配与复用(性能优化)
static int process_history_batch(zbx_vector_ptr_t *history_items){int processed = 0;for (int i = 0; i < history_items->values_num; i++){zbx_history_record_t *record = history_items->values[i];char *processing_buffer = zbx_malloc(NULL, PROCESSING_BUFFER_SIZE);if (NULL == processing_buffer){zabbix_log(LOG_LEVEL_WARNING, "memory allocation failed");return FAIL;}int ret = transform_history_record(record, processing_buffer);/* 修复:每次迭代后释放内存 */zbx_free(processing_buffer);if (SUCCEED == ret){processed++;}}return processed;}
3.2.2 修复实施步骤
获取对应版本源码
确定当前Zabbix版本zabbix_server -V | grep versionzabbix_server (Zabbix) 6.4.0下载对应版本源码wget https://cdn.zabbix.com/zabbix/sources/stable/6.4/zabbix-6.4.0.tar.gztar -zxvf zabbix-6.4.0.tar.gzcd zabbix-6.4.0
应用修复补丁
# history_memory_leak_fix.patch--- src/zabbix_server/history/history.c.orig+++ src/zabbix_server/history/history.cstatic int process_history_batch(zbx_vector_ptr_t *history_items){int processed = 0;+ char *processing_buffer = NULL;++ /* 预分配处理缓冲区 */+ processing_buffer = zbx_malloc(NULL, PROCESSING_BUFFER_SIZE);+ if (NULL == processing_buffer)+ {+ zabbix_log(LOG_LEVEL_WARNING, "memory allocation failed for processing buffer");+ return FAIL;+ }for (int i = 0; i < history_items->values_num; i++){zbx_history_record_t *record = history_items->values[i];- char *processing_buffer = zbx_malloc(NULL, PROCESSING_BUFFER_SIZE);-- if (NULL == processing_buffer)- {- zabbix_log(LOG_LEVEL_WARNING, "memory allocation failed");- return FAIL;- }+ /* 清空缓冲区以复用 */+ memset(processing_buffer, 0, PROCESSING_BUFFER_SIZE);int ret = transform_history_record(record, processing_buffer);-- /* 内存泄漏:缺少 zbx_free(processing_buffer) */if (SUCCEED == ret){processed++;}-- /* 修复:每次迭代后释放内存 */- zbx_free(processing_buffer);}+ /* 释放预分配的内存 */+ zbx_free(processing_buffer);+return processed;}
编译与部署
应用补丁patch -p1 < history_memory_leak_fix.patch配置编译环境./configure --enable-server \--with-mysql \--with-libcurl \--with-libxml2 \--with-net-snmp编译安装make -j$(nproc)make install验证修复valgrind --tool=memcheck \--leak-check=summary \/usr/sbin/zabbix_server --test
4.1 监控系统自监控配置
为防止类似问题再次发生,配置Zabbix监控自身关键指标:
监控项配置示例:
-- 创建监控Zabbix Server内存使用的SQL查询INSERT INTO items (hostid, name, key_, type, value_type,units, multiplier, delta, history, trends) VALUES ((SELECT hostid FROM hosts WHERE host = 'Zabbix server'),'Zabbix Server memory usage','proc.mem[zabbix_server,,,rss]',0, 3, 'B', 1, 0, 7, 365);
触发器配置:
触发器名称:Zabbix Server内存使用异常增长表达式:{Zabbix server:proc.mem[zabbix_server,,,rss].increase(5m)} > 100M和 {Zabbix server:proc.mem[zabbix_server,,,rss].last()} > 2G严重性:严重恢复表达式:{Zabbix server:proc.mem[zabbix_server,,,rss].last()} < 1.5G
4.2 定期维护与优化策略
制定定期维护计划:
每周维护任务:
(1) 检查Zabbix Server日志中的内存相关警告
(2)分析历史数据增长趋势
(3)验证数据库索引效率
每月维护任务:
(1)执行压力测试验证系统极限
(2)评估和调整缓存参数
(3)审查自定义脚本和用户参数的内存使用
配置优化建议:
# /etc/zabbix/zabbix_server.conf 优化配置### 内存相关优化 #### 根据物理内存大小调整缓存HistoryCacheSize=256M # 历史数据缓存,建议为可用内存的5-10%TrendCacheSize=64M # 趋势数据缓存ValueCacheSize=512M # 值缓存,对性能影响较大### 并发处理优化 #### 根据CPU核心数调整StartPollers=50 # 建议为CPU核心数的2-3倍StartPreprocessors=10 # 预处理进程数StartHistoryPollers=8 # 历史数据同步进程### 数据库连接优化 ###DBHost=localhostDBPort=3306DBName=zabbixDBUser=zabbix# 连接池配置StartDBSyncers=4 # 数据库同步进程HouseskeepingFrequency=1 # 小时,清理旧数据频率
5.1 修复效果验证
修复后持续监控内存使用情况:
# 监控内存使用趋势$ watch -n 60 "echo '===== 内存使用统计 =====';ps -p \$(pidof zabbix_server) -o rss,size,%mem,cmd --no-headers | \\awk '{printf \"RSS: %.2fGB\\tVirtual: %.2fGB\\tMEM%%: %.1f%%\\n\", \$1/1024/1024, \$2/1024/1024, \$3}';echo '';echo '===== 系统内存统计 =====';free -h | grep -E '^(Mem|Swap)'"
5.2 长期监控指标
建立以下关键性能指标监控体系:
(1)内存使用率:不超过物理内存的70%
(2)内存泄漏检测:连续1小时内存增长超过100MB触发告警
(3)处理队列长度:各处理器队列长度不超过1000
(4)数据库连接数:活跃连接数不超过最大连接的80%
通过本次内存泄漏排查与修复,我们总结出以下关键经验:
(1)预防优于修复
开发阶段实施严格的内存管理规范
代码审查重点关注资源分配与释放的对称性
自动化测试包含内存泄漏检测用例
(2)监控体系完善性
监控系统必须包含对自身的监控
建立多维度、多层次的监控告警体系
定期审查监控项的有效性和准确性
(3)应急响应机制
建立标准化的故障排查流程
制定不同严重级别问题的响应策略
保持故障处理的知识库更新
附录:常用诊断命令参考
# 1. 内存使用分析pmap -x <pid> # 进程内存映射详情cat /proc/<pid>/smaps # 详细内存段信息cat /proc/<pid>/status # 进程状态信息# 2. 性能分析strace -p <pid> -c # 系统调用统计perf top -p <pid> # 实时性能分析# 3. Zabbix专用诊断zabbix_server -R config_cache_reload # 重载配置缓存zabbix_server -R housekeeper_execute # 手动执行清理任务# 4. 数据库分析# 查看历史数据表大小SELECTtable_name,ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mbFROM information_schema.tablesWHERE table_schema = 'zabbix'ORDER BY size_mb DESC;



