小米開源監控系統OpenFalcon應對高併發7種手段前端
原創 2016-04-01 秦曉輝 高可用架構 編者按:本文是秦曉輝在 3 月 27 日數人云「百萬併發」活動的演講,受權「高可用架構」首發。轉載請註明來自高可用架構公衆號「ArchNotes」。golang
秦曉輝,小米運維研發技術負責人,互聯網公司監控解決方案 OpenFalcon 主程,國內第一套開源 PaaS 平臺 DINP 主程,企業級業務監控 Minos 做者,Gopher,現負責小米運維平臺的搭建。關注運維自動化、PaaS 領域。算法
今天給你們簡單介紹一下 OpenFalcon 應對高併發的一些手段。OpenFalcon 是一個監控系統,來自於小米的運維團隊,OpenFalcon 主要針對運維架構師、DevOP 及關注高併發的研發人員。小米在使用 OpenFalcon 的過程中,每一個週期(5 分鐘)大約有 1 億條數據彙報上來。數據庫
下面我首先會對 OpenFalcon 作一個簡單介紹,而後再介紹小米在高併發場景 7 種應對的手段,包括怎麼作數據採集、轉發、分片、報警等內容。後端
(OpenFalcon 架構,點擊圖片可全屏縮放)瀏覽器
OpenFalcon 簡介緩存
監控系統是整個運維環節,乃至整個產品生命週期中最重要的一環。服務器
當公司剛剛起步,業務規模較小,運維團隊也剛剛創建的初期,選擇一款開源的監控系統,是一個省時省力,效率最高的方案。微信
以後,隨着業務規模的持續快速增加,監控的對象也愈來愈多,愈來愈複雜,監控系統的使用對象也從最初少數的幾個 SRE,擴大爲更多的 DEVS,SRE。這時候,監控系統的容量和用戶的「使用效率」成了最爲突出的問題。網絡
OpenFalcon 來自於小米的運維團隊,在 2014 年初開發,大約開發了半年左右第一個版本上線,以後一直在線上穩定運行,後來咱們成立了 OpenFalcon 社區。
如今有不少公司正在使用 OpenFalcon,像美團、金山雲、京東金融、趕集、宜信、快網等。
BAT 這種大公司目前還沒了解到是否使用 OpenFalcon,他們大多使用自研系統。
OpenFalcon 官網是 http://open-falcon.org/ ,文檔地址是 http://book.open-falcon.org/ ,感興趣的同窗的能夠進一步訪問了解。
OpenFalcon 是在這樣一個場景下產生,當時小米有三套 Zabbix,每套大約能夠支撐 2,000 臺機器左右。當時有 6,000 臺機器,因此搭建了 3 套 Zabbix。另外內部還有 1 套業務監控系統,內部叫 PerfCounter,負責業務性能指標監控。
因爲 4 套監控系統維護起來比較麻煩,因而就有了開發這麼一個大一統的解決方案,也就是 OpenFalcon 的想法。
(高可用小編:看來牛人偷懶,永遠是強大系統產生的源動力)
OpenFalcon 其餘部分特性還包括:
水平擴展能力:支持每一個週期上億次的數據採集、告警斷定、歷史數據存儲和查詢
高可用:整個系統無核心單點,易運維,易部署,可水平擴展
開發語言: 整個系統的後端所有 golang 編寫,portal 和 dashboard 使用Python 編寫
OpenFalcon 在高併發場景的 7 種應對手段
對於監控系統來講,包含幾個核心功能:數據採集、歷史數據存儲、報警,最後是繪圖展現及數據挖掘。
數據採集
這一塊咱們但願作一個大一統的東西,所以要採集不少監控指標,好比 Linux 自己的監控指標,像 CPU、內存、網卡、IO 等,一些硬件指標,好比風扇的轉速、溫度等等,再加上一些開源軟件如 MySQL,Nginx,OpenStack,HBase 等監控指標。
公司內部有不少產品線,每個服務運行情況都但願採集到,好比中間層服務開了一些 RPC 端口,每個 RPC 端口在服務過程當中,latency 是多少,QPS 是多少,咱們都但願瞭解到。
因此須要覆蓋不少監控指標,監控團隊剛開始只有兩我的,不可能把全部監控指標都採集到——人力不行、技術水平也達不到。
因此咱們須要共建監控數據,讓專業的人幹專業的事。
DBA 同窗對 MySQL 比較熟,那他們去採集 MySQL 相關指標,分佈式團隊同窗去採集 HBase 或 Hadoop 等指標,網絡組同窗去採集交換機路由器指標。
而做爲監控團隊要作的,就是制訂一個規範。制定一個數據進來的機制,而後公司開發人員和運維人員按照規範去推送數據。
數據收集沒有采用拉的方式,由於太多數據源,做爲一個 Client 去鏈接源端,採集數據,再關閉鏈接,會產生不少 time_wait 狀態鏈接,其吞吐必然是不高,因此要把本身作成 Server 端。如今每一個週期有 1 億多條數據。
這個週期簡單解釋一下,監控數據是一個持續上報,好比 Linux 一些基本監控項一分鐘一次採集以後上報,下一分鐘再採集再上報。一些像業務監控有 3 分鐘的,有 5 分鐘的。
所以週期是指數據量是 5 分鐘之內,有上報動做的數據。
數據有不少要 Push 到 Server 端,Server 端最前端組件是 Transfer,Transfer 接收到數據後要把它轉發給後面兩個組件,一個是 Graph(用來作繪圖),一個是 Judge(用來作報警判斷)。
首先對每個後端實例建立一個 Queue 出來,好比 20 個 Graph 實例,60 個 Judge 實例,爲每一個實例建立一個 Queue,每一個 Transfer 內存中有 80 個 Queue,
當一條監控數據過來以後,須要判斷數據發到哪個實例,而後放到這個實例對應 Queue。Transfer 接收數據 RPC 邏輯很是簡單,數據拿到後放到 Queue 就立馬返回。
Agent 到 transfer,transfer 到 judge,judge 到 Redis,Redis 到 alarm,報警鏈路比較長,若是但願儘快觸發報警,鏈路每個環節都但願比較快速處理,用 Queue 方式,Transfer 吞吐特別大,不會拖慢整個鏈路。
數據放在 Queue 中有一個問題,若是不及時轉發,好比後端 load 比較高或者掛了,Queue 數據就會堆積,超過內存就會 crash,因此作了一個簡單保護措施,將 Queue 設成定長,超過 Queue 長度,數據就放不進來。
數據 Push 到 Queue 後,有一個專門對 Queue 讀入 worker,讀到了以後轉發。轉發這個動做由一堆寫 worker 完成,這裏 worker 是指 goroutine,如此這般,一堆 goroutine 協同工做,來提升轉發性能。
一致性哈希分片
這麼多數據上來不可能由一臺機器處理,所以作了一個數據分片,即一個機器只處理一部分數據,報警數據是由 Judge 作分片,繪圖數據由 Graph 作分片,這兩個都是使用一致性哈希。
一致性哈希分片有一個問題,就是擴縮容比較麻煩,數據打到某個 judge 以後,就會一直打到這個 judge。
當列表發生變化時候,因爲一致性哈希算法,原來打到一臺 judge 實例的數據就會打到另一個 Judge 實例,因此 Judge 必定要保證沒有狀態,這樣才能方便擴縮容。
狀態標記
其實說它沒有狀態也不太合適,judge 內存裏也存了幾個點。好比某一臺機器 cpu.idle 數據上來以後,連續 3 ~ 5 次達到一個特定閥值纔去報警,而不是達到閥值立馬報警。像 CPU,是一直都忙碌狀態纔去報警,Judge 判斷的時候它是判斷多個點。
產生報警以後,還有一些後續處理,好比對這個報警事件作一個判斷,上次產生事件是什麼狀態,他是第幾回報警,是否是達到了最大報警次數不能再報了,避免重複報警給處理人員形成干擾。通常你們都設置報警 3 次。
所以報警事件須要記錄一個狀態,標記是否健康,若是有問題,記錄當前是第幾回。Judge 狀態存在數據庫,雖然 1 億條數據上來,實際上報警數據很少,可能只有 10 萬條數據級別,所以能夠存入數據庫,這樣 Judge 就剝離了報警事件狀態。
雖然 Judge 內存當中還存一些前面所說數據狀態,但也不是一個大問題。由於監控數據是源源不斷上來,即便丟掉一些狀態,新的 Judge 實例很快就會又填充數據。
擴容
一致性哈希對擴容不是很友好,好比 20 臺 Graph 的機器若是變成 40 臺,勢必有老的 Graph 實例的一部分數據打到新的 Graph 上,所以咱們作了一個自動數據遷移。
這個自動遷移是因爲一致性哈希形成的問題,若是用映射表作分片,在映射表這統一維護數據和 graph 實例對應關係,擴容就簡單不少。
當數據上來後,要判斷這個數據是否是觸發了報警策略,策略有不少種,好比咱們如今系統中有幾千上萬條。
上來一條數據以後,要判斷這個數據跟哪一條策略相關,而後再判斷閥值是多少,是否是要觸發報警。
咱們選擇去數據庫同步全部報警策略列表,由於策略列表整個公司不會特別多,雖然數據量多,可是策略不是特別多,好比只有幾千條或者幾萬條。
在策略數據庫作了一個簡單索引,方便數據上來以後快速定位策略,而後根據閥值看是否要須要報警處理。
爲了加快策略斷定,須要知道近期一些歷史數據,歷史存在 Judge 內存中,這樣獲取速度相對來講快一些。
第一個版本作測試時沒有放到內存中,當時用了 56 個 Redis 實例,每一個實例大概有 3,000 QPS,那時上的量不大,仍然達到了一個這麼高的 QPS。因爲併發高,把數據放到 Redis 中並非一個很好的解決辦法,後來就把它放到了Judge 內存裏。這樣處理起來就快不少。
報警狀態也存在 Judge 內存及 DB。若是每一個報警判斷都去訪問 DB 比較耗時,因此就加載到 Judge 內存,至關與緩存的機制,內存沒有再去 DB 加載。在 Judge 重啓的時候,內存沒有數據,這時報警狀態的判斷須要去 DB 加載,而後再讀到內存裏。
時間序列數據自動歸檔
報警數據存儲採用 RRD,RRD 比較有名。大量開源監控軟件存儲時間序列數據都選用 RRD。
RRD 最大的優勢是自動歸檔。監控數據有一個特色,不須要關心歷史監控數據具體的值,只需知道當時的趨勢便可。
最新 6 個小時可能有看原始值需求。可是最近 3 天 及 1 個月原始值的需求就很小。並且那個點特別多,一分鐘 1 個點,一天有 1440 個點。若是加載 1 個月瀏覽器不崩纔怪。
因爲對歷史點只要能看到趨勢就行。所以監控數據特別須要歸檔功能。好比一個小時的數據歸檔爲一個點,RRD 能夠幫咱們作這個事情。
RRD 優化:延遲合併寫入
RRD 默認操做性能比較差,它的邏輯是打開 RRD 文件,而後去 seek,write,seek,write,最後 close 文件句柄。一個監控指標對應一個 RRD 文件,好比這個機器上面處理了大約 200 萬個監控指標,實際上就有 200 萬個 RRD 的文件。
每次寫入數據的時候,打開這個 RRD 文件,讀頭部信息,包含一些 meta 信息,記錄了歸檔策略、數據類型之類數據,而後去作寫入操做。
若是每個數據上來以後都作這個操做,RRD 讀寫會形成特別大的 IO。雖然如今磁盤都是 SSD,但因爲 IO 居高不下,因而作了一個延遲寫入的優化。
如今數據都是 1 分鐘上報一次,可能有的數據 10 秒或 30 秒上報一次。並非上報上來立馬打開 RRD 文件寫入,而是等 10 分鐘或者 30 分鐘,在內存中緩存一段時間,緩存 30 個點或者 60 個點,一次性把文件打開,一次性寫入再關閉,這樣能夠減小 RRD 文件打開的次數,讓 IO 下降一些。
咱們根據緩存的時間,好比緩存半個小時,再按照半個小時時間長度來作數據打散,好比如今半個小時是 1,800 秒,舉個例子,1,800 秒把它作成 1,800 個槽位,每一個數據上來以後平均分散到 1,800 個槽位當中,寫的時候慢慢地寫,這樣作了一個打散操做,避免讓 IO 出現一些峯值。
報警事件量一般不是特別大,但個別時候會比較大——觸發一些大面積報警的時候,好比某一個核心交換機掛掉了,會產生特別大的報警。
好比服務依賴於上游某幾個服務,上游服務掛了,全部下游服務都報警。若是核心交換機掛了,不少核心服務都受影響,核心服務受影響以後,下游不少服務就產生報警,這樣產生一個大面積報警。但一般狀況下,報警量都是一個很平穩的一個量。
當大面積報警出現時,咱們仍然是應用 Queue 機制,用 Queue 來抹平峯值。
報警的分級處理
咱們將報警進行分級,從 P0、P1 一直到 P5,P0 最高。
基於優先級的分級策略
P0、P1 發短信發郵件,而且是收到報警當即發; P2 這個級別發短信不是當即發,而是作一個報警合併; P三、P4 那些低級別就作報警合併,同時不發短信,只發郵件。
咱們對報警事件作一個分級,每個級別就對應 Redis 裏面一個Queue。利用 Redis BRPOP 簡單實現按照優先級處理報警事件,即先處理 P0,再處理 P一、P2 順序。
系統自己可能鏈路比較長,每一個鏈路都但願可以扛住高併發,實際上在系統開發過程中,咱們依賴於其餘基礎設施,好比內部有 SMTP 服務器來發送郵件,有短信通道來發送短信,可是這些接口扛不住很大的併發。
當要系統依賴調用幾個併發能力較差的接口,最好作一個限流。
有一個專門的模塊 Sender 發送報警郵件或者報警短信,它發送時候能夠給它配置一個 Worker 數量,你們能夠理解成最多有多少個線程來調用發送接口。這樣就能夠保護後端發送接口,不至於把它打掛。
總結
回到今天的議題「百萬併發」,總結咱們在設計 OpenFalcon 用到的技術。
分片:一臺機器抗不住就分紅多臺機器,數人云是一個 PaaS 平臺,PaaS 平臺很容易作擴容,原來三百臺實例如今作三千臺,在頁面上按鍵按一下,10 秒就可讓 3000 臺實例起來,作 3000 個分片。
隊列:有時候產生一些峯值,咱們不但願被峯值打垮,因而用隊列作緩衝,這個系統有多個地方用到隊列,好比 transfer 內存中構建了多條隊列,報警事件使用 Redis 作隊列服務。
索引:索引能夠加快查詢速度。
限流:後端的接口抗不住壓力的時候會作限流。
這只是幾個簡單的、很普適的手段,沒有炫耀那些高精尖、你們不太能理解及很難借鑑的東西,但願能給你們在應對高併發時候提供一些參考,謝謝你們!
相關精彩文章
基於 Locust、Tsung 的百萬併發秒殺壓測案例 5 人技術團隊開發 Go Web 項目的 9 條教訓 小米搶購限流峯值系統「大秒」架構解密
想關注更多高併發技術,請訂閱公衆號獲取更多文章。轉載請註明來自高可用架構「ArchNotes」微信公衆號及包含如下二維碼。
高可用架構 改變互聯網的構建方式