news 2026/10/21 7:46:48

Zabbix数据库从MySQL迁移到TiDB的实战与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Zabbix数据库从MySQL迁移到TiDB的实战与避坑指南

如果把一套线上规模不小的 Zabbix 数据库从 MySQL 迁到 TiDB,听起来像是个挺折腾的事。但做下来你会发现,因为 TiDB 在协议层面兼容 MySQL,整个迁移并没有想象中那么重的改造量。这次项目就是冲着解决监控数据库的扩容和清理痛点去的:用 TiDB 替换 MySQL 作为 Zabbix 的存储层,前端和后端几乎没动,数据先全量导入,再验证性能与稳定性。整条链路跑通后,Zabbix 的写入压力、历史数据堆积、清理慢的问题都有了明显改善。

这个项目比较适合两类人看:一类是正在被 Zabbix 历史数据膨胀、MySQL 单机写入瓶颈折磨的运维,另一类是刚接触 TiDB、想了解分布式数据库怎么和现有 MySQL 生态对接的 DBA。我会把迁移过程中踩过的坑、试过的方案选择、以及最后的配置调整都写出来,尽量让你照着做也能复现。

1. 项目背景:为什么监控库要先“扛不住”

1.1 Zabbix 的数据模型与存储压力

Zabbix 绝大部分数据都集中在几张表里:history、history_uint、history_str、trends、trends_uint。这些表的特征是高频写入、短时间累积巨大、按时间过期。监控项一多,比如几千台设备、每台设备几十个监控项、采集间隔 30 秒,一晚上就能写出几千万行。再叠加长周期保留(90 天甚至更长),MySQL 单机的磁盘、IO、事务并发很快就到瓶颈。

更关键的一点是 Zabbix 默认的 housekeeper 清理逻辑。它会按频率执行DELETE FROM history WHERE clock < xxx。数据量一大,这种删除就会拖慢整个实例,甚至产生大量 binlog,让从库同步也跟不上。很多团队最后不得不用脚本按天删分区表,但 MySQL 单机下重建分区的时候锁表、IO 抖动都是绕不开的。

1.2 为什么选 TiDB 而不是分库分表

再看数据库选型。如果继续待在 MySQL 生态里,可以走分库分表,但 Zabbix 内部 SQL 对跨库关联、聚合统计用得非常频繁,改造 SQL 的工作量很大,而且后续升级 Zabbix 还得同步维护分片逻辑。TiDB 对整个应用层依然表现为一个完整的 MySQL 数据库,连接串、SQL 语法、事务行为都是 MySQL 兼容的,应用不需要感知背后有几个 TiKV 节点。

TiDB 的分布式存储把多节点的 CPU、内存、磁盘集合成一个逻辑库,单点扩容难、写入并发受限这些问题被拆散到多节点上。同时它的分区表管理也完整支持,可以把 Zabbix 最头疼的批量老数据清理,从DELETE改成 DDL 式的分区删除,效果立竿见影。

1.3 兼容层能省多少事

TiDB 的通信协议、客户端认证都基于 MySQL,Zabbix server 本身是 C 写的,通过 MySQL 客户端库连库,PHP 前端也一样。只要切换连接地址和端口,Zabbix 不知道背后换了数据库。前提是把模式和数据正确导入,避免个别不兼容的 DDL 和排序规则问题。这个兼容层是整条迁移路径里最值钱的部分,也是我最终坚持采用“直接换库、不换应用”方案的原因。

2. 迁移方案选型与前置准备

2.1 TiDB 部署方式对比

如果是测试环境,最快的办法是用单机方式启动一个 TiDB 实例,组件包括 TiDB Server、PD、TiKV,也可以加入 TiFlash,但 Zabbix 用不到列存索引,先不启用。单机模式适合验证功能连通性和数据完整性,但不足以证明生产性能。

生产环境建议用集群方式部署,至少 3 个 PD、3 个 TiKV,TiDB Server 无状态可以多放几个。不同部署方式对最终迁移验证结果影响很大,我最终验证的结论来自一套 3 节点 TiKV 的集群,每个节点 SSD,网络万兆。整体部署使用 TiUP 就能完成,如果不想深入 TiDB 的内部原理,按官方推荐的拓扑来即可。

实践中我的体会是:TiDB 扩容友好,但初始拓扑还是别太省。尤其是 TiKV 节点内存和磁盘的分配要留足,监控数据的压缩比和热数据分布很依赖机器配置。配置太低容易把性能问题误判成产品问题。

2.2 迁移工具怎么选:直接 dump 还是专用导入

Zabbix 的库最重要的问题是要搬运大量历史数据。数据量在几十 GB 以内、或者本来就是做概念验证,可以直接用mysqldump导出 SQL,再用 MySQL 客户端导入 TiDB,简单直观。但数据量上百 GB 后,mysqldump 的导出和导入都是单线程逻辑,效率上不划算,更推荐用dumpling导出加tidb-lightning物理导入的组合。

因为这个项目要同时兼顾迁移效率和数据完整性,我实际采用了两套方案:先用 mysqldump 做小批量联调验证,确认库表结构能兼容,再在正式切割时用 dumpling 导出、lightning 导入,整体花费的时间能少一个数量级。工具的选择不是越高级越好,而是和迁移窗口、数据量、可回滚性挂钩。

2.3 账号库表初始化与连接准备

在 TiDB 集群部署完成后,先创建 Zabbix 使用的数据库和账号:

CREATE DATABASE zabbix DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; CREATE USER 'zabbix'@'%' IDENTIFIED BY 'your_password_here'; GRANT ALL PRIVILEGES ON zabbix.* TO 'zabbix'@'%'; FLUSH PRIVILEGES;

这里账号的权限给得比较宽,是为了迁移期间方便调试。上线后可以按最小权限收窄,但 Zabbix 运行中会做临时表、分区变更,至少得保留 DDL 权限。

连接端口要注意,TiDB 默认的 SQL 监听端口是 4000,不是 3306。第一次用 MySQL 客户端连上去时,很多人会下意识写-P3306,然后报连接失败。我在这一步就被绕了一下。检查无误后可以用mysql -h <tidb_ip> -P 4000 -u root -p测试连通性。

3. 迁移实操:从 MySQL 到 TiDB 的完整流程

3.1 源库导出:结构与数据分开走

先把 Zabbix 库表结构导出。导出时建议加上--single-transaction保证快照一致,如果源 MySQL 开启了 GTID,还要加--set-gtid-purged=OFF,否则导入 TiDB 时会因为 GTID 语句不识别而报错。

mysqldump -h 192.168.1.10 -u root -p \ --default-character-set=utf8mb4 \ --single-transaction \ --routines \ --no-data \ --set-gtid-purged=OFF \ --databases zabbix > zabbix_schema.sql

导出数据时,不建议再带建表语句,这是为了后续可以只专注于大数据表的导入。Zabbix 表之间的外键约束本来就不多,跳过约束能让导入速度和安全系数都有提升:

mysqldump -h 192.168.1.10 -u root -p \ --default-character-set=utf8mb4 \ --single-transaction \ --skip-triggers \ --skip-routines \ --no-create-info \ --set-gtid-purged=OFF \ --databases zabbix > zabbix_data.sql

拆分导出还有一个额外好处:结构文件可以人工检查,尤其可以提前处理 TiDB 不支持的排序规则。数据文件再怎么大也不用逐个看。

3.2 导入到 TiDB:先建库、再导结构、最后灌数据

按照上面拆分好的文件,依次执行:

mysql -h 127.0.0.1 -P 4000 -u root -p \ -e "CREATE DATABASE IF NOT EXISTS zabbix DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;" mysql -h 127.0.0.1 -P 4000 -u root -p \ --default-character-set=utf8mb4 \ zabbix < zabbix_schema.sql mysql -h 127.0.0.1 -P 4000 -u root -p \ --default-character-set=utf8mb4 \ zabbix < zabbix_data.sql

如果数据量小,这些命令一条条跑完就行。数据量大时,用 MySQL 客户端导入最大的history相关表会非常慢,因为客户端是单连接顺序执行,而且每条 INSERT 的提交开销都在。此时可以用 dumpling 和 lightning 替换。

dumpling 导出的默认文件格式就是 TiDB 生态最熟悉的 SQL/CSV 格式:

dumpling -h 192.168.1.10 -u root -p \ -P 3306 \ --threads 8 \ --filetype sql \ --output /data/zabbix_dump \ --database zabbix \ --where "clock > '2024-01-01 00:00:00'"

后面这个--where条件是我做分批迁移时加的,如果做全量一次性迁移不需要加。tidb-lightning 的配置则相对简单,核心是告诉它源目录和 TiDB 连接信息:

[lightning] level = "info" checkpoint = true [mydumper]>ALTER TABLE history_uint PARTITION BY RANGE (TO_DAYS(clock)) ( PARTITION p20240101 VALUES LESS THAN (TO_DAYS('2024-01-01')), PARTITION p20240102 VALUES LESS THAN (TO_DAYS('2024-01-02')), PARTITION p20240103 VALUES LESS THAN (TO_DAYS('2024-01-03')) );

这一步有两个细节要注意。第一,在导入前完成分区能避免导入后重写整表;第二,TiDB 对分区数量的上限有约定,不能无限增加,所以按天建分区时,批量加一个月或一个季度的分区更稳妥。

清理数据时,直接删除旧分区比 DELETE 快得多,而且不会产生大量长事务:

ALTER TABLE history_uint DROP PARTITION p20240101;

这套逻辑和 Zabbix 自己的 housekeeper 并不冲突。housekeeper 只负责删未分区的过期行,而分区表清理可以在凌晨低峰执行一次 DDL 脚本。实测下来,DDL 方式对集群整体 IO 的冲击几乎可以忽略。

3.4 引入增量同步方案作为切割策略

业务量大的系统不建议直接停库导数据。先全量导入 TiDB,再用 DM 工具把 MySQL 新增的 binlog 增量同步到 TiDB,等到切换窗口时应用停写、手动追平增量、再改 Zabbix 连接串,这样能保证数据基本不丢。

DM 配置里需要定义源 MySQL 和同步任务,核心思路和主从同步很像。注意源端需要开启 binlog 且使用 row 格式,Zabbix 表最好带主键,否则 DM 同步过程中无法有效定位变更行。这个配置要点,在写 DM 任务时一定要回头确认源 MySQL 的参数。

4. Zabbix 配置改造与启动验证

4.1 zabbix_server.conf 连接参数

Zabbix server 的数据库连接集中在/etc/zabbix/zabbix_server.conf里,迁移后改动如下:

DBHost=tidb01 DBPort=4000 DBName=zabbix DBUser=zabbix DBPassword=your_password_here

如果原本配置里有DBSocket或者DBHost=localhost,一定要去掉或改成远端地址,否则 Zabbix 会尝试走本地 socket,连接不到 TiDB。

我当时测试时还犯过一个低级错误:端口改成 4000 后,密码里带有特殊字符,忘记转义,导致连接被拒后花了不少时间排查。先确认连接串再动服务,能省很多事。

4.2 PHP 前端配置切换

Zabbix Web 前端在/etc/zabbix/web/zabbix.conf.php,数据库类型保持 MYSQL,因为 TiDB 走的就是 MySQL 协议。只改服务端地址和端口:

<?php $DB['TYPE'] = 'MYSQL'; $DB['SERVER'] = 'tidb01'; $DB['PORT'] = '4000'; $DB['DATABASE'] = 'zabbix'; $DB['USER'] = 'zabbix'; $DB['PASSWORD'] = 'your_password_here'; $DB['SCHEMA'] = '';

前端 PHP 所在的机器要能访问 TiDB 的 4000 端口,有些环境里前端服务器和后端服务有防火墙隔离,记得加白名单。改完后台页面上如果有报错,往往是网络通不通的问题,而不是数据库连接类型的问题。

4.3 启动与健康检查

配置改完,先不要直接启动生产服务,建议做两步验证。

第一步是连接性测试,直接用 PHP 的 mysql 扩展或命令行客户端去连:

mysql -h tidb01 -P 4000 -u zabbix -p -e "SELECT 1;"

第二步是前端页面登录,确认配置、用户、监控项都能正常读取。Zabbix 前端加载时会执行一批元数据查询,如果排序规则不对,有些中文或特殊字符页面会直接显示乱码或报错。把前端跑通了,整个底层的连通性才算闭环。

如果 Zabbix server 启动后日志里持续报PostgreSQL connection之类的错误,先检查是不是改错了配置文件,或者旧的数据库进程占用着连接端口。这类排查大部分和 TiDB 无关,属于常规的换库后遗症。

5. 迁移后的避坑清单与实测体会

5.1 排序规则不匹配是最常见的坑

Zabbix 源库常见字符集是utf8mb4,排序规则可能是utf8mb4_general_ci或utf8mb4_bin。而 MySQL 8.0 默认的utf8mb4_0900_ai_ci在部分 TiDB 版本上不支持,导入建表语句时直接报:Unknown collation: 'utf8mb4_0900_ai_ci'。

解决办法是导入前统一替换 schema 文件里的排序规则,建议统一为utf8mb4_bin,对 Zabbix 这种监控数据来说完全够用。替换命令一行搞定:

sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_bin/g' zabbix_schema.sql

遇到其他不支持的排序规则,也可以先查目标 TiDB 版本支持列表再替换。这种问题早早在联调阶段发现,比正式割接后报错要好处理得多。

5.2 ZERO 日期和 SQL_MODE 差异

Zabbix 部分历史数据里可能写入0000-00-00 00:00:00这种零值日期。MySQL 8 默认在会话里允许,但 TiDB 的 SQL 模式如果偏严格,会在导入或查询时拒绝。导入前调整会话或者全局 SQL 模式:

SET GLOBAL sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

注意:一旦动了 SQL_MODE,要对 Zabbix 的业务 SQL 做一轮回归测试,防止某些聚合查询受ONLY_FULL_GROUP_BY影响。实际生产里我见过一个报表因为时间分组查询不满足严格模式而报错,最终还是把ONLY_FULL_GROUP_BY去掉了才通过。

好在 TiDB 对 SQL 模式的兼容性已经做得比较成熟,Zabbix 的增删改查没有碰到更复杂的问题。如果遇到函数不支持,优先看函数名是否大小写敏感,TiDB 的兼容函数清单在对应版本文档里都有,一个个对照排查即可。

5.3 分区维护别让 housekeeper 双份干活

Zabbix 如果开启了原生分区,housekeeper 还是会尝试清理过期数据。分区表的手动 DROP PARTITION 能很快删除旧数据,但 housekeeper 进程对同一张表的 DELETE 操作依然可能产生锁竞争。最稳妥的做法是调整 Zabbix 的自动清理周期,或者直接关闭对应历史表的 housekeeper 清理,完全依赖分区脚本。

实际维护中,我会在每周日凌晨统一删除 14 天前的历史分区。脚本思路很简单:循环生成需要添加的日期分区,然后对history_uint、history、trends_uint、trends依次执行 DDL。

#!/bin/bash DB="zabbix" TIDB_HOST="tidb01" TIDB_PORT="4000" for i in $(seq 1 14); do D=$(date -d "+${i} days" +%F) PN="partition_name_$(date -d "+${i} days" +%Y%m%d)" mysql -h "$TIDB_HOST" -P "$TIDB_PORT" -u zabbix -pYourPass \ -e "ALTER TABLE history_uint ADD PARTITION (PARTITION $PN VALUES LESS THAN (TO_DAYS('$D')));" done

分区名不能用数字开头,所以我在前面拼了字符串前缀。这种细节在写脚本时特别容易忽略,报错一次就能记住。

5.4 性能观测:写入和查询都变稳了

迁移完成后,我关注的核心指标有三个:历史写入延迟、housekeeper 清理耗时、前端图表加载速度。

先说写入。TiDB 集群在夜间批量写监控数据时,整体的写入延迟曲线比原来 MySQL 单机平稳,高峰期的排队延迟明显降低。原因是 TiKV 的多节点天然分担了热点写入,不会像单机 InnoDB 那样在大量 INSERT 时互相阻塞。

再说清理。原来 MySQL 上清理几千万行老数据可能要跑几十分钟,而且期间 CPU 飙升、IO 打满。切换到 TiDB 后,通过 DROP PARTITION 清理一个月前的数据几乎是分钟级完成,对业务的影响大幅度降低。对我来说,仅仅这一个改善就值回迁移成本。

前端图表的查询速度,在历史时间范围较大的聚合查询里也表现不错。小范围短暂查询和 MySQL 差异不大,但长时间跨度、跨多节点聚合统计时,TiDB 的分布式优势能发挥出来。

5.5 回滚预案要提前写好

迁移顺利时大家都很开心,但 DBA 的习惯是先想退路。我的回滚方案是保留 MySQL 原库不删,切换 TiDB 后只做只读验证,等到前端、报表、告警都跑了一周,确认没有异常,再做原库归档。千万别在迁移当天把 MySQL 直接删掉,万一 TiDB 侧碰到隐藏兼容问题,想快速回滚都没机会。

前后端配置改回原来的 MySQL 地址,理论上几分钟就能恢复。真正花时间的反而是确认增量同步任务、权限账号、分区脚本这些外围内容,我在预案里都把这部分写清楚了,团队演练过一次就知道怎么切。

最后的实践感受

这套项目做完,我最深的体会是:TiDB 和 MySQL 的兼容性确实给 Zabbix 这种老牌监控系统留了一条很平滑的迁移路径。真正复杂的并不是数据库类型的变化,而是历史数据怎么搬得高效、分区策略怎么重新设计、运维习惯怎么跟着调整。分区清理从 DELETE 改成 DROP PARTITION 这一步,给我的印象比迁移本身还深。

如果你手头的 Zabbix 也到了 MySQL 单机写入吃力、清理慢、前端报表越来越卡的程度,先把历史数据量和增长趋势拉出来看看,再对照 TiDB 的集群规格做一次小范围压测,大概率值得一试。迁移过程中逐渐把脚本、分区维护、回滚预案沉淀下来,之后这套系统再扩容,只需要给 TiKV 加节点就行,不必再动应用层,省下来的时间会非常可观。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 7:46:33

财务利益运作防控与人员制衡:岗位、权限、流程三层设计

做财务管理的这些年&#xff0c;“财务利益运作防控”和“人员制衡”这两个词经常被摆在一起&#xff0c;但真正能把它讲清楚、落到系统里的团队并不多。把这个系列写到第十二篇&#xff0c;前面聊过预算、核算、资金计划、成本控制这些具体业务&#xff0c;今天这篇想换一个更…

作者头像 李华
网站建设 2026/10/21 7:46:06

A*与DWA融合:机器人导航中全局路径与局部避障的实战解析

开篇&#xff1a;两条路线&#xff0c;一次缝合做机器人导航的人&#xff0c;迟早会遇到同一个选择题&#xff1a;全局路径规划用A*&#xff0c;局部避障用DWA&#xff0c;两个算法单独用都挺好&#xff0c;为什么合在一起就能解决实际问题&#xff1f;我在实际项目里走过不少弯…

作者头像 李华
网站建设 2026/10/21 7:46:00

AI自动文件管理实战:从规则设计到Python落地

不管你是写文档的、做设计的、还是敲代码的&#xff0c;提到“文件管理”这四个字&#xff0c;估计没几个人不头疼。桌面堆满截图、下载文件夹乱成垃圾场、不同版本的文档散落在三个网盘里、同名文件到处都是&#xff0c;等到真需要用的时候&#xff0c;翻半个小时都找不到想要…

作者头像 李华
网站建设 2026/10/21 7:45:44

四个大模型的GEO优化实战:从AI可见性到品牌引用率提升

1. 先搞清楚一件事&#xff1a;GEO到底在优化什么最近这一年&#xff0c;我特别明显的一个感受是&#xff1a;身边越来越多的人开始习惯把问题直接甩给AI助手。想找个东西、想了解某个产品、想对比方案&#xff0c;不再翻好几页搜索结果&#xff0c;而是直接问DeepSeek、Qwen、…

作者头像 李华
网站建设 2026/10/21 7:45:33

MySQL面试高频考点全梳理:从索引事务到锁与日志的底层原理

作为常年混在技术社区和各种内推群的人&#xff0c;我太清楚“MySQL面经”这四个字的分量了。无论是校招还是社招&#xff0c;后端技术面里MySQL的出镜率几乎接近百分之百&#xff0c;甚至可以说&#xff0c;MySQL聊得深不深&#xff0c;直接决定了面试官愿不愿意给你打高分。很…

作者头像 李华
网站建设 2026/10/21 7:45:33

QVariantHash全解析:从哈希表原理到Qt动态配置实战

开发 Qt 项目这些年&#xff0c;我越来越觉得 QVariantHash 是个被低估的老朋友。很多人写代码时习惯了 struct 字段类型&#xff0c;一行行定义好&#xff0c;编译器帮忙检查&#xff0c;看起来很安全&#xff0c;可一旦遇到"配置项随时可能增加""接口返回结构…

作者头像 李华