[From] https://mp.weixin.qq.com/s?__biz=MjM5OTcxMzE0MQ==&mid=400225178&idx=1&sn=c98609a9b66f84549e41cd421b4df74d前端
講師:秦曉輝java
我的介紹:mysql
一個來自運維部的研發,長期從事自動化運維平臺的構建,參與百度自動化部署系統Archer、小米的監控系統open-falcon,偶爾作作PaaS,國內首個開源PaaS平臺(噱頭,哈)DINP的做者。代碼熟手,工程師,not程序員。nginx
分享的主題:《open-falcon編寫的整個腦洞歷程》git
1. zabbix時代的痛程序員
2. open-falcon的目標制定github
3. 架構設計的習慣性redis
4. 試用以後算法
5. 一些折中sql
6. 將來改進
你們好,我是秦曉輝,來自小米運維部,畢業這幾年一直作運維平臺開發,對部署系統、監控系統相對熟悉一些,此次主要是給你們介紹一下open-falcon開發過程當中的一些思考,力求以最直白的表述重走一下開發過程,若是大家公司也要寫一套監控,或許會有一點幫助,羣裏大牛衆多,獻醜了。
原本想提綱挈領的講一講,頂多40分鐘搞定,寫稿件的時候越寫越多,限於我的表達能力的問題,而又想盡可能講清楚,老是囉囉嗦嗦的,最後發現時間關係仍是無法所有講到,你們見諒。
咱們先來說講zabbix時代的痛,小米初期是使用zabbix來作監控的。zabbix你們應該是知道的,大名鼎鼎,成熟穩健,不少公司都在用。小米也不例外,初期作運維開發的人比較少,機器量、業務量也少,zabbix能夠很好的知足需求。
咱們要開發一個項目、產品,確定是要解決一些問題,zabbix是很好,可是機器量、業務量上來以後,zabbix就有些力不從心了。那咱們先來講一下zabbix存在的問題。
小米在大規模使用zabbix的年代,我當時在研究CloudFoundry,直到衆位sre受不了zabbix了,但願開發一個新的監控系統,咱們開始組建監控團隊,開始open-falcon的設計、編碼。因此對zabbix的問題可能理解不深刻,拋磚引玉……
1. 性能瓶頸。zabbix是使用MySQL來存放監控歷史數據的。一臺機器假設有100個監控項,2000臺機器,就是20w監控項,監控系統的數據採集沒有高峯低谷,是持續性的,週期性的,通常是一分鐘採集一次。
機器量愈來愈大,數據量就愈來愈大,MySQL的寫入逐漸成爲瓶頸,業界有一些proxy的方案,咱們有試用,也嘗試把採集週期調長,好比3分鐘採集一次,或者5分鐘採集一次,可是都治標不治本。
zabbix有些數據採集是經過pull的方式,也就是server端主動探測的方式,當目標機器量大了以後,這些pull任務也常常出現積壓。維護zabbix的同窗焦頭爛額。
2. 管理成本高昂。爲了讓zabbix壓力小一點,咱們整個公司搭建了多套zabbix,好比多看本身用一套、電商本身用一套、米聊本身用一套,若是要作一些公司級別的統計,須要去多個數據源拉取數據。每套zabbix都得有運維人員跟進,人力成本上升。
3. zabbix有些易用性問題。好比zabbix的模板是不支持繼承的,機器分組也是扁平化的,監控策略不容易複用。zabbix要採集哪些數據,是須要在server端作手工配置的,咱們認爲這是一個本該省去的操做。
4. 監控系統沒有統一化。機器相關的數據採集、監控咱們使用zabbix來作,可是咱們還須要業務的監控,好比某個thrift rpc接口,每分鐘調用的cps,latency,咱們但願作監控,某些url的5xx、4xx咱們也但願作監控,某個開源軟件,好比redis、openstack、mysql的一些狀態統計數據,咱們也但願作監控。
咱們稱後面這些數據爲performance數據,我同事來煒曾經專門寫了一個系統叫perfcounter,用來存放這些performance數據。perfcounter使用rrdtool來繪圖,rrd是一個環形數據庫,不少監控系統的數據都是使用rrd來存儲的,這個就不展開講了,你們能夠google一下rrd相關知識。
perfcounter的繪圖作得不錯,可是報警功能比較薄弱。zabbix自己有多套,再加上perfcounter,入口比較多,要看監控數據,可能要去不一樣的地方分別查看,比較麻煩。迫切須要一個大一統的解決方案。
不能否認,zabbix是個很優秀的方案,初期zabbix幫咱們解決了很大的問題,不過如上所述,咱們在使用過程當中也遇到了一些問題,剛開始的時候提到過,zabbix時代我還在作PaaS,因此上面的說法主要是在作open-falcon設計的時候從各位sre瞭解到的。
下面咱們來講說open-falcon的目標制定。咱們已經肯定要作一個新的監控解決方案了。因而開始討論,這貨應該作成什麼樣子。每一個人可能都會有一些思考,可是每一個point基本都比較散亂,我初入監控這個業務,主要是推進你們的討論,而後整理方案,再討論,再整理,最終出一個產品需求文檔和概要設計。
有人說,咱們應該既能夠處理機器監控,也能夠處理業務監控,還能夠處理各類開源軟件的監控。
沒錯,就是要這種大一統,並且不一樣的系統有不一樣的採集方式,有不一樣的監控指標,DBA對MySQL熟悉,知道應該採集哪些指標,雲存儲團隊對HBase熟悉,知道應該採集哪些指標,可是我做爲監控系統的開發人員,我對MySQL不熟,對HBase不熟,因此咱們沒法提供其對應的採集腳本。
下面重點!
因此咱們要制定規範,制定推送接口,你們本身去採集本身的系統,完事按照咱們的規範,把數據組織成監控系統須要的數據格式,發送給監控系統的接口。這樣你們就能夠共建監控數據,把各類須要監控的軟件、平臺都歸入進來。
固然了,對於操做系統的一些指標,好比cpu、內存、IO、網卡、磁盤、負載等等,這個仍是須要咱們監控系統開發人員去提供採集機制的。
因而,咱們仿照zabbix_agentd,編寫了falcon-agent。
這一部分主要是講監控系統的數據採集機制
這裏有哪些思考的點呢?首先,咱們不但願用戶在server端配置哪一個機器應該採集哪一個指標,這樣作麻煩且不必。咱們儘可能把agent作得能夠自發現,好比某機器有12塊盤,agent應該能夠自動探測到,而後採集各塊盤的指標push給server;好比某個機器有2塊網卡,agent也應該自動探測到,把各塊網卡的流量、丟包率等信息採集push給server。
就是說,咱們但願在裝機的時候就把agent安裝好,agent就能夠自動去採集相關數據了,省去了服務端的配置。
順着這個思路繼續延伸一下哈,天不遂人願,咱們但願服務端不作任何配置,agent就能夠自動去採集,這是咱們的設計哲學,可是有的時候仍是要打破一下,好比端口存活監控、進程數監控。
咱們拿端口存活監控來舉例,按照咱們自動去採集數據的哲學,agent應該如何處理端口存活性呢?你們稍微思考一下。
剛開始咱們的想法是這樣的:咱們能夠把當前機器上監聽的全部tcp端口收集到,彙報給server,好比某機器監聽了22、80兩個端口,ss -tln,獲取之。這樣的確是能夠收集到數據。可是我如今要作80端口的存活性監控,server端應該怎麼作呢?
想一想cpu.idle,咱們一般會在server端作配置,說某個機器的cpu.idle,連續3次<5%,就報警,最多報3次。這個策略要想正常工做,cpu.idle的數據就應該源源不斷的上來。每一個週期都不能少。
可是端口監控,ss -tln,能夠獲取當前有哪些tcp端口在監聽,假設如今nginx進程掛了,80端口再也不監聽,ss -tln就只能獲取到22端口,獲取不到80端口了,因而彙報給server端的數據就少了80端口的數據。
相似cpu.idle的監控方式是須要數據源源不斷上來的,因而,端口監控在這種模式下沒法完成。怎麼辦?
咱們能夠寫一個nodata的組件,來判斷數據多長時間沒上來就報警。可是nodata組件實現起來還有點小麻煩,並且還存在另外兩個問題,一個是策略配置方式與cpu.idle等數據的策略配置方式不同,好比cpu.idle是all(#3)<5報警,端口存活須要配置成相似:nodata(300),方式不一樣用戶的使用成本會上升;再一點是有些機器可能監聽了N多個端口,可是真正須要監控的端口,只有少許幾個,自發現端口形成資源浪費。
all(#3) 表示連續3次都
nodata(300) 表示300s沒數據上來
換個方式……
端口再也不作成自發現的。用戶要想對端口作監控,最後確定是要配置策略的。咱們從用戶配置的策略中找出全部須要監控的端口,經過hbs模塊下發給agent,這樣agent就能夠只對特定端口作監控了。好比剛纔的例子,某主機須要監控22和80兩個端口,用戶必然在服務端配置策略,咱們從策略中分析出22和80,而後下發給對應的agent,agent就能夠只監控這倆端口了,端口活着,彙報個1給服務端,端口死了,彙報個0給服務端,好比:net.port.listen/port=22 value=1,net.port.li1,net.port.li1,net.port.listen/port=80 value=0
下發這個動做是經過hbs這個模塊來完成的,即heartbeat server。agent每分鐘去調用hbs,詢問本身應該監聽哪些端口、哪些進程、要執行哪些插件。經過這種機制來下發一些狀態信息。
OK,數據採集這部分,就是這麼多內容:
1. server端制定接口規範,以此接入各類監控數據
2. agent自發現採集各類Linux性能指標,無需server端作配置
3. 進程、端口監控等沒法作到自發現的,又不想引入nodata組件,想讓策略配置統一化,就須要hbs來下發信息。
繼續下個點以前,這裏再補充兩點不過重要的。
1. agent要採用什麼語言來開發?
開發open-falcon這個系統以前,其實我最熟悉的語言是java。可是agent要run在全部目標機器上的,用本身最熟悉的java來開發麼?要run agent,每一個機器上都要先啓動一個java虛擬機,這有點扯……
咱們但願找一個資源佔用儘可能少的語言,C、C++或許是個不錯的選擇,可是C、C++我並不熟悉,聽說寫很差還容易內存泄露,呵呵。C/C++相對更底層,對於不一樣的操做系統可能要寫不少分支,簡單看過zabbix_agentd的源碼,各類操做系統的分支處理,很麻煩。固然了,zabbix但願兼容各類操做系統,因此寫的分支比較多,咱們公司的操做系統清一色centos,不會有這麼多分支判斷。
咱們但願找一個更工程化的語言,不容易出錯的語言,畢竟要在全部的機器上部署,今天這個core了明天那個core了也讓人受不了。
go語言看着還不錯哦。首先,go是靜態編譯的,編譯完了一個二進制,扔到相同平臺的機器上能夠直接跑,不須要安裝亂七八糟的lib庫,這點特別吸引我,特別是我在上家公司作過至關長一段時間的自動化部署,這種部署友好的靜態編譯發佈,我喜歡。
go的進程不須要java那種虛擬機,資源佔用比較少;go的併發支持是語言層面的,server端須要併發的組件用着合適;go的資源回收是defer關鍵字,也不是傳統的try...catch...finally,乾淨且不容易出錯;go的function能夠有多個返回值,錯誤處理一般是一個額外的error類型的返回值,無需拋異常,由於是返回值,不刻意忽略的話就確定會記得處理,不然編譯都過不了;go與github結合,生態創建的比較快;go的模板看起來怪怪的,還好我不須要用……
2. agent怎麼擴展?
咱們能夠在agent中預置一些採集項,可是咱們不是神,沒法覆蓋全部的需求。有些用戶須要擴展agent的功能,採集更多的指標。咱們須要提供這種機制。這就是插件機制的設計初衷。
zabbix是有一個目錄,你們只要把採集腳本放到這個目錄,zabbix就去執行。這樣作天然是能夠解決問題,可是有些問題實際上是扔給了使用者,好比腳本的分發管理問題。
那咱們來思考,要採集數據發送給server端,應該要作哪些事情呢?
a) 寫一個採集數據的腳本
b) 把腳本分發到須要採集數據的機器上
c) 寫一個cron每隔一段時間去跑這個腳本
d) 收集腳本的輸出,調用server的接口去push數據
e) 根據需求相應的對腳本作上線、下線、升級
插件機制是如何解決這幾個過程的呢?首先,腳本確定仍是要用戶本身寫,可是咱們提供一個腳本的管理,採集腳本是代碼,代碼就須要版本管理,咱們內部有個gitlab,要求用戶把插件提交到咱們指定的git repo。而後agent每隔一段時間去git pull這個git repo,採集腳本就完成了分發。
而後咱們在server端提供一個配置,哪些機器應該執行哪些插件,經過hbs把這個信息分發給agent,agent就能夠去執行了,腳本按照一個什麼週期去跑呢?這個信息寫在腳本的名稱裏,好比60_ntpoffset.sh,60表示60s執行一次,agent經過對腳本文件名的分析,能夠得知執行週期。
執行週期也能夠在server端配置,均可以,咱們是放到文件名裏了
腳本執行完了,把輸出打印到stdout,agent截獲以後push給server。插件的升級、回滾,就是經過git repo和server端的配置來完成。
OK,數據採集就說這麼多,真的是又臭又長,哈。咱們回到系統設計階段,看還有哪些點值得分享一下。
1. tag的設計。這個要好好跟大夥說說。這個設計靈感來自opentsdb,咱們說監控數據有不少,若是對每條監控項都配置報警,是一個很繁重的工做量。那咱們可否經過某個手段來對採集項作個聚合,一條配置能夠搞定多個監控項?
舉個例子,好比某臺機器有多個分區:
/
/home
/home/work/data1
/home/work/data2
/home/work/data…
/home/work/data12
咱們想配置任何一個分區的磁盤剩餘量小於5%就報警,怎麼辦?上例中,假設咱們有12塊盤,加上/home分區和/分區,就有14個採集項,寫14條策略規則?OMG……
這個時候tag機制就派上用場了,採集到的數據在彙報的時候,每條數據組織成這個樣子:
{
"endpoint": "qd-sadev-falcon-graph01.hd",
"metric": "df.bytes.free.percent",
"tags": "fstype=ext4,mount=/home",
"value": 10.2,
"timestamp": 1427204756,
"step": 60,
"counterType": "GAUGE"
}
上面表示qd-sadev-falcon-graph01.hd這個機器的/home分區的磁盤剩餘百分比(df.bytes.free.percent)
再舉個例子
{
"endpoint": "qd-sadev-falcon-graph01.hd",
"metric": "df.bytes.free.percent",
"tags": "fstype=ext4,mount=/home/work/data1",
"value": 10.2,
"timestamp": 1427204756,
"step": 60,
"counterType": "GAUGE"
}
metric(監控項名稱)是相同的,只是tag不一樣,不一樣的tag表示不一樣的掛載點。這樣一來,咱們就能夠這麼配置策略:說,對於某一批機器而言,df.bytes.free.percent這個採集項,只要value<5就報警。咱們沒有配置tag,那麼這14個掛載點的數據都與這個策略關聯,一個策略配置,搞定了14條數據。還有好比網卡也能夠用相似的處理方式。
上面的例子還沒法徹底體現出tag的威力。咱們再舉個例子,說一個業務監控的例子。小米的好多服務都是java寫的,有個團隊依據open-falcon提供的接口規範,寫了一個通用jar包,全部thrift中間層服務,只要引入這個jar包,就能夠自動採集全部rpc接口的調用延遲,因而,產生了N多這樣的數據:
{
"endpoint": "qd-sadev-falcon-judge01.hd",
"metric": "latency",
"tags": "department=sadev,project=falcon,module=judge,method=com.mi.falcon.judge.rpc.send",
"value": 10.2,
"timestamp": 1427204756,
"step": 60,
"counterType": "GAUGE"
}
插一句:業務代碼中嵌入監控採集邏輯,目前咱們的實踐來看,真的很好用,嘿
若是咱們這麼配置:latency/department=sadev all(#2) > 20就報警。就意味着對sadev這個部門的全部rpc接口的latency都作了策略配置。覆蓋了N條監控數據。怎麼樣?有那麼點意思吧?
說白了,tag就是一種聚合手段,能夠用更少的配置覆蓋更多的監控項。
OK,tag的設計就講這麼多。下面咱們說說模板繼承。zabbix的host有一個扁平的group來管理,模板是沒法繼承的,這個讓咱們的管理很是不方便。舉個例子。
sadev這個部門的全部機器能夠放到一個group,配置load.1min大於20報警,sadev這個部門下有不少項目,好比falcon這個項目,falcon這個項目總體使用機器資源比較狠,因而配置的load.1min大於30報警,falcon這個項目下有不少模塊,好比graph模塊,graph的機器負載更重,正常的load.1min都是35,咱們但願load.1min大於40報警。因而問題來了
qd-sadev-falcon-graph01.hd這個機器是graph的一臺機器,它應該處於graph這個組,天然也應該處於falcon這個組和sadev這個組,因而,這個機器與三個模板都有綁定關係,load.1min>20的時候報一次警,>30 >40的時候都會報警,這顯然不是咱們須要的。
模板繼承能夠解決這個問題,graph.template繼承自falcon.template,falcon.template又繼承自sadev.template,sadev.template中配置各類經常使用監控項,好比cpu.idle < 5報警,df.bytes.free.percent < 5報警,load.1min < 20報警,falcon.template和graph.template中只是load.1min比較特殊,那就只須要對load.1min配置特定的閾值便可。如此一來,graph的機器只有在load.1min>40的時候報警,>20的時候>30的時候都不會報警,你們理解一下。
模板的思考就講解到這裏。下面說說這個機器分組的問題,open-falcon與zabbix同樣,都是使用扁平的分組結構。這種狀況有個問題,就是機器的維護不方便,好比上面的例子,咱們graph機器要擴容,須要把新擴容的機器加入graph這個組,同時也要加入falcon這個組,加入sadev這個組,比較麻煩。
因此小米內部的實踐方式是與內部的機器管理系統相結合,那是一個樹狀的結構,機器加入graph中,也就自動加入了falcon中,自動加入了sadev中。你們若是要在公司內部引入open-falcon,最好也要作個二次開發,與本身公司的CMDB、服務樹、機器管理之類的系統結合一下。
那這裏有一個點,好多公司把機器管理、服務樹、CMDB這種管理機器的系統作成樹狀結構,緣由何在?部署系統有這個需求麼?部署系統的最小部署單位一般是模塊,一個模塊所在的機器徹底能夠放到一個扁平的group中。樹狀結構不是部署系統的需求,而是監控系統的需求,監控系統一般在一個大節點上綁定一些經常使用的策略配置,而後在小節點上綁定一些特殊的策略配置,相互之間有個繼承覆蓋關係。好多人不理解這個樹狀結構的設計初衷,個人理解就是這個樣子的,不必定對哈,我的觀點而已。
咱們繼續往下講:架構設計的習慣性
這個階段有哪些腦洞歷程呢?首先,監控系統的數據量估計是不小,你看一個zabbix都扛不住對吧,哈哈……並且沒有高峯低谷,週期性的,每時每刻都有大量數據上來。那第一反應是什麼?
沒錯,上集羣!一臺機器不管如何都是搞不定的,那就必需要搞多個機器協同工做。
監控系統的本質,在我看來就是採集數據並作處理的一個過程。處理方式最重要的有兩種,一個是報警,一個是存儲歷史數據。這兩個處理邏輯差別比較大,報警要求速度很快,儘可能在內存裏完成;存儲歷史數據主要是寫磁盤,讀少寫多。
那最直觀的思路就是把報警作成一個組件,把數據存儲作成另外一個組件。先說存儲,以前說過,咱們內部有個perfcounter系統來存放performance數據,這個系統是用rrd來存放的數據。架構設計的習慣性,讓咱們再次選擇使用rrd來作存儲,畢竟rrd是不少監控系統的存儲介質,隨大流,問題不大。
rrd是本地文件,一臺機器的磁盤容量或許能夠搞定監控系統的全部數據,可是IO確定不夠,perfcounter當時用了5臺機器,所有都是ssd作raid10,IO仍是比較高。因此,要搞多臺機器來存放rrd文件,每臺機器只處理一部分,壓力就小了。
因而,咱們習慣性的使用perfcounter採用的一致性哈希算法,來對數據作分片。數據分片一般有兩種方式,一個是使用算法來計算,一個是在中心端記錄一個對應關係。監控系統的量會比較大,若是要使用對應關係,還得維護一個存儲,當時我我的實際上是主張使用一個存儲來存放對應關係的,可是團隊其餘成員都以爲略麻煩,就放棄了,直接使用一致性哈希來計算對應關係,架構上顯得簡單很多。
你們應該知道,使用算法來計算對應規則,會有一個比較麻煩的問題,就是擴容,一旦擴容,一些原本打到老機器的數據就會打到新機器上,雖然一致性哈希的算法會使遷移的量比較少,可是仍然不可避免會有數據遷移。這個問題怎麼辦呢?
分享一個觀點:遇到一個比較棘手的技術問題,若是能在業務層面作規避,將是最省事的。因而咱們就想業務上可否接受數據遷移時候的丟失呢?說實話,不太容易接受,能不丟,儘可能仍是不要丟。
因而咱們退一步,擴容的時候,咱們不是立馬遷移到新機器列表,而是先作一段時間的migrating,好比作一個月。這樣一來,擴容以後,對於每一個監控項仍是會有至少一個月的數據,這樣用戶是能夠接受的。
說完了存儲,咱們再來講說報警。報警數據要求的歷史點數比較少,好比咱們一般會配置說某個機器的cpu.idle連續三次達到閾值就報警,這裏的「連續三次」就意味着,只要有最近三個點就能夠搞定用戶這個策略。數據量少,可是訪問頻繁,由於每一個數據上來,都有可能找到其關聯的策略,都須要拉取其歷史點作判斷,這樣的場景,沒啥說的,用內存吧。
咱們把用來處理報警的這個模塊稱爲judge,judge會有不少實例,當時想,某個實例掛了或者重啓都不該該影響正常的報警,爲了可以水平擴展,儘可能作得無狀態,那歷史數據就不能存在judge的內存裏了。redis吧,有名的內存nosql。因而咱們就一次性上線了一堆judge實例,前面架設lvs作負載均衡,數據使用redis存儲,走起。
稍總結一下,對於server的數據處理,這個屬於產品實現細節了,咱們由於團隊人少,剛開始只有倆人,後來三個,因此力求簡單,粗暴的解決問題。數據經過一致性哈希對rrd作一個分片,確實能夠大幅縮減開發時間,不過也存在一些問題,你們發現問題在哪裏了麼?
下面咱們先說試用以後立馬發現的問題。
當時初版上線,用了7臺機器56個redis實例,給judge存放少許歷史數據,發現每一個redis的qps都是4K、5K的樣子,初版只是部署了少許agent(具體的量記不清了),結果qps就這麼大,當時agent比較少,redis的壓力讓咱們不能接受。
怎麼辦?你們有思路麼?
外部內存的速度若是跟不上,那最直觀的想法就是使用進程自身的內存,這裏也就是judge組件的內存。那若是用了judge的內存,judge就有狀態了,就沒法水平擴展了呢。
仔細想一想其實問題不大,judge使用內存的話,仍然須要使用算法作分片,既然繪圖組件用了一致性哈希,那能夠複用一下。同一個監控指標的數據,當前這分鐘上來的數據打到某個judge,下一分鐘上來的數據,一樣應該打到這個judge,一致性哈希能夠作到,沒問題。
每一個judge實例只處理一部分數據,好比50w,放到內存裏量也不大,只是Go的GC不知道好很差用,若是Go的GC很差用,咱們就在單機多搞一些judge實例,作進程級隔離,先想好退路,呵呵。
judge是數據驅動型的。就是說,數據來到我這個實例,我就去處理,數據沒來,我就不處理,judge前面有個組件叫transfer來作轉發,作一致性哈希計算,能夠保證數據分發規則,看起來都沒啥問題。最惹人煩的是什麼呢?是judge重啓,你們能夠想一想judge重啓會帶來哪些問題
judge一旦重啓,就丟掉了歷史數據,好比用戶配置說某個機器的cpu.idle連續3次達到閾值就報警。前兩次都達到閾值了,而後,而後judge重啓,這倆點就丟了。judge重啓完成,又上來一個達到閾值的新點,已經知足連續3次達到閾值了,可是,卻沒法報警。若是後面繼續有兩個點達到閾值那還好,仍是會報警,若是後面的點都正常了,那此次本該有的報警就永遠都不會報了。
這個問題業務上能夠接受麼?好吧,咱們又來問業務了。首先,judge重啓的概率比較小,只有升級的時候纔會重啓,代碼寫得注意一些,理論上是不會掛的;再一點,機器一旦出了問題,若是sre不介入處理,一般採集到的點都是持續性達到閾值,因此老是會報出來的,不然基本就能夠不用關心。
這麼看來,這個改造是能夠進行的。因而,代碼開始重構,上線以後效果大大好轉,處理能力是原來的8倍左右。
原本想單開一節來講說一些折中考慮,發現折中都穿插在前面講完了,那咱們就再也不單獨講系統的折中處理了。
時間已經比較久了,其餘一些小的點咱們就先不講了,最後咱們說說系統的問題以及將來的改造。
最大的問題是什麼?相信你們已經想到了,就是每一個graph(繪圖組件)實例都是單點。若是某一臺繪圖機器磁盤壞,那這部分數據就丟了。怎麼解決呢?
最簡單的,硬件解決,咱們每一個機器都是ssd作raid10,穩定性比較高。而後,咱們作了一個雙寫機制,可是如今的繪圖機器IO已經比較高了,再搞個雙寫,勢必要加機器,老闆最近又在搞什麼控制成本云云,就算了吧。監控數據雖然不是丟了會死人那麼嚴重,可是若是不解決仍然讓咱們如鯁在喉。
因而,咱們開始求助於一些分佈式存儲,咱們作數據分片,作雙寫備份,很大程度上其實就是在解決分佈式存儲領域的問題,那咱們爲何不直接使用分佈式存儲呢?
opentsdb,嗯,看着還不錯,就是用來存放時間序列的數據。咱們組一個同事聶安對opentsdb作了一些調研,以爲不能知足需求,兩點:1. opentsdb不提供歸檔,要查看一年的歷史數據,opentsdb就真的去把一年的全部點load出來,速度慢不說,瀏覽器非卡死不可; 2. opentsdb有tag數目限制,tag數不能多於8個,但咱們在用的過程發現,好多業務數據的tag都是9個10個,無法減小。
你們看rrd的時候順便看一下它提供的歸檔機制,很強大
經過改代碼,或許能夠調整tag數不能多於8個的限制,但性能可能會急劇降低。另外在很早的時候,同事來煒曾簡單嘗試過opentsdb,當時只用了10來臺opentsdb前端,一打就掛一打就掛,多是咱們機器用的太少,也多是某些參數沒有作調優,時間關係,當時沒有深刻去研究,可是先入爲主的以爲opentsdb不夠強。再加上聶安此次調研,咱們最終就放棄了opentsdb。
小米有好幾個hbase的committer,團隊強大,咱們如今準備直接使用hbase作存儲,雲存儲團隊給咱們技術支持,本身作歸檔,用hbase作後端,實現一個分佈式rrd。目前基本開發完成,測試中……若是OK的話,之後就不用擔憂graph單點數據丟失的問題了。
第二個問題:agent掛了無從知曉
這個問題的本質實際上是一個nodata的需求,也就是數據多久沒上來應該有個報警機制。開源版本的open-falcon目前沒有提供解決方案。應該如何設計這個nodata組件呢?
nodata組件的開源工做應該正在進行中
咱們仍是不但願改變用戶的使用習慣,好比如今每一個agent每一個週期都會push一個agent.alive=1的數據,用戶只要在portal上配置說all(#3) agent.alive != 1就報警。若是沒有nodata組件,這個策略是無法工做的,由於agent掛了,不會有agent.alive=0的數據上來。那咱們只要寫一個組件,在發現沒有agent.alive數據的時候就自動push一個agent.alive=0的數據不就能夠了麼。
O了,這就是nodat組件的工做邏輯,咱們能夠配置一些關鍵的指標的default值(當server端發現沒有對應數據上來的時候,就自動push一個default值),注意,這裏只是配置了一些關鍵指標,不是全部指標都配置,若是全部指標都配置,工做量不可接受,並且也不必,好比agent會採集cpu、內存、磁盤、io等不少數據,咱們不必爲這些數據都配置default值,只要配置agent.alive的default值是0,就能夠了,就能夠監測到agent是否掛掉。
最後一個問題:如何處理集羣監控
好比咱們有一個集羣,掛一兩臺機器沒啥問題,可是掛的機器超過10%就有問題了。另外一個例子:咱們有個集羣,失敗請求率小於5%沒有問題,大於5%了就要儘快接入處理了。
這種從集羣視角去判斷閾值的情形,應該如何支持呢?
這個問題若是從簡單着手,能夠直接作成:對一批機器的某個指標作一個相加。好比某集羣有30臺機器,要對集羣的總體錯誤率作一個統計,只要每臺機器都計算一個本機的錯誤率:query_fail_rate=query_fail/query_total,而後把全部機器的這個query_fail_rate相加求平均便可。
可是,這樣作顯然是不太準確,更準確的作法應該是把全部的query_fail相加,把全部的query_total相加,而後作除法。
因此最後能夠抽象爲一批機器+一個除法表達式。一批機器就是指某個集羣的全部機器,一個除法表達式,在上例中,其分子是query_fail,分母是query_total。集羣指標聚合的這個組件姑且稱之爲aggregator,這個aggregator組件獲得機器列表和分子、分母以後,就能夠去計算了。把每一個機器的query_fail查詢到並所有相加,把每一個機器的全部query_total查詢到並所有相加,最後作個除法便可
這種作法是否能夠解決集羣機器掛的數量達到某個值就報警的需求?沒問題的,分子是agent.alive,分母是機器總量,好比30(這個能夠動態計算),agent.alive正常來講都是1,若是掛了就是0(咱們的nodata組件的成果),好比有3臺掛了,分子之和計算出來應該是27,分母是30,27/30<90%? 符合閾值就報警。
這種抽象看起來問題不大,最後一點要說明的是,aggregator模塊去計算的集羣聚合結果應該是每一個週期都要計算,計算結果要從新push給falcon,這樣這個集羣的聚合結果就能夠像一個普通的監控項同樣,能夠用來繪圖,能夠用來報警。
OK,已經挺長時間了,整個open-falcon的腦洞歷程就講解這麼多,但願對你們有幫助,謝謝你們。
Q1 和elk或者stasd加graphite比是否使用方便
A1. 這個方便程度很難講了,falcon側重的是作一個監控框架,歸入各類數據,而後作好報警,還有歷史數據歸檔,和elk之類的可能目標不是徹底一致,不是一類產品
Q2. 最後說的 求 集羣監控 query_fail_rate 的部分應該也會有 單點問題的吧、怎麼規避的呢
A2. aggregator模塊的確是會有單點問題的,目前尚未去解決,能夠作個選主之類的邏輯,多個實例一塊兒上,可是每次只有一個主在工做
Q3.我想請教一下,open-falcon將大多數監控處理放到了agent,部署升級得關注版本一致性,若是使用snmp協議監控資源,服務端每次採集資源時經過go的goroutine併發採集入庫,資源報警和其餘程序經過trap反饋給服務端,感受是否會更方便一些,問的比較弱,見笑了。
A3. snmp沒有agent強大,agent做爲一個常駐進程運行在機器上,能夠乾的事情更多一些,並且snmp去pull,server端的壓力會大一些,處理起來略麻煩
Q4.監控在告警時存在誤報麼、怎麼保證每條發送出去的告警都是有用的?
A4. hbs只是用來分發agent要執行的插件、要監控的進程、端口,不作報警相關的處理,這樣邏輯結構上更清晰一些:)
Q5. 目前業務層也接入了監控系統,會出現監控系統單點故障致使全局的應用所有不可用嗎?
A5. 業務系統中嵌入監控的邏輯,就要很當心了,這個監控邏輯不能阻塞主要業務處理,只是一個旁路,一個單獨的線程,監控系統整個掛了,不會影響到各個業務:)
Q6.監控在告警時存在誤報麼、怎麼保證每條發送出去的告警都是有用的?
A6. 誤報這個是不存在的,都是按照用戶的策略去報警,固然,有的時候用戶不知道本身的閾值設置多少合適,隨便設置了一個,這種狀況報的警可能確實沒啥用處
Q7、agent端數據採集點有多少,性能壓力是怎樣的?
A7. agent在全部目標機器上部署,好比有1w臺機器,就要部署1w個agent,每一個agent大約採集200各監控項,如今小米的falcon應用狀況是每一個週期5000w左右的數據上來,有幾十臺監控server端協同工做
Q8、jduge中的transfer作轉發,這個是單點處理麼?若是掛了怎麼辦?
A8. transfer只是一個轉發組件,是無狀態的,transfer掛個一兩臺沒有問題
Q9、看到agent運行腳本的時候,採集的是stdout的數據,stderr的數據採集麼?若是不當心採集了二進制數據,是怎麼處理?不當心調試的時候採集數據量比較大,阻塞了網絡的狀況有麼?
A9. 只採集stdout是一種約定,須要彙報的數據寫入stdout,腳本運行出錯了寫入stderr,若是採集的腳本不能decode成要求的數據格式,直接扔掉。目前沒有出現調試的時候數據量大阻塞網絡的狀況:)
Q10、agent是打包到大家的鏡像文件中,系統安裝完後自動啓動,而後上報麼?若是是這樣,那麼何時填寫的服務器地址?
A10. 咱們的系統由系統組統一裝機,而後統一初始化,初始化的時候安裝一些基礎組件,agent就是在這個時機安裝,以後各個業務線再作針對本身業務的初始化工做:)
Q11. 有沒有相應的監控報表之類的?是否能夠對接kibana
A11. 如今基本沒有報表性質的東西,只有趨勢圖,針對各個監控項的歷史趨勢圖。哦,還有一個未恢復的報警列表,各個產品線工程師能夠在下班的時候看一眼這個未恢復的報警列表,看是否有忘記處理的。其餘就沒了,不懂kibana:)
Q12 如此多的監控項和圖表如何展現,如何快速找到須要的東西
A12. 通常咱們要看什麼數據是有很強目的性的,好比某個服務掛了,你可能要看這個服務所在機器的狀況,因而就能夠拿着機器名之類的去搜索,也能夠根據metric(監控項)去搜索,等等。也能夠提早作screen,把常常要看的圖表放在一個頁面
Q13. 是否有監控到異常,而後自動對服務器進行後續操做的?
A13 有的,異常了以後一般的處理是報警,也能夠回調一個業務的接口,把相關的參數都傳遞個這個接口,用戶就能夠在這個接口中寫本身的業務邏輯,好比去重啓某個機器