本文原創做者鮑光亞,京東商城基礎平臺部軟件開發工程師,經做者贊成發表於本人博客,如需轉載需經本人贊成。web
1、引言算法
隨着監控量的迅速增加,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的修改方案將另文討論,本文不涉及。sql
2、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兩個函數實現。api
3、具體方案及實現數組
在數據庫中,history表依照數據類型不一樣分爲history、history_uint、history_str、history_text、history_log五個表,trends表則分爲trends和trends_uint兩個表。遵循着分散io的思路,能夠考慮兩種方案,第一種方案是按照類別將history和trends分散到兩個獨立的數據庫中,另一種是按照類別以及數據類型的不一樣,將每個表都獨立地存儲到單個數據庫中。下文主要按照第一種方案進行論述。緩存
4、數據一致性問題session
分離模式存在的風險之一是數據一致性問題。在集中模式時,zabbix經過互斥鎖來協調對緩存的訪問,保證緩存數據的一致性。寫數據庫時則經過transaction保證一致性。由於緩存鎖機制的存在,數據庫的分離與否並不會影響緩存的一致性,問題只能存在於數據庫內部。
若是採用按類別分離的方案,即history和trends數據分別存儲在兩個數據庫中,則須要考慮history、trends和其餘表之間的一致性。若是採用按類別+數據類型分離的方案,則同時要考慮history各個表之間的數據一致性以及trends表之間的一致性。
經過分析源碼中的transaction邏輯,history/trends表的更新操做不須要與其餘表保持一致性(在數據庫級別),在程序容許的狀況下,雙方能夠獨立寫數據庫。app
5、進一步的方案ide
遵循數據庫分離的思路,更激進的方案是將history和trends數據中的每個表都進行拆分,以itemid或者clock爲key按照必定的哈希算法,將數據分散存儲到更多的數據庫中。