在Zabbix监控平台跑了将近三年数据量到了一定规模后MySQL的维护成本开始变得有些失控。清理历史数据、分区维护、主从延迟、磁盘空间每一项都在消耗精力而真正的问题在于只要业务扩张监控项和采集频率不变数据库的压力只会越来越大光靠MySQL的纵向升级迟早遇到天花板。这篇文章不是科普TiDB是什么而是记录一次真实的企业运维替换过程——把Zabbix默认的MySQL后端换成TiDB分布式数据库。如果你也在维护上千台主机、几十万监控项的Zabbix集群特别是history和trends表已经膨胀到几百GB甚至上TB量级这篇内容应该能帮你减少很多试错成本。先交代一下这次替换的背景监控规模大概在5000主机监控项60万每秒写入峰值在2万条左右保留策略是history 30天、trends 90天。MySQL主从架构在这个规模下从库经常因为大事务延迟几个小时housekeeper清理任务也经常跑不完导致磁盘占用只增不减。1. Zabbix数据增长瓶颈MySQL撑不住的本质原因Zabbix的后端数据库压力和我们平时理解的业务数据库有很大区别。它的写入模式是高频小批量写入每台主机每秒钟都有多个监控项在插入数据而且几乎全是insert操作很少update和delete。这种模式下MySQL的InnoDB引擎要不停刷新redo log、维护二级索引、做随机IO即使加了SSD和足够大的buffer pool单库单实例的写入能力依然有物理上限。等到历史数据累积到一定体量更麻烦的问题也随之而来。Zabbix的housekeeper进程会定期执行大范围delete这些delete往往一次性涉及上千万行在InnoDB里会产生巨大的undo和purge压力主从复制在这种大事务下更是雪上加霜。我这边最直观的体验是凌晨三点housekeeper一跑从库的延迟立刻从几十秒飙升到几小时期间如果业务方要查监控数据体验非常糟糕。1.1 MySQL时期遇到的具体问题清单拿这次替换前备份的一份现场数据来说问题集中在几个层面写入吞吐瓶颈主库在高峰期CPU经常达到70%以上IO util满盘。尽管binlog已经调成了row模式但大事务产生的binlog量依旧能瞬间打满磁盘带宽。历史数据清理困难虽然Zabbix官方有分区表方案但分区数量过多时ALTER TABLE重建分区耗时非常长而且housekeeper清理逻辑和分区的配合并不完美。查询响应变慢特别是要跨长时间范围查历史趋势时一张几亿行的表上做聚合查询耗时经常超过30秒前端图表加载都出现明显卡顿。主从延迟不可控业务高峰期主库写入一波动从库延迟就跟着抖整个过程很难提前预测和干预。这些问题的根源是MySQL单库架构下CPU、内存、磁盘都绑在同一台机器上任何一项资源达到瓶颈整体性能就跟着塌方。而Zabbix的数据模型和查询特征其实非常适合分布式存储的sharding思路。1.2 为什么最终选了TiDB而不是继续优化MySQL其实在考虑TiDB之前团队也花了两三周时间尝试优化MySQL的配置和架构。比如增加buffer pool、升级到更高规格的物理机、调整history表索引、手工维护分区等。但核心矛盾一直无法回避单机资源终究有限写入量一旦超出阈值加内存换CPU只是把爆发点往后延并不能根治问题。TiDB的吸引力在于这几个点完全兼容MySQL协议Zabbix连接层几乎不用改代码DSN换一下就能连。存储层TiKV天然分片数据按Region自动拆分并分布到多个节点写入能力和存储容量可以靠加机器线性扩展。强一致性和分布式事务对Zabbix这种写多读少但要求不丢数的场景非常合适。在线扩缩容能力让后期运维有底气不用每次扩容都停机迁移数据。另外要说明的是Zabbix虽然官方文档主要支持MySQL和PostgreSQL但TiDB的协议兼容层做得比较成熟通过配置zabbix_server和前端PHP的连接驱动就能对接。很多没做过的人会担心TiDB是否被官方支持实际上只要DSN指向的协议是MySQLZabbix是感知不到后端差异的。2. TiDB集群部署与关键参数落地这次部署用的是TiDB 6.5 LTS版本属于长期支持版本稳定性上比较放心。整套集群规划了三台物理机加一台中控机的拓扑中控机用来跑TiUP和监控组件数据节点由三台同等配置的机器组成每台机器承担TiDB Server、PD和TiKV的混合部署角色。这里有个经验要分享对于Zabbix这种体量不需要一开始就按官方推荐的大规模集群来部署。三台机器混合部署足够支撑相当长一段时间的容量需求后面真扛不住了再单独拆TiKV节点做水平扩展也不迟。初期搞太多节点反而增加运维复杂度。2.1 TiUP方式部署和拓扑规划TiUP是官方推荐的部署工具用它对多节点做统一管理很省事安装配置流程大概是这样# 中控机安装TiUP curl --proto https --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh # 声明集群拓扑文件YAML格式 tiup cluster deploy zabbix-tidb v6.5.0 ./topology.yaml --user root -p拓扑文件里需要重点关注的是TiKV的存储参数。在混合部署场景下如果不限制TiKV占用的存储目录和capacity它默认会把整个数据盘都当成自己的存储空间一旦多个组件共用一块盘很容易出现磁盘空间管理混乱。我的拓扑配置大致长这样tikv_servers: - host: 10.0.1.1 port: 20160 status_port: 20180 data_dir: /data/tikv config: storage.capacity: 800GB raftstore.capacity.ratio: 0.6 - host: 10.0.1.2 port: 20160 status_port: 20180 data_dir: /data/tikv config: storage.capacity: 800GB raftstore.capacity.ratio: 0.6 - host: 10.0.1.3 port: 20160 status_port: 20180 data_dir: /data/tikv config: storage.capacity: 800GB raftstore.capacity.ratio: 0.6 pd_servers: - host: 10.0.1.1 - host: 10.0.1.2 - host: 10.0.1.3 tidb_servers: - host: 10.0.1.1 port: 4000 status_port: 10080 - host: 10.0.1.2 port: 4000 status_port: 10080 - host: 10.0.1.3 port: 4000 status_port: 10080TiKV的storage.capacity参数尤其重要它决定了Region调度时是否认为空间充足。如果不设置TiKV会读取整个挂载盘的空间但混合部署时其他组件也会占用磁盘久了会导致空间误判。建议留出20%到30%余量给日志、快照和系统文件。2.2 Zabbix Server连接TiDB的配置变更Zabbix Server本身是用C语言写的连接MySQL走的是libmysqlclient或mariadb-connector-c。用TiDB完全不需要改Zabbix代码只需要改配置文件里的数据库地址、端口和DSN参数# /etc/zabbix/zabbix_server.conf DBHost10.0.1.1 DBNamezabbix DBUserzabbix DBPasswordxxxxxx DBPort4000注意这里的DBPort要改成TiDB Server的端口4000而不是MySQL的3306。另外前端PHP连接的时候如果之前用的是mysqli扩展需要确认编译时是否启用了mysqlnd或者直接改用PDO_MYSQL指向TiDB。这块只要按普通MySQL连接来处理即可协议层的兼容性TiDB做得很到位。还有一个小细节是时区设置。Zabbix内部记录了大量的时间戳TiDB默认时区是UTC如果Zabbix Server和前端都跑在Asia/Shanghai时区建议在TiDB的DSN或会话参数里统一对齐否则时间字段返回结果会和预期差8个小时。TiDB的time_zone参数需要设为08:00可以在集群配置中通过session级变量统一设置或者在Zabbix的PHP配置里指定连接初始化SQL。2.3 初始化数据库结构与权限TiDB虽然兼容MySQL但有些MySQL特有的系统表不存在Zabbix的建表脚本本身没有依赖那些特殊功能所以直接用官方提供的schema导入即可。过程没有想象中那么复杂zcat /usr/share/doc/zabbix-server-mysql-*/create.sql.gz | mysql -h 10.0.1.1 -P 4000 -uzabbix -p zabbixZabbix的建表语句里有ENGINEInnoDB、AUTO_INCREMENT这些关键字TiDB导入时会自动忽略或转化为TiDB内部的等价实现不会报错。唯一需要注意的是字符集和排序规则建议统一设为utf8mb4_general_ci避免后续告警内容里的特殊字符出现乱码。导入完成后检查几个关键表是否生成成功比如history、history_uint、trends、trends_uint对应的分区表结构是否正常。Zabbix初始化SQL里默认没有分区只是普通表如果没有额外执行分区脚本导入后会以普通表形式存在。3. 数据迁移从MySQL到TiDB的实战过程数据迁移是整个替换过程中最让人紧张的一环毕竟监控历史数据虽然不像业务数据那样直接产生收入但一旦丢了后续故障分析和容量规划就会缺少依据。为了避免中断迁移分两个阶段进行先是全量迁移再是增量同步。3.1 全量迁移阶段的操作细节全量备份我们用Dumpling导出Dumpling是TiDB生态里的逻辑导出工具但它的兼容性做得不错也可以直接从MySQL导出数据。命令大致如下dumpling -h 10.0.0.10 -P 3306 -u root -p xxxx \ --filetype sql \ --threads 16 \ --output /data/backup/zabbix \ --database zabbix这里有个注意点导出大表的时候Dumpling会按chunk大小自动拆分文件对Zabbix这种几十GB的history表来说导出时间主要受磁盘IO和网络带宽影响建议在从库上导出避免压到主库。导出完成后把文件传送到TiDB中控机再用Lightning导入tiup tidb-lightning -config lightning.tomlLightning的配置文件里主要设置数据源目录和TiDB连接信息。如果对导入速度有要求可以用region-concurrency调高并发。但要注意Lightning导入时默认是物理导入模式导入过程中目标表对Zabbix不可见所以必须在停写窗口做或者先导入到临时库再切换。3.2 Zabbix停机窗口切换监控平台有一定的停机容忍度但也不能太长。我们选择了凌晨业务低峰期操作全量导入后的增量同步用TiDB的binlog组件完成了从MySQL到TiDB的追平等两边数据一致后再把Zabbix Server的配置指向TiDB整个过程大约两个多小时。如果嫌binlog同步组件配置麻烦也可以直接采用分阶段停写方案先停Zabbix采集导出全量导入TiDB然后重新启动采集。这种方案的好处是逻辑简单、不需要额外的同步组件坏处是停机窗口会拉长到几个小时适合数据量不大或团队对操作时间要求不苛刻的场景。我个人更推荐binlog增量同步方案数据量较大的情况下停机窗口大幅缩减操作风险也低很多。配置时注意一下TiDB的DM组件需要访问MySQL的binlogMySQL必须开启GTID模式且binlog_format设为row否则同步链路会中断。3.3 迁移后数据校验数据迁移完不能直接宣布成功必须做完整校验。最实用的校验方式是分别统计每个核心表的行数和关键字段的聚合值对比MySQL和TiDB两侧的数据。这里分享一个比较高效的校验思路-- 对比表行数 SELECT COUNT(*) FROM history; SELECT COUNT(*) FROM history_uint; SELECT COUNT(*) FROM trends; -- 对比时间范围分布 SELECT MIN(clock), MAX(clock), COUNT(*) FROM history; SELECT MIN(clock), MAX(clock), COUNT(*) FROM trends;如果两端行数一致、时间范围一致基本可以确认迁移成功。还可以抽查几个itemid在时间轴上的数据曲线确保粒度没有丢。实际做下来TiDB的校验结果如果出现个位数差异多半是增量同步的过程中有事务没有完全追平需要检查DM的同步延迟。4. 替换后Zabbix的适配调优与踩坑记录迁移完只是开始后面的适配调优才是真正决定这套架构能用多久的关键。TiDB毕竟不是MySQL在事务模式、分区表、DDL行为、查询优化器上都有自己的一套逻辑。Zabbix跑在TiDB上的性能表现很大程度上取决于这些细节有没有处理好。4.1 分区表策略保留还是不保留Zabbix官方优化方案里history和trends表通常建议做分区按天或者按周建分区方便清理历史数据时直接DROP分区。在MySQL上这套方案非常有效但到了TiDB上分区表的实现方式不同查询和写入的行为也随之改变。TiDB支持Range分区和List分区Range分区的基本语义和MySQL一致。但实际测试下来Zabbix的housekeeper清理逻辑如果直接依赖DROP分区反而可能和TiDB的调度产生冲突。更稳妥的做法是取消分区改用TiDB原生的生命周期管理方式——直接DELETE旧数据配合GC机制回收空间。可能有读者会问MySQL上正是因为DELETE导致清理慢才用分区为什么TiDB上DELETE方案反而可行原因在于TiDB的TiKV是LSM-Tree存储模型删除操作的写入是顺序追加不会像InnoDB那样引发随机IO和碎片整理删除行产生的空间只要过一轮RocksDB compaction就会被回收。而且TiDB可以按主键范围快速定位需要清理的数据清理效率远高于MySQL的大范围DELETE。4.2 一个容易忽略的问题事务大小限制TiDB默认单条事务有大小限制包括txn-entry-size-limit单KV条数限制和txn-total-size-limit总大小限制。Zabbix的housekeeper和某些大报表请求可能在一次事务里更新大量行如果超过TiDB的默认事务大小上限就会报错。这里需要根据实际情况调大限制同时注意别调得太夸张。比较合理的做法是把tidb_txn_mode设为optimistic优化模式下大事务放宽一些保持乐观事务的大事务特性再配合调大KV数上限SET GLOBAL tidb_txn_mode optimistic; SET GLOBAL tidb_store_limit 100 GB; SET GLOBAL tidb_mem_quota_query 8 GB;这在TiDB 6.5上是可行的。如果是悲观事务模式大事务很容易锁冲突和重试失败。Zabbix的写入和清理任务大多不依赖强事务隔离用乐观事务模式反而更合适。4.3 housekeeper清理任务在大数据量下的表现Zabbix的housekeeper进程会根据保留策略定期执行DELETE在MySQL时代这是最令人头疼的任务。切换到TiDB后整体清理效率明显改善但首周运行时还是发现了一些性能抖动主要原因是TiKV的compaction触发时机和流量峰值重叠导致清任务和实时写入抢资源。解决方式是手动控制GC的触发时间以及清理速率。TiDB的GC是周期性运行的可以把GC的启动窗口设置到凌晨低峰期避开housekeeper的清理高峰SET GLOBAL tidb_gc_scan_interval 3h; SET GLOBAL tidb_gc_scan_worker_concurrency 3;实际测试下来housekeeper在TiDB上的运行时间从MySQL时期的几小时缩短到几十分钟而且不再出现主从延迟放大问题前端查询的QPS也没有明显波动这是最直观的改善。4.4 查询性能优化统计信息和索引设计Zabbix前端图表和报表查询时经常按照itemidclock的范围做聚合这类查询依赖索引和统计信息。TiDB的优化器依赖统计信息来预估行数如果统计信息不新鲜很容易选出错误的执行计划。建好数据、跑一段时间后建议对核心表做一次ANALYZE TABLE并且设置自动收集统计信息的策略ANALYZE TABLE history; ANALYZE TABLE history_uint; ANALYZE TABLE trends; ANALYZE TABLE trends_uint;常见误区是认为只要建了索引就万事大吉其实TiDB在索引选择和并发扫描上的行为与MySQL有明显差异。TIDB的MPP架构下聚合查询往往可以拆成并行扫描多个Region前提是优化器判断扫描代价足够低。如果发现某些大查询仍然走全表扫描多半是统计信息过期手动ANALYZE后基本都能扭转。5. 真实性能对比MySQL与TiDB的关键数据替换前后我们做了几轮基准测试和实际负载对比包括写入吞吐、历史数据查询耗时、清理任务耗时、磁盘占用四个方面结果相当有参考价值。测试指标MySQL主从架构TiDB三节点集群高峰每秒写入行数约2.0万约4.5万历史数据查询30天范围平均35秒平均8秒housekeeper清理任务时长经常超过2小时约25分钟磁盘占用同一保留策略历史表膨胀严重数据压缩明显写入吞吐提升主要得益于TiKV的分布式写入能力三节点的并行度天然高于单主库。查询耗时的提升则来自TiDB对聚合查询的并行处理。清理任务的时间大幅缩短后整套监控平台的稳定性都上了一个台阶夜间不再出现因为清理历史数据导致的告警延迟。磁盘占用这块非常有说服力。三副本复制策略其实增加了原始数据体积但TiKV本身采用压缩存储加上LSM-Tree的写入模式较紧凑实际物理占用比MySQL单副本加binlog加从库副本的总空间还要节省。从运维成本角度看这算是个小惊喜。6. 后端切换后的监控与长期运维要点Zabbix本身就是监控平台但替换后端之后TiDB集群自身的状态监控同样不能忽略。如果TiDB的所有节点都被Zabbix监控一旦Zabbix本身出问题就失去了监控视角所以我强烈建议单独部署一套PrometheusGrafana来监控TiDB集群自身的指标。TiDB生态里自带Prometheus监控方案部署后主要关注几个关键指标TiKV的CPU使用率、PD的Leader切换次数、TiKV的磁盘IO延迟、Region数量是否均衡、GC耗时等。长期运维中发现最需要重视的是TiKV的Region均衡如果某台机器上的数据分布不均匀整集群的性能就会受限于最忙的那个节点。另外定期备份依旧是必须的。虽然TiDB天然有3副本但逻辑错误、误删表这种场景多副本也救不回来。我们每周做一次全量备份保存到独立存储用的工具是BRtiup br backup full --pd 10.0.1.1:2379 \ --storage local:///data/backup/tidb \ --ratelimit 128恢复时同样用BR进行操作相对简单数据安全兜底就靠它了。7. 这套替换方案的局限性和适用边界TiDB替换MySQL并非所有Zabbix场景都适用需要理性看待它的边界。如果你的监控规模在几百台主机以内监控项不到十万个history表只有几十GBMySQL单机完全能轻松应对完全没有必要引入分布式架构。分布式系统带来的运维复杂度是实打实的多一个组件就多一份维护工作。另外TiDB的硬件资源要求比MySQL高。三节点集群的生产环境至少需要每台机16核CPU、64GB内存起步磁盘最好是SSD或者NVMe。如果硬件规格不足TiKV的性能反而可能比不上单机MySQL。还有一点如果公司对数据库运维的认知还停留在传统脚本化运维没有专门的DBA或者基础设施团队我建议谨慎考虑。TiDB的日常维护需要理解Region调度、Raft一致性、LSM-Tree压缩机制等分布式系统概念踩坑的时候不一定能从普通MySQL的文档里找到答案。Zabbix场景选择TiDB核心推动力永远是数据量增长带来的单机瓶颈而不是追新技术的热度。架构选型要给业务留出足够的增长余地同时也要知道它在什么条件下会失效。这次替换从规划到上线前后花了三周时间实际停机切换两小时。整个过程中踩了不少坑但最大的收获是验证了一条路Zabbix在分布式存储后端上完全可以健康地跑起来而且性能余量非常充足。如果你也在观测平台数据量增长带来的数据库压力希望这次的替换细节能帮你少走一些弯路。
阅读完成 · 觉得有帮助?