zabbix运行久了以后效率会变慢的原因分析

公司zabbix 的规模500多台机器,日常操作感觉很卡,随着好奇心看了一下zabbix的实现。。发现了一些有趣的东西。。

首先是数据库特别的大,大概340g ,是我见的过比较大的。用的是mysql innodb ,里面表比较多,但是大多都比较平常,有一个特别之巨大,是history这个表,看了下,有30亿行数据。。

select table_name ,table_rows from tables  where table_schema='zabbix'  and table_name like 'history%';

+-------------------+------------+
| table_name        | table_rows |
+-------------------+------------+
| history           | 2881585282 |
| history_log       |          0 |
| history_str       |     720801 |
| history_str_sync  |          0 |
| history_sync      |          0 |
| history_text      |    5275879 |
| history_uint      |  352996499 |
| history_uint_sync |          0 |
+-------------------+------------+

这里table_rows这个并不是精确数值,是一个大概的值,每次查询得到的都不一样,而且相差个1,2亿是正常的。。要正确取得rows 的话只能count(*) ,但是运行一下的话全表遍历,估计要n久才能得出结果。

好吧,不去纠结具体多少,大概就是30亿数据这个数据量。

history的表结构如下,

       Table: history
Create Table: CREATE TABLE `history` (
  `itemid` bigint(20) unsigned NOT NULL,
  `clock` int(11) NOT NULL DEFAULT '0',
  `value` double(16,4) NOT NULL DEFAULT '0.0000',
  `ns` int(11) NOT NULL DEFAULT '0',
  KEY `history_1` (`itemid`,`clock`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

说道这里就必须提一下zabbix的架构了,是一个典型的c/s架构,server段去拿agent 端的数据,然后把数据存在数据库里,这也是为什么运行server的时候一定要给出正确的连接数据库参数的原因了。

他很简单,叫拿到的数据按照itemid 存到数据库里面去,需要的时候select 出来,通过php 的frontpage 来展现给我们。

但是这个数据增长的有点快,已500个主机的监控为例,每个host默认有108项items ,当然有些不止108,可以自定义添加的。那么多是时间获取一次呢,这个也是不定的,system.cpu.load[,avg1],网卡流量net.if.in[eth0,bytes]等都是5s 一次的,system.cpu.util[,nice,avg1] 什么的都是10s一次,还有20s,30s ,60s等。

算他20s 平均,那么一天的数据流就是

500*100*20=20w  ,这个估算有作用,有个server 参数MaxHousekeeperDelete ,当开启自动清理history数据的时候,最大清理多少项,如果这个值设的太低,低于每天生成的数据,那么清理是无效的。

我看了下公司的zabbix 记录,可以看到1年前的图。。基本没起什么用,所以这个数据量才能达到惊人的30亿行!

大家都知道,在这么大的一个数据量上进行select ,不慢才怪了。。基本上生成一幅图表需要15s样子。。插入数据需要30多秒。。系统变的越来越臃肿,用户体验直线下降。。查询效率非常之慢!

那么写到这里大概找到整个系统运行慢的终极原因了。似乎有二条路可以分两步走,第一是手动把history数据给删掉点。。第二是设置正确的MaxHousekeeperDelete 参数。但是做之前先要备份数据库。这里没有实践。因为考虑到history有不少相关的其他的表

+-----------------------------+
| history                     |
| history_log                 |
| history_str                 |
| history_str_sync            |
| history_sync                |
| history_text                |
| history_uint                |
| history_uint_sync           |

把history删了以后,其他地方 导致不统一了怎么办?

这里我的做法 是先改大MaxHousekeeperDelete,每次多删有点,保持每天都在瘦的状态,那么最终会达到我们想要的效果。

 怎么看是否有删除呢,我的做法是开启slow log ,基本上,这种操作都会被记录进slowlog 的,有记录那么肯定在删除了。而且5.1以后slow log都是可以动态开启的。不需要重启mysql。不要的时候关闭即可。非常方便。

========================================

隔了一段时间,再修改这篇文章,发现这个也是存在问题的,首先zabbix 卡不单是因为history这个表,还要一个events的表我觉得很有关系。还是,history 这个表时刻在insert数据,这么大量的删除,会和insert 争用锁? delete的时候为了保证数据完整性,应该会用锁,而我觉得这个锁会对insert有 影响。

分析slowlog

Count: 10936 Time=18.11s (198094s) Lock=0.00s (0s) Rows=1.0 (10935), zabbix[zabbix]@2hosts
SELECT e.eventid, e.value, e.clock, e.objectid as triggerid, e.acknowledged FROM events e WHERE e.object=N AND e.objectid=N AND e.value=N ORDER by e.object DESC, e.objectid DESC, e.eventid DESC LIMIT N OFFSET N

Count: 9435 Time=17.47s (164812s) Lock=0.00s (0s) Rows=1.0 (9434), zabbix[zabbix]@[192.168.0.75]
select eventid,value from events where source=N and object=N and objectid=N and value in (N,N) order by object desc,objectid desc,eventid desc limit N

可以看到zabbix 一直在从events 数据库里面查询数据,这个表数据大概在8千万样子,1亿不到,物理数据有14G,

show engine innodb status
68.23 inserts/s, 0.50 updates/s, 11.75 deletes/s, 5300219.70 reads/s

发现大量的read 操作,再看这个sql 语句,14g的数据,虽然explain中有用到索引,我觉得这个量还是非常大的,如果减小这个表的规模,查询应该会很快。

这里我觉得有两个方法,一种是比较大胆的,删了events表的全部数据,当然14G的数据你不能这么干,否则老板也会把你干掉的。网上有种不错的方法是利用ln 硬连接,先drop了,然后再慢慢对付硬盘文件。

还一种是慢慢切割行,每天分钟删一点,那么一天累计起来也不错。这个数据要测试,不能太大,影响业务。

原文地址:https://www.cnblogs.com/gqdw/p/2841221.html