本文原創(chuàng)作者鮑光亞,京東商城基礎(chǔ)平臺部軟件開發(fā)工程師,經(jīng)作者同意發(fā)表于本人博客,如需轉(zhuǎn)載需經(jīng)本人同意。
目前累計服務(wù)客戶1000多家,積累了豐富的產(chǎn)品開發(fā)及服務(wù)經(jīng)驗。以網(wǎng)站設(shè)計水平和技術(shù)實力,樹立企業(yè)形象,為客戶提供成都網(wǎng)站制作、網(wǎng)站建設(shè)、網(wǎng)站策劃、網(wǎng)頁設(shè)計、網(wǎng)絡(luò)營銷、VI設(shè)計、網(wǎng)站改版、漏洞修補等服務(wù)。創(chuàng)新互聯(lián)始終以務(wù)實、誠信為根本,不斷創(chuàng)新和提高建站品質(zhì),通過對領(lǐng)先技術(shù)的掌握、對創(chuàng)意設(shè)計的研究、對客戶形象的視覺傳遞、對應(yīng)用系統(tǒng)的結(jié)合,為客戶提供更好的一站式互聯(lián)網(wǎng)解決方案,攜手廣大客戶,共同發(fā)展進步。
一、前言
我部門對數(shù)據(jù)庫的監(jiān)控使用的是開源的Zabbix系統(tǒng),目前監(jiān)控了上萬臺主機。本文旨在通過分析Zabbix系統(tǒng)server端的數(shù)據(jù)結(jié)構(gòu)和并行計算的實現(xiàn)方法,嘗試探尋Zabbix系統(tǒng)server端的潛在擴展能力,同時希望有助于在實際應(yīng)用過程中進一步優(yōu)化運行效率和穩(wěn)定性。
Zabbix系統(tǒng)采用server-proxy-agent架構(gòu),其server端的主要功能是收集監(jiān)控數(shù)據(jù)并基于所收集的數(shù)據(jù)觸發(fā)報警動作。在實際應(yīng)用中,zabbix有可能會監(jiān)控10000臺主機(host,由hostid唯一標識),如果每臺主機設(shè)置50個監(jiān)控指標(item,由itemid唯一標識),并且每分鐘收集一次數(shù)據(jù),則一共有50萬個item,每秒鐘需要接收并處理8333項數(shù)據(jù)(value),即vps(values per second)為8333。如果有三分之一的item設(shè)置了報警觸發(fā)器(trigger,由triggerid唯一標識),則共有17萬個trigger。
在以上情境中,為了保證監(jiān)控的有效性和及時性,zabbix接收到每個value后需要立即在50萬個item中找到正確的item,并獲取該item的前一個值(previous value,last(),以便計算增量),或者計算前5分鐘內(nèi)的平均值(avg(5m)),以便根據(jù)觸發(fā)器表達式(trigger expression,由functionid唯一標識)判斷是否應(yīng)該觸發(fā)報警事件(event,由eventid唯一標識)。同時如果item返回值類型為數(shù)字型,還需要計算該item在一個小時內(nèi)的平均值(value_avg)、最大值(value_max)、最小值(value_min)。按照上面的vps數(shù)據(jù),zabbix至少需要每秒鐘搜索8333*500000次。此外,item和trigger并不是靜態(tài)數(shù)據(jù),用戶隨時可能會增加、修改、刪除、禁用(disable)、啟用(enable)某些item和trigger,zabbix需要在處理value時查詢該item和trigger最新的狀態(tài)。如何在一秒時間內(nèi)完成如此大量的操作,zabbix給出的方案是: 哈希表。
在并行計算的軟件方面,由于Zabbix系統(tǒng)監(jiān)控的各個主機之間是相對獨立的,無論在任務(wù)還是在數(shù)據(jù)方面都非常便于計算的并行化。服務(wù)器硬件方面,我們實際使用的服務(wù)器結(jié)構(gòu)是2*8處理器+三級緩存+16G*8內(nèi)存+SSD硬盤+10Gbps網(wǎng)卡(數(shù)據(jù)庫、zabbix server和web服務(wù)共用)。Zabbix的并行計算主要采用的是共享內(nèi)存模式。
二、Zabbix中的哈希表種類
Zabbix使用的哈希表是鏈式哈希表,主要有以下五類(都是在共享內(nèi)存中分配空間):
1.Valuecache
Valuecache中包含兩個哈希表vc_cache->items(itemid作為鍵值進行哈希)和vc_cache->strpool(字符串作為鍵值),用于存儲收集到的values(包括數(shù)字型和字符串型),每個item占用一個slot,每個槽位都是一個鏈表,鏈表節(jié)點存儲實際需要的信息。
Valuecache的哈希表在服務(wù)啟動時創(chuàng)建,服務(wù)退出時銷毀,初始槽數(shù)為1009(1000之后的第一個素數(shù)),隨著表中元素數(shù)量的增加,槽數(shù)也會按照一定的規(guī)則增多。Valuecache可使用的最大空間由配置文件中的ValueCacheSize參數(shù)控制,允許的范圍是128K-64G。
2.Dbcache
Dbcache中的cache->trends哈希表,用于緩存trends表(每個item的小時平均值、最大值、最小值)的數(shù)據(jù)。Zabbix server的history_syncer進程會持續(xù)接收來自agent或者proxy的數(shù)據(jù)后會將其加載到緩存中,同時更新cache->trends哈希表。該哈希表中的元素是ZBX_DC_TREND結(jié)構(gòu)體。
Cache->trends表中的數(shù)據(jù)時間超過整點時會被flush到數(shù)據(jù)庫中,例如10點之后會將9-10點之間的數(shù)據(jù)flush到數(shù)據(jù)庫中。
Cache->trends哈希表在服務(wù)啟動時創(chuàng)建,初始槽數(shù)與vc_cache->items相同,為1009(1000之后的第一個素數(shù))。Cache->trends哈希表的最大可用空間由配置文件中的TrendCacheSize參數(shù)控制,允許的范圍是128K-2G。
3.Dbconfig
Dbconfig緩存中存儲了多個與監(jiān)控有關(guān)的配置信息的哈希表,包括config->hosts、config->items、config->functions、config->triggers等等。配置信息哈希表的鍵值包括hostid、itemid、functionid、triggerid、triggerdepid、expressionid、globalmacroid、hostmacroid、hosttemplateid、interfaceid、host_inventory等,其中數(shù)量最多的往往是itemid、functionid和triggerid,會在數(shù)十萬級別(以10000個host計)。
以config->items為例,該哈希表的元素是ZBX_DC_ITEM結(jié)構(gòu)體。Config->items中的數(shù)據(jù)是從數(shù)據(jù)庫中查詢獲得的,zabbix server的configuration syncer進程會周期性地從數(shù)據(jù)庫同步數(shù)據(jù)到緩存中。
Dbconfig緩存中的其他哈希表與config->items表類似,都是從數(shù)據(jù)庫同步數(shù)據(jù),都是在服務(wù)啟動時創(chuàng)建,初始槽數(shù)都是1009,并隨著數(shù)據(jù)量的增加動態(tài)擴展。整個dbconfig緩存可用空間大小由CacheSize參數(shù)決定,取值范圍為128K-8G。
4.Strpool
此處的strpool與vc_cache->strpool是相互獨立的兩個哈希表。此Strpool緩存用于存儲配置信息相關(guān)的字符串值,它與dbconfig共同分享CacheSize的空間(strpool占15%)。Strpool存儲的字符串包括host name、item key、item delay_flex、snmp community、snmp securityname、snmp passphrase、logitem format等數(shù)據(jù)。Zabbix需要使用host name等字符串時,會首先在strpool中查找。
Strpool的哈希表初始槽數(shù)為1009。鍵值是字符串本身,哈希值是對字符串調(diào)用哈希函數(shù)的返回值。
5.其他
除了以上哈希表,還有snmpidx、vmware service等哈希表。
三、哈希表的實現(xiàn)
下面以config->items哈希表為例,說明zabbix中哈希表的實現(xiàn)方法。
1.數(shù)據(jù)結(jié)構(gòu)定義
Zabbix采用的是鏈式哈希表,哈希表中的每個slot都是一個鏈表。具體的數(shù)據(jù)結(jié)構(gòu)定義如下:
2.
槽數(shù)取值及負載因子
Zabbix的哈希過程是先調(diào)用哈希函數(shù)計算鍵值對應(yīng)的哈希值,然后用取余法確定槽位號。因此,取余計算時的除數(shù)就是槽位數(shù),該數(shù)值取素數(shù)(因為素數(shù)可以做到最大程度上均勻散列)。在config->items哈希表中,槽位數(shù)的初始值是1009,隨著數(shù)據(jù)量的增加,當(dāng)負載因子(元素數(shù)/槽數(shù))達到0.8時,會擴充槽數(shù)量(擴充為當(dāng)前數(shù)量的1.5倍以上,并取素數(shù))。因此,負載因子總是保持在0.8和0.533之間。
按照以上規(guī)則,每次擴展哈希表,其槽數(shù)如下表示。當(dāng)item數(shù)量為50萬時,槽數(shù)應(yīng)為670849。
序號 | 理論值 | 素數(shù)(槽數(shù)) | 允許的元素數(shù) |
0 | 1000 | 1009 | 806 |
1 | 1513 | 1523 | 1217 |
2 | 2284 | 2287 | 1828 |
3 | 3430 | 3433 | 2745 |
4 | 5149 | 5153 | 4121 |
5 | 7729 | 7741 | 6191 |
6 | 11611 | 11617 | 9292 |
7 | 17425 | 17431 | 13943 |
8 | 26146 | 26153 | 20921 |
9 | 39229 | 39229 | 31382 |
10 | 58843 | 58889 | 47110 |
11 | 88333 | 88337 | 70668 |
12 | 132505 | 132511 | 106007 |
13 | 198766 | 198769 | 159014 |
14 | 298153 | 298153 | 238521 |
15 | 447229 | 447233 | 357785 |
16 | 670849 | 670849 | 536678 |
17 | 1006273 | 1006279 | 805022 |
18 | 1509418 | 1509427 | 1207540 |
19 | 2264140 | 2264149 | 1811318 |
3.哈希函數(shù)
Zabbix使用的哈希函數(shù)是在fnv-1a函數(shù)(http://www.isthe.com/chongo/tech/comp/fnv/index.html)的基礎(chǔ)上稍微進行了改進。該函數(shù)采用乘積和位操作達到快速哈希的目的。具體實現(xiàn)如下:
按照以上函數(shù),模擬620000個itemid的哈希過程(槽數(shù)取1006279),哈希效率如下:
總桶數(shù) | 1006279 |
空桶數(shù)量 | 543405 |
深度大于1的桶數(shù) | 127940 |
載荷因子 | 0.616131311 |
最大桶深 | 7 |
深桶占有值桶比例 | 0.276403514 |
深桶占總桶數(shù)比例 | 0.127141677 |
空桶占總數(shù)比例 | 0.540014251 |
四、任務(wù)和數(shù)據(jù)的并行化
1.任務(wù)的并行
Zabbix系統(tǒng)的任務(wù)基本上都是基于所監(jiān)控的host和item,各個host和item之間有較強的獨立性。為了并行化,Zabbix將任務(wù)拆分為相對獨立的子任務(wù),各個子任務(wù)由一個或者多個進程來執(zhí)行。Zabbix server端的進程劃分如下表所示:
啟動 順序 | process title | 允許 進程數(shù) | 默認值 | 任務(wù) |
1 | configuration syncer | 1-1 | 1 | 從數(shù)據(jù)庫同步數(shù)據(jù)到Dbconfig緩存 |
2 | db watchdog | 1-1 | 1 | 周期性地檢查server端數(shù)據(jù)庫是否可用,如果不可用則發(fā)送報警信息 |
3 | poller #n | 0-1000 | 5 | 根據(jù)dbconfig中的數(shù)據(jù),從passive agent和snmp設(shè)備采集數(shù)據(jù),并flush到共享內(nèi)存cache->history中 |
4 | unreachable poller #n | 0-1000 | 1 | 當(dāng)設(shè)備處于unreachable狀態(tài)時,周期性地polling設(shè)備 |
5 | trapper #n | 0-1000 | 5 | 從socket接收并處理active agent和active proxy發(fā)來的數(shù)據(jù)(json格式,zabbix通訊協(xié)議),并flush到共享內(nèi)存cache->history中 |
6 | icmp pinger #n | 0-1000 | 1 | 根據(jù)dbconfig中的數(shù)據(jù),批量采集icmpping相關(guān)的item數(shù)據(jù),并flush到共享內(nèi)存cache->history中 |
7 | alerter | 1-1 | 1 | 發(fā)送各種報警通知 |
8 | housekeeper | 1-1 | 1 | 周期性地刪除過期的歷史數(shù)據(jù) |
9 | timer #n | 1-1000 | 1 | 計算與時間相關(guān)的trigger表達式等 |
10 | node watcher | 1-1 | 1 | 處理與node之間的交互 |
11 | http poller #n | 0-1000 | 1 | 收集web監(jiān)控相關(guān)的數(shù)據(jù),并flush到共享內(nèi)存cache->history中 |
12 | discoverer #n | 0-250 | 1 | 按照指定規(guī)則掃描網(wǎng)絡(luò),自動發(fā)現(xiàn)host、interface等 |
13 | history syncer #n | 1-100 | 4 | 將共享內(nèi)存cache->history中的數(shù)據(jù)批量更新到數(shù)據(jù)庫中,并flush到共享內(nèi)存vc_cache、cache->trends、config->items等中 |
14 | escalator | 1-1 | 1 | 當(dāng)報警操作需要分步連續(xù)執(zhí)行時,控制各步驟之間的escalations |
15 | ipmi poller #n | 0-1000 | 0 | 與poller進程類似,處理ipmi items |
16 | java poller #n | 0-1000 | 0 | 與poller進程類似,處理JMX items |
17 | snmp trapper #n | 0-1 | 0 | 與trapper進程類似,處理snmp items |
18 | proxy poller #n | 0-250 | 1 | 與passive proxy交互,以設(shè)定的頻率獲取所需要的json格式數(shù)據(jù)并將數(shù)據(jù)flush到共享內(nèi)存cache->history中 |
19 | self-monitoring | 1-1 | 1 | 處理與zabbix自身運行狀態(tài)相關(guān)的item信息,訪問共享內(nèi)存中的collector變量 |
20 | vmware collector #n | 0-250 | 0 | 采集vmware虛擬機相關(guān)的數(shù)據(jù),并flush到共享內(nèi)存中 |
所有進程中比較關(guān)鍵的進程有兩類:poller/trapper類進程,用于采集數(shù)據(jù)并加載到共享內(nèi)存中;history syncer進程,用于更新數(shù)據(jù)庫及觸發(fā)events和報警。邏輯上這兩類任務(wù)是先后執(zhí)行的,首先要采集到數(shù)據(jù)然后才能觸發(fā)報警。而每類任務(wù)的各個進程之間是獨立的,多個poller/trapper進程可以同時執(zhí)行,多個history syncer進程也可以同時執(zhí)行。
2.Socket multiplexing對多進程的支持
Zabbix監(jiān)控系統(tǒng)的數(shù)據(jù)最終來源是被監(jiān)控的主機,數(shù)據(jù)通過socket監(jiān)聽端口接收(監(jiān)聽端口允許的最大連接數(shù)由操作系統(tǒng)決定)。Zabbix通過fork多個子進程來共享同一個socket,在讀socket時則通過基于select()函數(shù)的multiplexing實現(xiàn)多進程同時讀取。
按照10000個host,每分鐘采集一次數(shù)據(jù)(假設(shè)每個host上的所有item同時采集數(shù)據(jù),事實可能并非如此),平均每秒鐘有167個連接請求。
3.MySQL數(shù)據(jù)庫的讀寫
Zabbix支持多種數(shù)據(jù)庫,包括Mysql、Oracle、IBM DB2、PostgreSQL、SQLite,我們實際使用的是Mysql。為了保證數(shù)據(jù)的持續(xù)性,zabbix在觸發(fā)報警前會先將數(shù)據(jù)插入到數(shù)據(jù)庫中。History syncer進程數(shù)允許最多100個,每個進程可以與數(shù)據(jù)庫建立獨立的連接,進行數(shù)據(jù)更新。
五、共享內(nèi)存與進程間通信
1.共享內(nèi)存的創(chuàng)建
共享內(nèi)存是進程間通信中最簡單并且速度最快的一種機制。Zabbix的進程間通信主要采用共享內(nèi)存的方式,主進程在fork出所有子進程之前調(diào)用shmget創(chuàng)建共享內(nèi)存,并attach到地址空間中。
Zabbix調(diào)用shmget創(chuàng)建的共享內(nèi)存segment共有8個,為config_mem、trend_mem、history_mem、history_text_mem、vc_mem、vmware_mem、strpool.mem_info、collector,分別用于dbconfig緩存、cache->trends數(shù)據(jù)、cache->history(數(shù)字和string)、vc_cache、vmware數(shù)據(jù)、strpool、監(jiān)控zabbix自身狀態(tài)的collector結(jié)構(gòu)。如果實際應(yīng)用中沒有啟用vmware,則只有7個共享內(nèi)存被attach到各子進程的地址空間中,如下圖所示,這些共享內(nèi)存段將一直保持attach狀態(tài),直到服務(wù)停止。
從上圖可以看出,每個共享內(nèi)存段都attach到了553個進程中,即zabbix server的每個進程都可以訪問所有七個共享內(nèi)存。
2.信號量機制
Zabbix使用二進制信號量機制來協(xié)調(diào)多個進程對共享內(nèi)存的同時訪問,避免資源爭用。系統(tǒng)在創(chuàng)建共享內(nèi)存之前會調(diào)用semget函數(shù),創(chuàng)建一個包含13個信號量的信號量集,并將每個信號量的值初始化為1。各個信號量用于對不同的共享內(nèi)存進行訪問控制,具體如下所示:
# define ZBX_MUTEX_LOG 0
# define ZBX_MUTEX_NODE_SYNC 1
# define ZBX_MUTEX_CACHE 2
# define ZBX_MUTEX_TRENDS 3
# define ZBX_MUTEX_CACHE_IDS 4
# define ZBX_MUTEX_CONFIG 5
# define ZBX_MUTEX_SELFMON 6
# define ZBX_MUTEX_CPUSTATS 7
# define ZBX_MUTEX_DISKSTATS 8
# define ZBX_MUTEX_ITSERVICES 9
# define ZBX_MUTEX_VALUECACHE 10
# define ZBX_MUTEX_VMWARE 11
# define ZBX_MUTEX_SQLITE3 12
當(dāng)進程需要對某個共享內(nèi)存進行寫操作時,會首先lock(調(diào)用semop函數(shù)將信號量-1),執(zhí)行寫操作完畢后將再unlock(將信號量+1)。如果執(zhí)行l(wèi)ock時信號量為0,則等待,直到信號量非0。Zabbix的信號量在釋放共享內(nèi)存時銷毀。
六、聲明與結(jié)論
本文創(chuàng)作基于zabbix 2.2.10版本的源碼分析,歡迎批評指正。
Zabbix所采用的哈希函數(shù)效果比較理想。但在實際應(yīng)用中,仍然可以根據(jù)需要和資源情況對負載因子、槽數(shù)擴展速度、槽數(shù)初值、哈希函數(shù)定義進行改進。
在Zabbix的并行計算方面,由于監(jiān)控系統(tǒng)的特點,數(shù)據(jù)和任務(wù)之間有較強的獨立性,非常便于并行化。Zabbix通過多進程+共享內(nèi)存實現(xiàn)并行,資源爭用問題通過信號量進行控制。從實際應(yīng)用效果來看,并行的性能非常理想。
本文名稱:Zabbix數(shù)據(jù)結(jié)構(gòu)及并行計算實現(xiàn)
本文路徑:http://m.rwnh.cn/article30/gdicpo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、微信公眾號、網(wǎng)站內(nèi)鏈、虛擬主機、品牌網(wǎng)站建設(shè)、軟件開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)