资讯详情

Zabbix 7.0 LTS 数据库分区实战:从部署到优化的完整指南

📅 2026/10/11 19:28:55 | 华诺云谱 👁 阅读
Zabbix 7.0 LTS 数据库分区实战:从部署到优化的完整指南
简介本资源为Zabbix 7.0 LTS部署及数据库分区优化的操作记录文档面向运维工程师、监控系统管理员及需要处理Zabbix数据库性能瓶颈的技术人员。内容聚焦MySQL/MariaDB环境下历史记录与趋势表的分区方案针对housekeeper进程繁忙、旧数据删除效率低等常见问题给出可落地的解决思路。资源包为1个PDF文件大小约835KB便于在数据库服务器或本地环境中随时查阅与对照操作。文档围绕分区脚本的获取与执行、分区过程的自动调度、前端保留天数配置以及分区参数调整等环节展开并提示备份数据库、大型库执行耗时等注意事项适用于Zabbix 3.0以后各版本。已有354人学习适合希望降低维护成本、提升监控系统长期稳定性的读者参考。1. Zabbix 7.0 LTS 落地为什么数据库分区是绕不开的第一道坎很多团队装完 Zabbix 7.0 LTS把主机一加、模板一挂看着绿油油的监控面板觉得万事大吉。结果跑上两三个月history、trends 这几张表膨胀到几千万行前端翻个最新数据要转圈十几秒MySQL 磁盘 IO 直接打满告警延迟从秒级掉到分钟级。这不是 Zabbix 本身慢是底层数据库没做分区所有历史数据堆在一张无界大表里查询和清理全靠全表扫描硬扛。Zabbix 7.0 LTS 是官方长期支持版本默认用 MySQL 或 MariaDB 存历史数据核心的 history、history_uint、trends、trends_uint 四张表会随监控项数量线性增长。分区优化的本质是按时间维度把大表切成若干小表让查询只扫对应分区、过期数据直接 drop 分区而不是 delete 行。这套操作适合自建 Zabbix 的运维和 SRE尤其是监控主机超过 200 台、或者采集间隔压到 30 秒以内的场景。下面从选型、部署、分区到排错把我实际跑过一遍的路径讲清楚。2. 部署前的选型与系统准备MySQL 还是 MariaDB装在哪2.1 数据库选型MySQL 8.0 与 MariaDB 10.11 的取舍Zabbix 7.0 LTS 官方同时支持 MySQL 8.0 和 MariaDB 10.5 以上版本。两者在分区语法上几乎一致差异主要在细节MySQL 8.0 的information_schema查询性能更好窗口函数和 CTE 支持完整适合后续做报表分析MariaDB 10.11 在中小规模下内存占用略低mysql命令行工具对老运维更顺手。我一般这样选新机器、监控规模 500 台以内用 MariaDB 10.11装完即用配置简单如果后续要接 Grafana 做复杂查询或者团队已有 MySQL 8.0 运维经验直接上 MySQL 8.0。两者都别用 5.7Zabbix 7.0 对 5.7 的支持已经不在推荐列表里字符集和分区行为都有坑。操作系统层面CentOS 7.9 和 Ubuntu 22.04 是最常见的两个选择。CentOS 7.9 自带 MariaDB 5.5版本太老必须换源装新版Ubuntu 22.04 默认仓库的 MySQL 8.0 版本够用省一步。下面以 Ubuntu 22.04 MySQL 8.0 为主线CentOS 7.9 的差异我会单独标注。2.2 系统参数与依赖安装装数据库之前先把系统层面的限制调开否则后面 Zabbix Server 连上来会报连接数或文件句柄错误。# 调整内核参数Zabbix 和 MySQL 都需要较多文件句柄和连接 sudo tee -a /etc/sysctl.conf EOF fs.file-max 2097152 net.ipv4.ip_local_port_range 1024 65000 net.core.somaxconn 65535 vm.swappiness 10 EOF sudo sysctl -p # 调整用户进程限制 sudo tee -a /etc/security/limits.conf EOF zabbix soft nofile 65535 zabbix hard nofile 65535 mysql soft nofile 65535 mysql hard nofile 65535 EOFfs.file-max控制系统级文件句柄上限Zabbix Server 每个采集进程都会占句柄200 台主机起步就要几万。vm.swappiness10让系统尽量少用 swap数据库场景下 swap 会拖慢查询。limits.conf里的配置需要重新登录或重启对应服务才生效别改完就急着装。依赖包方面Ubuntu 22.04 执行sudo apt update sudo apt install -y wget gnupg2 software-properties-common \ mysql-server mysql-client libmysqlclient-dev \ snmp snmpd fping curlCentOS 7.9 则先换 MySQL 官方源再装mysql-community-server同时把fping从 EPEL 装因为 Zabbix 的 ICMP 采集依赖它。snmp和snmpd是监控网络设备时用的不监控交换机可以先不装。提示CentOS 7.9 的默认防火墙是 firewalld装完 MySQL 后要放行 3306Zabbix Server 本机连接可以只监听 127.0.0.1减少暴露面。3. Zabbix 7.0 LTS 服务端与数据库的安装配置3.1 MySQL 8.0 初始化与 Zabbix 专用库MySQL 装好后先做安全初始化设置 root 密码、移除匿名用户和测试库。sudo mysql_secure_installation # 按提示设置 root 密码其余选项一路 Y接着创建 Zabbix 专用数据库和用户。字符集必须用utf8mb4排序规则用utf8mb4_bin这是 Zabbix 官方要求用错会导致中文主机名乱码或索引失效。CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; CREATE USER zabbixlocalhost IDENTIFIED BY Zbx_Str0ng_Pass; GRANT ALL PRIVILEGES ON zabbix.* TO zabbixlocalhost; -- 如果 Zabbix Server 和数据库不在同一台机器把 localhost 换成 Server 的 IP FLUSH PRIVILEGES;utf8mb4_bin是二进制排序区分大小写Zabbix 的键值匹配依赖这个行为。密码别用纯数字或常见词Zabbix 前端登录和数据库是两套凭据数据库这层被爆破一样会丢数据。然后导入 Zabbix 7.0 的初始表结构。从官方仓库下载对应版本的server.sql.gz解压导入wget https://cdn.zabbix.com/zabbix/sources/stable/7.0/zabbix-7.0.0.tar.gz tar -zxvf zabbix-7.0.0.tar.gz cd zabbix-7.0.0/database/mysql zcat schema.sql.gz | mysql -uzabbix -p zabbix zcat images.sql.gz | mysql -uzabbix -p zabbix zcat data.sql.gz | mysql -uzabbix -p zabbix导入顺序不能乱schema 建表images 存前端图标data 插初始配置。三个文件都导入完用mysql -uzabbix -p zabbix -e show tables;确认表数量在 170 张左右。3.2 Zabbix Server 编译安装与关键配置Zabbix 7.0 可以用包管理装也可以源码编译。包管理省事但版本受仓库限制源码编译能精确控制编译选项。我一般用源码编译因为要开 MySQL 和 SNMP 支持。sudo apt install -y build-essential libpcre3-dev libevent-dev \ libmysqlclient-dev libsnmp-dev libssh2-1-dev libopenipmi-dev ./configure --prefix/usr/local/zabbix \ --enable-server --enable-agent \ --with-mysql --with-net-snmp \ --with-libcurl --with-ssh2 \ --with-openipmi make -j$(nproc) sudo make install--with-mysql是必须的不指定数据库后端编译出来的 Server 起不来。--with-net-snmp决定能不能监控交换机。-j$(nproc)用满 CPU 核数加速编译内存小于 2G 的机器改成-j2否则容易 OOM。编译完配置/usr/local/zabbix/etc/zabbix_server.conf核心几项DBHostlocalhost DBNamezabbix DBUserzabbix DBPasswordZbx_Str0ng_Pass DBPort3306 StartPollers20 StartPollersUnreachable5 StartTrappers10 StartPingers5 CacheSize64M HistoryCacheSize64M TrendCacheSize32M ValueCacheSize128MStartPollers是采集进程数200 台主机建议 20 起步每增加 100 台加 5。CacheSize和HistoryCacheSize根据内存调16G 内存的机器可以给到 128M。ValueCacheSize影响前端取最新值的速度给太小前端会卡。启动前先建 zabbix 系统用户再写 systemd 服务文件sudo useradd -r -s /sbin/nologin zabbix sudo tee /etc/systemd/system/zabbix-server.service EOF [Unit] DescriptionZabbix Server Afternetwork.target mysql.service [Service] Typesimple Userzabbix ExecStart/usr/local/zabbix/sbin/zabbix_server -c /usr/local/zabbix/etc/zabbix_server.conf Restarton-failure [Install] WantedBymulti-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now zabbix-serverAftermysql.service保证数据库先起否则 Zabbix Server 启动时连不上库会反复重启。Restarton-failure让进程异常退出后自动拉起生产环境必加。3.3 前端与 Agent 的快速验证前端用 Nginx PHP-FPM 部署把 Zabbix 源码里的ui目录拷到 web 根目录改conf/zabbix.conf.php里的数据库连接信息。PHP 版本要求 8.0 以上扩展要开bcmath、mbstring、gd、mysqli、xml。Agent 装在被监控机上配置Server指向 Zabbix Server 的 IP启动后到前端「数据采集 → 主机」里添加主机关联Linux by Zabbix agent模板。等一两分钟最新数据里出现 CPU、内存、磁盘曲线说明整条链路通了。注意如果前端显示「Zabbix server is not running」先看/var/log/zabbix/zabbix_server.log八成是数据库密码错或zabbix库权限没给全。4. 数据库分区优化把 history 和 trends 按时间切开4.1 为什么必须分区以及分区键怎么选Zabbix 默认把每一条采集数据写进history、history_uint、history_str、history_text、history_log以及对应的trends、trends_uint。一台主机 50 个监控项、60 秒采集一次一天就是 7 万多行一年 2500 万行。不分区的话delete from history where clock xxx这种清理语句会锁表几十分钟期间采集数据全堵在队列里。分区的核心是按clock字段做 RANGE 分区每个分区放一天或一周的数据。查询时 MySQL 只扫对应分区清理时直接ALTER TABLE ... DROP PARTITION秒级完成不产生大事务。分区键必须选clock因为 Zabbix 所有历史查询都带时间范围条件。分区粒度我一般用「一天一分区」保留 30 到 90 天具体看磁盘和合规要求。趋势数据trends保留时间长可以按「一月一分区」保留 12 到 24 个月。4.2 分区存储过程与定时任务Zabbix 官方提供了一套分区脚本核心是几个存储过程partition_create、partition_drop、partition_maintenance。我把它精简成适合自己环境的版本先建过程DELIMITER // CREATE PROCEDURE partition_create( IN p_schema VARCHAR(64), IN p_table VARCHAR(64), IN p_partition VARCHAR(64), IN p_start BIGINT, IN p_end BIGINT ) BEGIN SET sql CONCAT( ALTER TABLE , p_schema, ., p_table, ADD PARTITION (PARTITION , p_partition, VALUES LESS THAN (, p_end, )) ); PREPARE stmt FROM sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END // DELIMITER ;这个过程的逻辑是拼一条ALTER TABLE ... ADD PARTITION动态 SQL 并执行。p_start和p_end是 Unix 时间戳p_end决定分区上界。注意分区名不能重复重复执行会报错所以调用前要先查information_schema.partitions确认不存在。再建删除过程DELIMITER // CREATE PROCEDURE partition_drop( IN p_schema VARCHAR(64), IN p_table VARCHAR(64), IN p_retention INT ) BEGIN DECLARE done INT DEFAULT 0; DECLARE part_name VARCHAR(64); DECLARE cur CURSOR FOR SELECT PARTITION_NAME FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA p_schema AND TABLE_NAME p_table AND PARTITION_NAME IS NOT NULL AND PARTITION_NAME ! p_first AND PARTITION_DESCRIPTION UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL p_retention DAY)); DECLARE CONTINUE HANDLER FOR NOT FOUND SET done 1; OPEN cur; read_loop: LOOP FETCH cur INTO part_name; IF done THEN LEAVE read_loop; END IF; SET sql CONCAT(ALTER TABLE , p_schema, ., p_table, DROP PARTITION , part_name); PREPARE stmt FROM sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END LOOP; CLOSE cur; END // DELIMITER ;p_retention是保留天数游标遍历所有分区描述小于「当前时间减保留天数」的分区逐个 drop。PARTITION_NAME ! p_first是保护第一个兜底分区防止误删导致数据无处可放。最后是维护主过程把创建和删除串起来DELIMITER // CREATE PROCEDURE partition_maintenance( IN p_schema VARCHAR(64), IN p_table VARCHAR(64), IN p_retention INT, IN p_interval INT ) BEGIN DECLARE p_name VARCHAR(64); DECLARE p_start BIGINT; DECLARE p_end BIGINT; SET p_start UNIX_TIMESTAMP(DATE(NOW())); SET p_end p_start p_interval; SET p_name CONCAT(p, DATE_FORMAT(NOW(), %Y%m%d)); IF NOT EXISTS ( SELECT 1 FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA p_schema AND TABLE_NAME p_table AND PARTITION_NAME p_name ) THEN CALL partition_create(p_schema, p_table, p_name, p_start, p_end); END IF; CALL partition_drop(p_schema, p_table, p_retention); END // DELIMITER ;p_interval是分区跨度按天分区就传 86400。过程先算今天零点的时间戳拼出分区名如p20250101不存在就创建然后调删除过程清理过期分区。4.3 对现有大表做分区改造如果 Zabbix 已经跑了一段时间history 表里已有大量数据不能直接ALTER TABLE ... PARTITION BY RANGE因为 MySQL 要求分区表的主键必须包含分区键。Zabbix 的 history 表主键是(itemid, clock)clock 已经在主键里可以直接改。但trends表主键是(itemid, clock)同样满足。真正麻烦的是history_uint这类表主键也是(itemid, clock)没问题。改造语句ALTER TABLE history PARTITION BY RANGE (clock) ( PARTITION p_first VALUES LESS THAN (UNIX_TIMESTAMP(2025-01-01 00:00:00)) );先建一个兜底分区把所有历史数据装进去。然后调partition_maintenance逐天补建新分区。注意这个 ALTER 在大表上执行会锁表几千万行的表可能要跑十几分钟建议在业务低峰期做或者用pt-online-schema-change工具在线改。改造完成后用这条 SQL 验证分区是否生效SELECT PARTITION_NAME, TABLE_ROWS, PARTITION_DESCRIPTION FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA zabbix AND TABLE_NAME history ORDER BY PARTITION_ORDINAL_POSITION;TABLE_ROWS是估算值不精确但能看出数据分布。PARTITION_DESCRIPTION是分区上界时间戳确认每个分区对应一天。4.4 定时任务与参数调优分区维护要挂到 cron 或 MySQL 事件调度器。我一般用系统 cron每天凌晨 2 点跑一次0 2 * * * mysql -uzabbix -pZbx_Str0ng_Pass zabbix -e CALL partition_maintenance(zabbix,history,30,86400); CALL partition_maintenance(zabbix,history_uint,30,86400); CALL partition_maintenance(zabbix,trends,365,86400); CALL partition_maintenance(zabbix,trends_uint,365,86400);history 保留 30 天trends 保留 365 天这是常见组合。如果磁盘紧张history 可以压到 7 天trends 压到 180 天。注意 cron 里的密码明文有安全风险可以用~/.my.cnf存凭据权限设 600。MySQL 侧还要调几个参数配合分区innodb_file_per_table ON innodb_buffer_pool_size 4G innodb_flush_log_at_trx_commit 2innodb_file_per_table让每个分区独立表空间drop 分区时直接删文件回收磁盘快。innodb_buffer_pool_size给物理内存的 50% 到 70%16G 内存给 8G。innodb_flush_log_at_trx_commit2牺牲一点持久性换写入性能监控数据丢几秒可接受。5. 避坑与排查分区改造中最容易翻车的五个点5.1 分区键不在主键里ALTER 直接报错现象执行ALTER TABLE history PARTITION BY RANGE (clock)时报A PRIMARY KEY must include all columns in the tables partitioning function。原因MySQL 要求分区键必须是主键或唯一索引的一部分。Zabbix 的 history 表主键是(itemid, clock)clock 在里面所以能改。但如果之前有人手动改过表结构把主键改成只有itemid就会报这个错。解决先SHOW CREATE TABLE history确认主键定义如果 clock 不在主键里需要先加回主键或建包含 clock 的唯一索引。改主键在大表上同样锁表务必低峰操作。5.2 分区名重复导致定时任务报错现象cron 每天跑某天开始报Duplicate partition name p20250101。原因partition_maintenance里虽然查了information_schema判断存在性但如果同一天手动执行过一次或者 cron 跑了两次第二次就会撞名。解决过程里已经加了IF NOT EXISTS判断正常不会重复。如果还是报检查是不是有多个 cron 任务同时跑或者 MySQL 事件调度器和系统 cron 都在调。保留一个即可。5.3 drop 分区后磁盘空间没释放现象ALTER TABLE ... DROP PARTITION执行成功但df -h看磁盘占用没降。原因如果innodb_file_per_table是 OFF所有分区共享 ibdata1drop 分区不会释放文件。另外 MySQL 8.0 的innodb_undo_tablespaces和临时表空间也可能占着空间。解决确认innodb_file_per_tableONdrop 分区后等几分钟让 InnoDB 后台线程回收。如果还是没降检查是不是有长事务或未提交的查询持有旧分区文件的句柄SHOW PROCESSLIST看有没有卡住的会话。5.4 分区后查询反而变慢现象分区建好了但前端查最新数据比以前还慢。原因分区裁剪没生效。如果查询条件里clock用了函数比如WHERE FROM_UNIXTIME(clock) ...MySQL 无法裁剪分区会扫全部分区。解决Zabbix 内部查询都是直接比较 clock 时间戳不会用函数包。如果自己写报表 SQL确保clock是裸字段比较。另外分区数量别太多一天一分区、保留 90 天就是 90 个分区超过 200 个分区元数据管理开销会上升可以改成一周一分区。5.5 Zabbix Server 的 housekeeper 和分区冲突现象开了分区后Zabbix 自带的 housekeeper 还在跑两边同时删数据数据库负载高。原因Zabbix 的 housekeeper 是按行 delete 清理历史数据和分区 drop 功能重叠。分区生效后应该关掉 housekeeper 对 history 和 trends 的清理。解决在前端「管理 → 常规 → 管家」里把History和Trends的保留天数设为 0表示不通过 housekeeper 清理。或者直接在zabbix_server.conf里设HousekeepingFrequency0完全关掉。清理工作全部交给分区过程。6. 分区效果验证与长期维护的一个关键习惯分区做完不是终点得有一套验证方法确认它真的在干活。我一般用三个指标交叉看分区数量、单分区行数、查询扫描行数。先看分区分布SELECT TABLE_NAME, COUNT(*) AS part_count, SUM(TABLE_ROWS) AS total_rows FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA zabbix AND TABLE_NAME IN (history,history_uint,trends,trends_uint) GROUP BY TABLE_NAME;正常情况下 history 的分区数应该等于保留天数加一两个兜底分区trends 同理。如果分区数远小于保留天数说明维护过程没跑成功去查 cron 日志。再看单分区行数是否均匀SELECT PARTITION_NAME, TABLE_ROWS FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA zabbix AND TABLE_NAME history ORDER BY PARTITION_ORDINAL_POSITION DESC LIMIT 10;最近几个分区的行数应该在同一量级如果某一天突然翻倍可能是那天加了大量监控项或改了采集间隔属于正常波动。但如果某个分区行数为 0说明那天没有数据写入要查 Zabbix Server 是否宕过。最后用EXPLAIN验证分区裁剪EXPLAIN SELECT * FROM history WHERE itemid 12345 AND clock UNIX_TIMESTAMP(NOW()) - 3600;看partitions列应该只列出最近一两个分区名而不是全部。如果列出了所有分区说明裁剪没生效回头检查 clock 字段有没有被函数包裹。长期维护上我养成了一个习惯每周一早上花五分钟看一眼分区数量和磁盘趋势。分区数量对不上保留天数立刻查 cron磁盘增长曲线突然变陡提前扩盘或缩短保留期。这套动作比等数据库报警了再救火省心得多。Zabbix 7.0 LTS 本身很稳真正让它长期稳定的是底下这套按时间切分、自动清理的分区机制。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑