Zabbix Server内存泄漏排查及优化实践

文章目录

    • 引言
    • 一、问题识别与初步诊断
      • [1.1 异常现象观察](#1.1 异常现象观察)
      • [1.2 初步诊断流程](#1.2 初步诊断流程)
    • 二、深入分析与定位
      • [2.1 日志分析](#2.1 日志分析)
      • [2.2 内存泄漏检测工具应用](#2.2 内存泄漏检测工具应用)
        • [2.2.1 使用Valgrind进行内存分析](#2.2.1 使用Valgrind进行内存分析)
        • [2.2.2 分析结果](#2.2.2 分析结果)
      • [2.3 源码级问题定位](#2.3 源码级问题定位)
    • 三、修复方案设计与实施
      • [3.1 临时应急措施](#3.1 临时应急措施)
      • [3.2 代码级修复方案](#3.2 代码级修复方案)
        • [3.2.1 修复策略选择](#3.2.1 修复策略选择)
        • [3.2.2 修复实施步骤](#3.2.2 修复实施步骤)
    • 四、配置优化与预防措施
      • [4.1 监控系统自监控配置](#4.1 监控系统自监控配置)
      • [4.2 定期维护与优化策略](#4.2 定期维护与优化策略)
    • 五、效果验证与监控
      • [5.1 修复效果验证](#5.1 修复效果验证)
      • [5.2 长期监控指标](#5.2 长期监控指标)
    • 总结
    • 附录:常用诊断命令参考

引言

作为当下主流开源监控系统之一,Zabbix通常被用来监控各类基础设施和应用程序的性能指标。但是当Zabbix Server自身出现内存泄漏时,监控者反而成为被监控对象。这篇文章将基于生产环境案例,来谈一谈Zabbix Server内存发生泄漏时的排查过程与优化方案。

一、问题识别与初步诊断

1.1 异常现象观察

最近再在排查监控系统时,发现平台持续推送Zabbix Server内存使用率超标的告警。

经初步观察发现:

  • 内存使用率由正常的40%逐步攀升至95%以上
  • Zabbix Server响应延迟明显增加
  • Web界面数据刷新也变得缓慢

1.2 初步诊断流程

c 复制代码
# 检查系统整体内存状况
$ free -h
              total        used        free      shared  buff/cache   available
Mem:           16Gi        15Gi       512Mi       128Mi       512Mi       128Mi
Swap:          4Gi        3.5Gi       512Mi
# 定位内存占用最高进程
$ ps aux --sort=-%mem | head -10
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
zabbix    1234 45.2 58.3 4681232 3824564 ?     Ssl  Jun01 120:45 /usr/sbin/zabbix_server -c /etc/zabbix/zabbix_server.conf

通过pmap命令进一步分析进程内存分布:

c 复制代码
$ pmap -x 1234 | sort -k3 -n -r | head -20
Address           Kbytes     RSS   Dirty Mode  Mapping
00007f8a5b400000 1048576  786432  786432 rw---   [ anon ]
00007f8a4b400000  524288  262144  262144 rw---   [ anon ]
00007f8a53400000  262144  131072  131072 rw---   [ anon ]

观察发现,匿名映射内存区域([ anon ])占用异常高,暗示可能存在内存泄漏。

二、深入分析与定位

2.1 日志分析

检查Zabbix Server日志,发现规律性警告:

c 复制代码
2025-12-15 14:23:45.123 [WARNING] [12345] history syncer [processed 250 of 2500 items in 0.123456 seconds]
2025-12-15 14:23:46.456 [WARNING] [12345] queue is growing: history syncer [processed 120 of 3000 items]
2025-12-15 14:23:47.789 [DEBUG] [12345] Memory usage: 4321.45 MB

日志显示历史数据处理队列持续增长,处理速率低于数据产生速率。

2.2 内存泄漏检测工具应用

2.2.1 使用Valgrind进行内存分析

在测试环境复现问题并进行内存分析:

c 复制代码
# 配置调试版本Zabbix Server
$ ./configure --enable-debug --enable-server --with-mysql
# 使用Valgrind运行Zabbix Server
$ valgrind --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报告显示多处内存泄漏,其中一处关键发现:

c 复制代码
==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报告定位到具体源码文件。以下是存在问题的代码段:

c 复制代码
/* 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 临时应急措施

对于生产环境,立即采取以下措施控制问题影响:

c 复制代码
# 调整Zabbix Server配置参数
$ vi /etc/zabbix/zabbix_server.conf
# 优化配置参数
StartPollers=30                 # 原值:100
StartPreprocessors=5           # 原值:10
StartHistoryPollers=4          # 原值:8
HistoryCacheSize=128M          # 原值:256M
TrendCacheSize=32M            # 原值:128M
ValueCacheSize=256M           # 原值:512M
# 重启服务应用配置
$ systemctl restart zabbix-server
# 监控内存回收情况
$ watch -n 1 'ps -p $(pidof zabbix_server) -o %mem,rss,cmd'

3.2 代码级修复方案

3.2.1 修复策略选择

针对发现的内存泄漏问题,设计两种修复方案:

方案A:循环内分配释放(简单修复)

c 复制代码
# 调整Zabbix Server配置参数
$ vi /etc/zabbix/zabbix_server.conf
# 优化配置参数
StartPollers=30                 # 原值:100
StartPreprocessors=5           # 原值:10
StartHistoryPollers=4          # 原值:8
HistoryCacheSize=128M          # 原值:256M
TrendCacheSize=32M            # 原值:128M
ValueCacheSize=256M           # 原值:512M
# 重启服务应用配置
$ systemctl restart zabbix-server
# 监控内存回收情况
$ watch -n 1 'ps -p $(pidof zabbix_server) -o %mem,rss,cmd'

方案B:预分配与复用(性能优化)

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);
        /* 修复:每次迭代后释放内存 */
        zbx_free(processing_buffer);
        if (SUCCEED == ret)
        {
            processed++;
        }
    }
    return processed;
}
3.2.2 修复实施步骤

获取对应版本源码

c 复制代码
# 确定当前Zabbix版本
$ zabbix_server -V | grep version
zabbix_server (Zabbix) 6.4.0
# 下载对应版本源码
$ wget https://cdn.zabbix.com/zabbix/sources/stable/6.4/zabbix-6.4.0.tar.gz
$ tar -zxvf zabbix-6.4.0.tar.gz
$ cd zabbix-6.4.0

应用修复补丁

c 复制代码
# history_memory_leak_fix.patch
--- src/zabbix_server/history/history.c.orig
+++ src/zabbix_server/history/history.c
@@ -456,15 +456,19 @@
 static 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;
 }

编译与部署

c 复制代码
# 应用补丁
$ 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监控自身关键指标:

监控项配置示例:

c 复制代码
-- 创建监控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
);

触发器配置:

c 复制代码
触发器名称: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)审查自定义脚本和用户参数的内存使用

配置优化建议:

c 复制代码
# /etc/zabbix/zabbix_server.conf 优化配置
### 内存相关优化 ###
# 根据物理内存大小调整缓存
HistoryCacheSize=256M    # 历史数据缓存,建议为可用内存的5-10%
TrendCacheSize=64M      # 趋势数据缓存
ValueCacheSize=512M     # 值缓存,对性能影响较大
### 并发处理优化 ###
# 根据CPU核心数调整
StartPollers=50         # 建议为CPU核心数的2-3倍
StartPreprocessors=10   # 预处理进程数
StartHistoryPollers=8   # 历史数据同步进程
### 数据库连接优化 ###
DBHost=localhost
DBPort=3306
DBName=zabbix
DBUser=zabbix
# 连接池配置
StartDBSyncers=4        # 数据库同步进程
HouseskeepingFrequency=1 # 小时,清理旧数据频率

五、效果验证与监控

5.1 修复效果验证

修复后持续监控内存使用情况:

c 复制代码
# 监控内存使用趋势
$ 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)应急响应机制

建立标准化的故障排查流程

制定不同严重级别问题的响应策略

保持故障处理的知识库更新

附录:常用诊断命令参考

c 复制代码
# 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. 数据库分析
# 查看历史数据表大小
SELECT 
    table_name,
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb
FROM information_schema.tables
WHERE table_schema = 'zabbix'
ORDER BY size_mb DESC;
相关推荐
lvbinemail12 小时前
添加zabbix-agentd.service
linux·运维·服务器·zabbix·监控
2301_8000509914 小时前
Zabbix和ELK
笔记·elk·zabbix
小波小波轩然大波14 小时前
ELK 与 Zabbix
elk·zabbix
2301_7679026418 小时前
Zabbix
运维·zabbix
神秘面具男031 天前
Zabbix 部署与监控
zabbix
一心0923 天前
zabbix proxy 参数优化-配置缓存使用率(%)> 85%
缓存·zabbix·zabbix proxy
FIT2CLOUD飞致云6 天前
操作教程丨通过1Panel快速安装Zabbix,搭建企业级监控系统
运维·服务器·开源·zabbix·监控·1panel
小白跃升坊7 天前
操作教程丨通过1Panel快速安装Zabbix,搭建企业级监控系统
zabbix·安装教程·1panel·分布式监控
lvbinemail8 天前
Grafana模板自动复制图表
数据库·mysql·zabbix·grafana·监控