news 2026/10/21 7:47:02

Zabbix 历史数据膨胀?一次 MySQL 到 TiDB 的存储迁移全记录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Zabbix 历史数据膨胀?一次 MySQL 到 TiDB 的存储迁移全记录

做监控运维的人,早晚会撞上同一个坎:Zabbix 的数据库文件越来越大,history和trends表动辄几千 GB,MySQL 的磁盘 IO 和主从同步被拖垮,前端报表打开转圈,告警也能延迟几分钟。我之前在某个中等规模的监控项目里也遇到这个问题,检查了所有常规优化手段之后,决定把 Zabbix 的后端存储从 MySQL 迁移到 TiDB,也就是把 MySQL 里的历史监控数据完整导入 TiDB 服务里运行。

这条改造路线走完,整体方向是对的,但中间有不少细节是官方文档不会明确告诉你的。这篇文章把从选型、环境规划、数据迁移、切换验证到后续排障的完整过程都写下来,给后面打算做同样改造的人留一份可复现的参考。

1. 改造背景:Zabbix 后端从“能跑”到“扛不住”

1.1 监控历史数据是存储增长的主要来源

Zabbix 默认把监控数据存在 MySQL 或 PostgreSQL 里,最占地方的是几张历史表:

  • history:浮点数型监控项的历史采样值
  • history_uint:无符号整数型监控项的历史采样值
  • history_str、history_text、history_log:字符和日志类数据
  • trends、trends_uint:趋势数据,按小时聚合

这些表的数据量增长和监控项数量、采样频率直接挂钩。比如每 5 秒采集一次,单一监控项一小时就是 720 条记录,采集几百上千台设备,一天就能产生数百万行数据。MySQL 单机存储在这种写入强度下,一段时间后必然出现两个症状:一是写入跟不上,复制延迟飙高;二是历史数据查询慢,前端图表区域明显卡顿。

我做改造前先统计了一下现状:监控项总数约 12 万,历史数据表约 160 GB,history_uint单表最大,占了近 100 GB。当时的 MySQL 是单机主从架构,磁盘已经是 SSD,但仍经常出现主库 CPU 打满、从库明显延迟的情况。即使清理脚本 housekeeper 一直开着,删除历史数据的速度也赶不上新增速度,属于典型的“存储成为瓶颈”场景。

1.2 为什么选择 TiDB 而不是继续堆 MySQL

遇到瓶颈后,第一个念头是继续压榨 MySQL:升级硬件、优化索引、把历史表分区。但这些都只能延缓问题,解决不了本质。监控数据的写入是持续且并发的,单机 MySQL 的写入能力有物理上限,再往上堆就是主从复制、分库分表,运维复杂度和成本立刻上升。

选择 TiDB 主要看中这几点:

  • 原生分布式:数据自动打散到多个 TiKV 节点,写入可以水平扩展
  • 完全兼容 MySQL 协议:Zabbix 不需要改业务代码,连接方式还当成 MySQL 看待
  • 自动 Rebalance:扩容节点时数据自动迁移,不用手工拆库拆表
  • 支持分区表:可以继续使用 Zabbix 官方的分区维护脚本,按时间切片管理历史数据
  • 事务与一致性:TiDB 提供强一致事务,对 Zabbix 这种同时读写的系统很重要

一句话总结:TiDB 能让 Zabbix 的历史数据存储变成“可水平扩展的 MySQL”,而这正是监控场景最需要的。

1.3 什么样的环境不适合这个方案

不是所有 Zabbix 环境都适合迁移。如果监控规模很小,比如只有几十台设备、历史数据不到 20 GB,那完全没有上 TiDB 的必要,单机 MySQL 配合分区策略完全够用。另一个条件是团队有没有分布式数据库的运维能力,TiDB 集群涉及 PD、TiKV、TiDB 三个组件的日常巡检和维护,比单机 MySQL 多不少事。如果这两条不满足,建议不要动。

2. 环境规划:TiDB 集群与 Zabbix 的版本配套

2.1 软件版本选择与兼容性结论

版本选择是迁移前最重要的一步。我的选择是:

组件版本说明
Zabbix6.4 LTS当前长期支持版本,前端数据库检查要求 MySQL 8.0
TiDB6.5 LTSTiDB 长期支持版本,与 Zabbix 6.x 兼容
源 MySQL8.0.28原 Zabbix 数据库所在实例

Zabbix 6.4 前端在安装或初始化时会对数据库版本做检查,要求 MySQL 8.0 及以上。TiDB 6.5 默认返回的版本号是5.7.25-TiDB-v6.5.x,这个版本号会被 Zabbix 前端判定为“不受支持的数据库版本”,虽然不影响后端读取,但会在前端告警区一直挂着。

解决办法是在 TiDB 配置里把回传给客户端的版本号改成 8.0,配置项是server-version。我使用的是 TiDB 配置文件方式:

[server] server-version = "8.0.27-TiDB-v6.5.6"

改完重启 TiDB 进程,客户端再查SELECT VERSION()就会返回这个自定义版本号,Zabbix 前端的版本检查就过了。

2.2 TiDB 最小集群硬件与部署拓扑

TiDB 集群最小化生产部署建议如下:

组件节点数建议配置磁盘
TiDB Server1 台起4C 8GSSD 100 GB
PD3 台2C 4GSSD 100 GB
TiKV3 台起8C 32GSSD 1 TB

节点数量上,PD 必须是奇数,3 台起步,TiKV 至少 3 台。TiDB Server 可以后面按需增加,但至少要 1 台。磁盘空间估算时要把 TiKV 默认 3 副本考虑进去:原 MySQL 数据 160 GB,会占用 TiKV 总空间约 480 GB,再加上 Region 调度余量和日志文件,单台 TiKV 给 1 TB SSD 比较稳妥。

我用 TiUP 部署集群,拓扑文件里定义了 3 个 PD、3 个 TiKV 和 1 个 TiDB 实例的地址与配置。部署完成后,用tiup cluster display确认所有节点都是健康状态再继续。

2.3 迁移前务必处理的三处 MySQL 差异

TiDB 兼容 MySQL 协议,但不代表全盘兼容所有表结构和 SQL 细节。我提前处理了以下三个差异,避免导入时才发现不行:

  1. 存储引擎:MySQL 的 MyISAM 表在 TiDB 里不支持,导入前全部改成 InnoDB
  2. 字符集与排序规则:Zabbix 在 MySQL 8 默认使用utf8mb4_0900_ai_ci,TiDB 不支持这个排序规则,需要在导出/导入时统一为utf8mb4_bin或utf8mb4_general_ci
  3. 版本号返回:上文提到的server-version配置,提前设好

这三项不处理,后续要么导入直接报错,要么导入成功但前端检查通不过。

3. 数据迁移实操:用 Dumpling + Lightning 完成替换

3.1 停机策略:离线全量为什么最稳

迁移方案上我最终选择了离线全量导入,而不是在线迁移工具做实时同步。原因很简单:Zabbix 的监控数据是持续写入的实时数据,如果一边在 MySQL 继续写入、一边往 TiDB 导,就还得处理增量同步和双写一致性问题,复杂度明显上升,容易出幺蛾子。对监控系统来说,停机迁移的窗口是可以接受的,只要在业务低峰窗口进行,比如周末上午,影响面很小。

实际操作流程是:

  1. 停止 Zabbix Server 服务,让 MySQL 数据库处于静止状态
  2. 用 Dumpling 从 MySQL 导出zabbix全库结构加数据
  3. 用 TiDB Lightning 将导出文件导入 TiDB
  4. 修改 Zabbix Server 和前端配置,指向 TiDB
  5. 启动服务,验证数据完整性

3.2 用 Dumpling 从 MySQL 导出 zabbix 全库

Dumpling 是 TiDB 生态的数据导出工具,兼容 MySQL 协议,可以从 MySQL 实例导出逻辑备份文件,导出的格式可以被 TiDB Lightning 直接识别导入。

先安装 Dumpling,我用的是 TiUP 自带方式:

tiup install dumpling

导出命令:

dumpling \ -h 127.0.0.1 \ -P 3306 \ -u root \ -p '原mysql密码' \ --regex '^(zabbix)\..*$' \ --filetype sql \ --threads 8 \ --output-dir /data/dumpling_output \ --sql-mode "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"

参数说明:

  • --regex '^(zabbix)\..*$'表示只导出zabbix库下的所有表
  • --filetype sql生成 SQL 格式文件,包含建表语句和插入语句
  • --threads 8并发线程数,根据源 MySQL 的磁盘能力调整,8 线程对机械盘可能打满,SSD 可以更高
  • --sql-mode指定导出会话的 SQL 模式,尽量贴近 MySQL 的默认模式,减少导出过程中的兼容问题

导出完成后,在/data/dumpling_output目录下会看到类似zabbix-schema.sql、zabbix.history-schema.sql、zabbix.history.sql这样的文件,分别对应库结构、表结构和数据。

3.3 用 TiDB Lightning 导入 TiDB

TiDB Lightning 是 TiDB 的高性能数据导入工具,我做本次导入用的是物理导入模式(local backend),原理是直接把数据写成 TiKV 能识别的 SST 文件再调度到集群里。相比用 mysql 命令行一条条执行 SQL,速度快得多,我这套 160 GB 数据,全程导入大约用了 40 分钟。

Lightning 的配置文件tidb-lightning.toml这样写:

[tidb] host = "10.0.0.21" port = 4000 user = "root" password = "tiup部署时的root密码" status-port = 8280 pd-addr = "10.0.0.21:2379" [tikv-importer] backend = "local" sorted-kv-dir = "/data/sorted-kv-dir" [mydumper]>tiup tidb-lightning -config tidb-lightning.toml

日志里看到checksum pass和import finished字样说明导入成功。导入前我在 TiDB 里已经创建了空的zabbix库,字符集统一为utf8mb4、排序规则utf8mb4_bin,Lightning 会自动建表并插入数据。

3.4 修改 Zabbix 服务端与前端配置完成切换

数据导入完成后,开始切换连接。修改 Zabbix Server 配置文件/etc/zabbix/zabbix_server.conf:

DBHost=127.0.0.1 DBName=zabbix DBUser=zabbix DBPassword=新数据库密码 DBPort=4000

DBPort改为 TiDB 的服务端口 4000,而不是 MySQL 的 3306。DBUser 和 DBPassword 在 TiDB 里要提前创建好,并授权访问zabbix库。

前端配置文件/etc/zabbix/web/zabbix.conf.php同样改端口和密码:

$DB['SERVER'] = '127.0.0.1'; $DB['PORT'] = '4000'; $DB['DATABASE'] = 'zabbix'; $DB['USER'] = 'zabbix'; $DB['PASSWORD'] = '新数据库密码'; $DB['TYPE'] = 'MYSQL'; $DB['CHARSET'] = 'utf8mb4';

Zabbix 端不需要改类型,因为 TiDB 走的就是 MySQL 协议,前端仍然按 MySQL 类型连接。

改完后重启服务:

systemctl restart zabbix-server systemctl restart httpd # 或者 php-fpm,按前端部署方式而定

3.5 数据切换后的五步验证

切换完成不代表结束,我做了一套完整的验证清单:

  1. 查看 Zabbix 前端首页能否正常加载最新监控数据和告警
  2. 检查前端“报告”页的趋势图能否正常出图,这是验证trends表数据是否完整的最快方式
  3. 在 TiDB 里执行核心数据量统计,和 MySQL 导出前的总数对比
SELECT COUNT(*) AS cnt FROM zabbix.history_uint; SELECT COUNT(*) AS cnt FROM zabbix.trends_uint;
  1. 用 Zabbix 自带的探针或手动执行新的数据采集,确认能正常写入 TiDB
SELECT itemid, clock, value FROM zabbix.history_uint ORDER BY clock DESC LIMIT 5;
  1. 确认 housekeeper 进程日志正常,历史清理任务能执行,不会因为切库失败而堆积

五步都通过后,说明迁移完成。此时不要着急删除原 MySQL 备份,建议保留至少一周,回滚窗口要留足。

4. 上线后的排查与调优经验

4.1 切换后的真实性能变化

上线稳定运行一周后,我做了前后对比。最直观的感受是前端打开“最新数据”和“图形”不再卡顿。以前点开一个包含几十个监控项的图形页面,MySQL 要扫大量历史数据,经常等 5 秒以上;切换 TiDB 后基本在 1 秒内出图。这一方面是因为数据分散到了多台 TiKV 并行计算,另一方面也和 TiDB 对读请求的弹性调度有关系。

写入方面,Zabbix Server 的队列监控显示,历史数据发送到数据库的间隔明显缩短,不再出现因为数据库写入慢导致的积压告警。

4.2 高频报错与处理速查表

迁移和上线过程中,我碰到了几个别人大概率也会撞上的问题,整理成速查表:

报错/现象原因解决方式
前端提示数据库版本过低TiDB 默认返回 MySQL 5.7 版本号设置server-version为 8.0.x
建表报Unknown storage engine 'MyISAM'遗留 MyISAM 表改为 InnoDB 后重新导入
导入报Unknown collation 'utf8mb4_0900_ai_ci'MySQL 8 默认排序规则 TiDB 不支持导出前统一排序规则为utf8mb4_bin
Zabbix Server 起不来,日志提示数据库连接失败DBPort/IP 没改或 TiDB 未启动检查DBPort=4000,确认tiup cluster display状态正常
前端页面卡顿,TiDBCPU 高并发查询多集中在 TiDB Server增加 TiDB Server 实例或优化慢查询
查询报Out of sorted memoryTiDB 单次排序内存超限调大tidb_mem_quota_query或优化 SQL

那几天我印象最深的坑是排序规则问题。源 MySQL 的表结构里带着utf8mb4_0900_ai_ci,Dumpling 导出时数据中心保留了原排序规则,导入到 TiDB 直接报错。最后是把所有导出的-schema.sql文件里的utf8mb4_0900_ai_ci批量替换为utf8mb4_bin,再重新导入才正常。

4.3 历史数据清理:从 housekeeper 到分区表

Zabbix 默认用 housekeeper 定期清理过期历史数据,本质是执行 DELETE 语句。在 TiDB 里,DELETE 因为底层要扫描多个 Region,删除速度一般,如果历史数据量很大,housekeeper 可能来不及清。我当时观察到的现象是:历史表的数据量不再下降,housekeeper 任务一堆排队。

解决思路是放弃对历史表依赖 DELETE,改用分区表的 TRUNCATE PARTITION 方式。以history_uint为例,按天做 RANGE 分区:

ALTER TABLE zabbix.history_uint PARTITION BY RANGE (clock) ( PARTITION p20250101 VALUES LESS THAN (UNIX_TIMESTAMP('2025-01-02 00:00:00')), PARTITION p20250102 VALUES LESS THAN (UNIX_TIMESTAMP('2025-01-03 00:00:00')) );

清理时直接丢弃过期分区:

ALTER TABLE zabbix.history_uint DROP PARTITION p20250101;

TRUNCATE 分区的开销远小于逐行 DELETE,而且对 TiDB 的 Region 调度更友好。Zabbix 官方有一个分区维护脚本,继续在 TiDB 上运行即可,它会定期为新的一天添加分区,再按保留天数删除过期分区。

4.4 TiDB 侧值得调整的配置项

稳定运行后,我对 TiDB 集群做了一些针对 Zabbix 工作负载的调整,这里挑重点说:

  • SQL 模式:在 TiDB 集群配置里打开ONLY_FULL_GROUP_BY,避免 Zabbix 某些按监控项分组查询的 SQL 因为模式不一致出现意想不到的行为
  • TiKV 存储引擎缓存:把storage.block-cache.capacity调整为节点物理内存的 30% 左右,提高热点数据命中率
  • 内存保护:设置tidb_mem_quota_query = 8GB,避免了大查询直接打爆 TiDB Server 内存
  • 慢查询日志:打开慢查询记录,把执行超过 1 秒的 SQL 捞出来分析

这些配置都改在拓扑文件的配置段里,用tiup cluster reload滚动生效,不中断业务。

5. 项目复盘:这三个坑最值得避开

5.1 最值得避开的三个坑

如果让我重新做一遍,有三件事会提前做得更充分:

  1. 导出前先统一排序规则。在 MySQL 导出前就把表结构里的utf8mb4_0900_ai_ci全部改成utf8mb4_bin,而不是等导入报错再批量替换文件,能少走很多弯路。
  2. 提前确认 Zabbix 前端版本检查机制。server-version这个配置项要写在集群初始化配置里,而不是上线前临时改。
  3. 迁移前评估 Lightning 落盘空间。sorted-kv-dir如果空间不够,导入中途会卡住,那个状态折腾人。

5.2 如果规模再大一级,后续怎么做

这次改造解决的是 GB 级历史数据的瓶颈。如果监控规模再往上走,比如监控项超过 50 万、历史数据到 TB 级别,TiDB 这边依然有扩展空间:直接给集群加 TiKV 节点,数据会自动均衡;TiDB Server 加一台做负载分担;如果分析类报表多,还可以给trends表挂 TiFlash 列存副本,分析查询走列存会更快。加节点操作并不复杂,用 TiUP 修改拓扑文件后执行scale-out就行。

还有个方向是把 Zabbix Server 与 TiDB 之间的连接前面加一个连接池代理,避免前端并发激增时把 TiDB 连接打满。

5.3 我个人的迁移心得

这次改造给我的最大体会是:Zabbix 存储选型,与其在单机 MySQL 上不断加索引、清数据、做分片,不如直接换一个原生支持水平扩展的分布式数据库。TiDB 的 MySQL 兼容性让整个切换过程不需要改一行业务代码,迁移工具链也足够成熟,难度远比想象中低。

再补一个细节:迁移完成后,原 MySQL 彻底停用前,一定要留一台离线备机保留原库一个月左右。监控系统运行过程中经常需要回溯“半个月前的原始数据”,如果新库验证没做透,回退还有后路。我是在一个月确认无误后才把原 MySQL 实例下线的,这个谨慎一点不亏。

这次的项目记录就写到这里。如果你正准备做类似的 Zabbix 存储迁移,希望这篇能帮你少踩几个坑。迁移本身不复杂,复杂的是把细节做踏实。

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

Zabbix数据库迁移实战:从MySQL到TiDB的踩坑与调优

干运维这些年,第一次在监控系统上做这么大的改动——把 Zabbix 的后端数据库从 MySQL 换成 TiDB,说实话一开始心里也没底。当时我们这套 Zabbix 已经跑了三年多,监控着两千多台服务器和网络设备,item 数量超过二十万,历…

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

通达信艾略特波浪划线指标源码解析与实战调参

简介:这是一份面向股票技术分析爱好者与通达信指标编写者的艾略特波浪划线公式源码文档,基于艾略特波浪理论,通过移动平均线与高低点计算,在主图上自动绘制五浪结构,帮助看盘时快速识别趋势阶段与关键价位。资源包内共…

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

基于纳什博弈的多微网电热双层共享策略Matlab复现详解

做微电网或综合能源方向的课题,大概率会遇到这样一个场景:手上有好几个微网的负荷、光伏、热负荷和储能数据,每个微网都有自己的运营方,彼此不能互相指挥,但物理上却硬生生连在同一条联络线或供热管道上。谁该多出力、…

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

CSP初赛计算机基础知识集训课件:进制转换与补码精讲

简介:这份信奥帮初赛集训配套课件面向备战CSP-J1/S1(NOIP)初赛的选手与教练,聚焦计算机基础知识这一必考模块,帮助梳理零散概念、建立系统认知。课件以PDF形式呈现,共1个文件,压缩包约4.07MB&am…

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

LangGraph多智能体协作原理与状态机设计实战

1. 项目概述:这不是一个“多智能体框架”的演示,而是一次对协作逻辑的手术式解剖LangGraph Multi-Agent案例讲解——这八个字里,“LangGraph”是工具,“Multi-Agent”是形态,“案例讲解”才是真正的落点。我接触过太多…

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

TensorFlow Lite端侧部署实战:从模型转换到Android性能优化

如果你正读到第17章,意味着前面的训练、评估、导出这些环节已经把你折腾得差不多了,接下来要面对的就是那个很现实的问题:怎么把辛辛苦苦训练出来的模型,真正塞进手机或者嵌入式设备里跑起来。这一章要讲的TensorFlow Lite集成&am…

作者头像 李华