公司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了,然后再慢慢對付硬盤文件。
還一種是慢慢切割行,每天分鍾刪一點,那么一天累計起來也不錯。這個數據要測試,不能太大,影響業務。