本文原创作者鲍光亚,京东商城基础平台部软件开发工程师,经作者同意发表于本人博客,如需转载需经本人同意。
创新互联长期为上千多家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为桥西企业提供专业的成都网站建设、网站制作,桥西网站改版等技术服务。拥有10年丰富建站经验和众多成功案例,为您定制开发。
一、引言
随着监控量的迅速增长,zabbix管理员有一天会发现硬盘iops达到了数万,接近硬盘io的极限,无力支持处理更多监控数据。本文提出一种横向扩展方案,以尽量小的改动,增加zabbix系统的数据io能力。
考虑到zabbix的数据库io主要在于history表和trends表,这一方案是在不增加zabbix server数量的情况下,将history表和trends表的io分散到其他主机上。此方案的优点是保持单个zabbix server,不需要考虑多server之间的协同一致。这一数据库分离模式还可以兼容原有的集中模式。但是,由于io分散到多个主机上,当需要读写数据时,不得不访问多个数据库实例。同时,代码中涉及数据库读写的部分,包括zabbix server和web api,都需要重写,好在大部分可以参考已有的代码。
本方案设计基于zabbix 3.0.10版本。本文只论及对zabbix server的改造方案,对web api的修改方案将另文讨论,本文不涉及。
二、zabbix数据读写机制
由于configuration数据的io远小于history和trends数据io,本方案没有涉及对configuration数据的改动。
cache和vc_cache是zabbix源码中的两个变量名称,前者用于存储来自agent/proxy的原始数据,后者存储的则是从数据库中加载的数据(当数据已过期时,新数据则会直接从前者复制到后者之中),用于进行trigger计算等。
1.history和trends数据的写入
poller和trapper两类进程(包括pinger)负责从agent和proxy接收history数据,然后flush到cache中,同时更新cache中的trends数据。对cache的更新主要通过函数 process_hist_data实现。
dbsyncer进程则负责将cache中的数据写入到数据库中的history表和trends表中。由于dbsyncer存在多个进程,进程之间通过锁进行协调,避免冲突。cache数据入库主要通过DCsync_history和DCsync_trends两个函数实现。
三、具体方案及实现
在数据库中,history表依照数据类型不同分为history、history_uint、history_str、history_text、history_log五个表,trends表则分为trends和trends_uint两个表。遵循着分散io的思路,可以考虑两种方案,第一种方案是按照类别将history和trends分散到两个独立的数据库中,另外一种是按照类别以及数据类型的不同,将每一个表都独立地存储到单个数据库中。下文主要按照第一种方案进行论述。
四、数据一致性问题
分离模式存在的风险之一是数据一致性问题。在集中模式时,zabbix通过互斥锁来协调对缓存的访问,保证缓存数据的一致性。写数据库时则通过transaction保证一致性。因为缓存锁机制的存在,数据库的分离与否并不会影响缓存的一致性,问题只能存在于数据库内部。
如果采用按类别分离的方案,即history和trends数据分别存储在两个数据库中,则需要考虑history、trends和其他表之间的一致性。如果采用按类别+数据类型分离的方案,则同时要考虑history各个表之间的数据一致性以及trends表之间的一致性。
通过分析源码中的transaction逻辑,history/trends表的更新操作不需要与其他表保持一致性(在数据库级别),在程序允许的情况下,双方可以独立写数据库。
五、进一步的方案
遵循数据库分离的思路,更激进的方案是将history和trends数据中的每一个表都进行拆分,以itemid或者clock为key按照一定的哈希算法,将数据分散存储到更多的数据库中。