Zabbix 作为一个老牌的开源监控方案,长期被用于生产实践。但是原生方案一般会采用 MySQL 作为后端存储,无法应对更大规模的监控。因此我们选择使用TiDB来替换MySQL,TiDB 兼容 MySQL 协议,替换 MySQL 之后可以增强 Zabbix 的大规模监控能力,实现新的监控方案 TiZabbix。
通过优化监控实施逻辑,TiZabbix 弥补了因 TiDB 和 MySQL 差异造成的诸多问题,成功完成了 10000+ 监控对象和 16T 数据存储查询的实践。本文就将为大家介绍我们是如何把 TiDB 应用在金融行业的后台运维监控上。
Zabbix 是一个比较老牌的开源监控方案,这里只做一个简单介绍,Zabbix 主要分为四个部分:
传统的 Zabbix 监控方案主要有以下几个问题,这些问题都是由单机数据库 MySQL 引起的:
这里是一个简单的时间轴:
接着分享一下具体的实践历程,我们在这个过程中陆陆续续解决了一些问题,才达到了刚才说的 18T 的监控数据的一个相对稳定的状态。
首先,一开始是不改动 Zabbix 的源码,半黑盒替换数据库。改源码是一个系统性的工程,难度比较大。为什么说半黑盒替换呢?因为虽然没有改源码,但是在遇到问题时,需要通过阅读源码来通过一些替换方案或者绕行方案来解决替换过程中遇到的问题。
下面就是实践中遇到的一些问题。和原生不一样,监控对象自动注册我们改为使用 API 延迟注册,Zabbix 自动注册功能是它实现监控自动化的一个重要功能。但是 TiDB 是乐观锁(较新的版本已经支持悲观锁了),和 MySQL 的悲观锁是有区别的,当大规模的自动注册时,它是有严重的事务冲突的,所以就把自动注册功能改为用串行的 API 的延迟注册,通过 API 调用的方法,来将新上的监控分区注册上来,解决事务冲突的问题。
接着就遇到了 History 表的问题,因为 Zabbix 里几个 History 表是监控数据的存储表,是非常大的。当时一开始,我们用的是 TiDB 2.1 版本,还不支持表分区,所以存储时间长了后,删数据的问题比较难处理。升级到 3.0 版本,支持了表分区,通过 Drop Partition 来解决历史数据的删除问题。所以在用的过程中,对于大表的表分区还是非常重要的。
接下来还遇到一个问题,Log 类型的数据是一个长字符串,在 2.1 版本的时候,到了一定的数据量后发现所有数据都写入不进去。当时,看了 TiDB 的官方手册里提到写放大的问题,觉得可能是 Log 类型的长字符串引起的。对于监控来说,数值性的数据它的历史参考价值比较大,像 Log 的参考价值比较小。因此,把 Log 型的采集关掉后,数据库的写入就恢复了。
规模更大了以后,又遇到了外键约束的问题。因为 TiDB 是不支持外键约束的,而原生 Zabbix 后端数据库是 MySQL,是有外键约束的要求的,特别是在外键里,有一个主键和外键的级联删除功能,相当于从数据库层面实现而不是应用代码实现这个功能。所以,因为外键的问题也造成了某些因为 Low level discovery(Zabbix 里的自动发现功能)的问题,简单举例来说,就是比如说 Linux 和挂载点,需要发现每个挂载点来监控每个挂载点的磁盘使用量,这种自动发现的功能产生的告警就会因为外键的问题发生错乱。
除了外键约束的问题外,又发生了数据无法写入的问题。后来阅读了 Zabbix 的源码,在源码中发现,在判断告警规则的时候,有一个锁缓存的操作,可以锁掉 Zabbix Server 上的缓存。因为 Zabbix Agent 采上来的数据是先缓存到 Zabbix Server 的内存里,锁缓存以后,缓存的东西就不往数据库里写了,因此,后端数据库就无法写入。
最终因为这两方面的原因,我们决定把告警功能裁减掉,将TiDB 用在 Zabbix 后,只用它来采集、存储和查询数据。但是告警去掉了,怎么来弥补这个功能呢?在生产环境上,我们通过使用 Zabbix Agent 的本身双写能力(双写到不同 Server),往两个方向的 Server 上写数据。一个 Server 上对应的是 MySQL,用来实现告警功能,它的告警不会受外键的影响,但是它的数据存储就特别特别少,可以解决性能问题。另一方向的数据把它写到对接 TiDB 的 Server上,就不要告警功能,只要数据的访问和大规模存储。最终通过数据和告警的分离解决了这个问题。
接下来,简单说一下使用过程的一些小技巧。
1)在设计过程中,架构要尽量的简单。Zabbix 支持主 Server 上再放 proxy,但是一开始使用,建议先不用 proxy,因为 proxy 会引入复杂度。单 Zabbix Server 的情况下,按照现在的性能指标,保持现在的数据采集频率和存储时间,20000+ 的监控对象应该是没有问题的。
2) Agent 采用主动模式即 Zabbix agent active,这种模式可以有效减少 Zabbix server 的压力。因为在被动模式下,Zabbix server 性能消耗比较多,而在主动模式下,相当于把压力下推到 Zabbix Agent 的采集端,这个压力对单个服务器来说是微乎其微的;但是如果都叠加压到 Server 上, Server 肯定受不了的,所以通过选择 active 的模式,来减小 Server 的压力。
3)将 Zabbix 里的配置项 HistoryCache Size 设置为 2G 最大值,可以弥补硬件的不稳定性。刚才也提到了,因为没有用到 TiDB 建议的比较好的硬件,所以硬件性能的缺失就造成了 TiDB 的一些不稳定因素,有时数据写入会比较慢,就会积压到缓存里,把缓存设置的尽量大就会保证数据的不流失。虽然积压了,但是随着性能的恢复,数据是可以重新再写进去的,只是产生了一定的延时,但没有造成数据的丢失。
4) API 的调用不要过于频繁。因为 API 调用过程中权限的检查是要频繁的查和写同一个表的同一行数据,这会产生严重的事务冲突,特别是在 TiDB 乐观事务下,严重的事务冲突会拖垮数据库的。所以,API 调用不要过于频繁,如果需要多进程,或者多线程的调用 API,最好是多用几个 Session ID,Session ID 是权限检查的最小单元,这样可以避免这种情况。
5)随着数据量的增大,Web 的一些操作会失效,需要灵活的使用 API。失效主要是因为数据库事务比较大,前端会超时,因此,当数据量比较大时,比如说要在前端大规模的改一些东西,这时就要灵活的使用 API。因为 API 是一个自动化非常好的手段,通过灵活的使用 API,会规避这个问题。
我们通过以上的探索来解决了一些问题,完成了 TiDB 在 Zabbix 中的有效应用。
1)监控的数据中台化方案。TiZabbix 是用在监控数据的中台化方案,主要解决数据大量的采集、存储和查询,可以提供更大量的、更长时间监控的历史数据,方便我们进行数据分析、查询和一些复杂问题的定位。
2) Zabbix-Server 高效且支持多种数据采集方式。我们知道,原生的告警规则是比较简单的,只有通过较多历史数据的关联查询分析才能有效定位一些问题。同时, Zabbix-Server 比较高效,单 Server 下我们用的是虚机(一般最大 64G 内存),它是支持 20000+ 的 Linux 的采集的管理分区没有问题,而且它支持多种的数据采集方式,这就是一个很好的数据集成的支持。
3)Zabbix-Web 提供丰富的 API,可以通过 API 来调用数据。
4)TiDB 本身就是良好的横向扩展能力,且易用性极高。通过横向扩展提高数据库的容量和性能,这样可以获取更多的数据和更长时间的存储。
上图是 TiZabbix 简单的架构图, Zabbix Proxy 在这里是没有用到的,但当规模更大的时候会使用它来分摊 Zabbix Server 的压力。因为在单 Zabbix Server 下,它的内存会是潜在的瓶颈,当被管理端多了后,对应 Server 的内存肯定会不断的增长,增长到一定程度后单机就无法再增大了,就需要 proxy 来分担 Server 的压力。所以,当达到更大的规模后 proxy 是需要引入的。架构图的右半部分是提供 API 的 Web ,相当于第三方的调用来消费监控到的数据。
架构图最下面一层是 TiDB,TiDB 目前来看也是存在着一定的潜在的瓶颈,可能主要是并发冲突。因为用到的是比较差的硬件,肯定是要受点限制的,具体表现在并发的性能上会下降一些,不过这个也可以通过逻辑上的方案来规避一下,就是 item(Zabbix 的一个关键数据模型)。在一些极端场景下,自动产生的 item 会比较多,如果它不断的自动生成,相当于会出现写热点,然后会产生并发冲突,进而拖垮整个数据库。所以,在更大规模下,需要优化自动生成的 item 策略。将 item 的自动生成策略打散,不要在同一时间点生成过多的 item,来缓解可能引起的并发冲突。当然,通过提升硬件的性能,也能够来弥补这个问题。
领取专属 10元无门槛券
私享最新 技术干货