本文將從海量日誌系統在優化、部署、監控方向如何更適應業務的需求入手,重點從多種日誌系統的架構設計對比;後續調優過程:橫向擴展與縱向擴展,分集羣,數據分治,重寫數據鏈路等實際現象與問題展開。前端
有過項目開發經驗的朋友都知道:從平臺的最初搭建到實現核心業務,都須要有日誌平臺爲各類業務保駕護航。程序員
如上圖所示,對於一個簡單的日誌應用場景,一般會準備 master/slave 兩個應用。咱們只需運行一個 Shell 腳本,即可查看是否存在錯誤信息。面試
隨着業務複雜度的增長,應用場景也會變得複雜。雖然監控系統可以顯示某臺機器或者某個應用的錯誤。算法
然而在實際的生產環境中,因爲實施了隔離,一旦在上圖下側的紅框內某個應用出現了 Bug,則沒法訪問到其對應的日誌,也就談不上將日誌取出了。數據庫
另外,有些深度依賴日誌平臺的應用,也可能在日誌產生的時候就直接採集走,進而刪除掉原始的日誌文件。這些場景給咱們日誌系統的維護都帶來了難度。後端
參考 Logstash,通常會有兩種日誌業務流程:緩存
正常狀況下的簡單流程爲:應用產生日誌→根據預約義的日誌文件大小或時間間隔,經過執行 Logrotation,不斷刷新出新的文件→按期查看→按期刪除。安全
複雜應用場景的流程爲:應用產生日誌→採集→傳輸→按需過濾與轉換→存儲→分析與查看。性能優化
咱們能夠從實時性和錯誤分析兩個維度來區分不一樣的日誌數據場景:服務器
實時,通常適用於咱們常說的一級應用,如:直接面向用戶的應用。咱們能夠自定義各種關鍵字,以方便在出現各類 error 或 exception 時,相關業務人員可以在第一時間被通知到。
準實時,通常適用於一些項目管理的平臺,如:在須要填寫工時的時候出現了宕機,但這並不影響工資的發放。
平臺在幾分鐘後完成重啓,咱們能夠再登陸填寫,該狀況並不形成原則性的影響。所以,咱們能夠將其列爲準實時的級別。
除了直接採集錯誤與異常,咱們還須要進行分析。例如:僅知道某人的體重是沒什麼意義的,可是若是增長了性別和身高兩個指標,那麼咱們就能夠判斷出此人的體重是否爲標準體重。
也就是說:若是能給出多個指標,就能夠對龐大的數據進行去噪,而後經過迴歸分析,讓採集到的數據更有意義。
此外,咱們還要不斷地去還原數字的真實性。特別是對於實時的一級應用,咱們要能快速地讓用戶明白他們所碰到現象的真實含義。
例如:商家在上架時錯把商品的價格標籤 100 元標成了 10 元。這會致使商品立刻被搶購一空。
可是這種現象並不是是業務的問題,很難被發現,所以咱們只能經過日誌數據進行邏輯分析,及時反饋以保證在幾十秒以後將庫存修改成零,從而有效地解決此問題。可見,在此應用場景中,實時分析就顯得很是有用。
最後是追溯,咱們須要在獲取歷史信息的同時,實現跨時間維度的對比與總結,那麼追溯就可以在各類應用中發揮其關聯性做用了。
上述說起的各個要素都是咱們管理日誌的基準。如上圖所示,咱們的日誌系統採用的是開源的 ELK 模式:
ElasticSearch(後簡稱 ES),負責後端集中存儲與查詢工做。
單獨的 Beats 負責日誌的蒐集。FileBeat 則改進了 Logstash 的資源佔用問題;TopBeat 負責蒐集監控資源,相似系統命令 top 去獲取 CPU 的性能。
因爲日誌服務對於業務來講僅起到了維穩和保障的做用,並且咱們須要實現快速、輕量的數據採集與傳輸,所以不該佔用服務器太多資源。
在方式上咱們採用的是插件模式,包括:input 插件、output 插件、以及中間負責傳輸過濾的插件。這些插件有着不一樣的規則和本身的格式,支持着各類安全性的傳輸。
有了上述日誌的架構,咱們針對各類實際的應用場景,進一步提出了四個方面的優化思路:
基礎優化
內存:如何分配內存、垃圾回收、增長緩存和鎖。
網絡:網絡傳輸序列化、增長壓縮、策略、散列、不一樣協議與格式。
CPU:用多線程提升利用率和負載。
此處利用率和負載是兩個不一樣的概念:
利用率:在用滿一個核後再用下一個內核,利用率是逐步升高的。
負載:一會兒把八個核全用上了,則負載雖然是滿的,可是利用率很低。即,每核都被佔用了,可是所佔用的資源卻很少,計算率比較低下。
磁盤:嘗試經過文件合併,減小碎片文件的產生,並減小尋道次數。同時在系統級別,經過修改設置,關閉各類無用的服務。
平臺擴展
作加減法,或稱替代方案:不管是互聯網應用,仍是平常應用,咱們在查詢時都增長了分佈式緩存,以有效提高查詢的效率。另外,咱們將不被平臺使用到的地方直接關閉或去除。
縱向擴展:如增長擴展磁盤和內存。
橫向擴展:加減/平行擴展,使用分佈式集羣。
數據分治
根據數據的不一樣維度,對數據進行分類、分級。例如:咱們從日誌中區分error、info、和 debug,甚至將 info 和 debug 級別的日誌直接過濾掉。
數據熱點:例如:某種日誌數據在白天的某個時間段內呈現暴漲趨勢,而晚上只是平穩產生。咱們就能夠根據此熱點狀況將它們取出來單獨處理,以打散熱點。
系統降級
咱們在對總體業務進行有效區分的基礎上,經過制定一些降級方案,將部分不重要的功能停掉,以知足核心業務。
在此我向你們推薦一個架構學習交流羣。交流學習羣號:478030634 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
面對持續增加的數據量,咱們雖然增長了許多資源,可是並不能從根本上解決問題。
特別體如今以下三方面:
日誌產生量龐大,天天有幾百億條。
因爲生產環境隔離,咱們沒法直接查看到數據。
代理資源限制,咱們的各類日誌採集和系統資源採集操做,不可超過業務資源的一個核。
一級業務架構
咱們日誌系統的層次相對比較清晰,可簡單分爲數據接入、數據存儲和數據可視化三大塊。
具體包括:
Rsyslog,是目前咱們所接觸到的採集工具中最節省性能的一種。
Kafka,具備持久化的做用。固然它在使用到達必定數據量級時,會出現 Bug。
Fluentd,它與 Rsyslog 相似,也是一種日誌的傳輸工具,可是它更偏向傳輸服務。
ES 和 Kibana。
該架構在實現上會用到 Golang、Ruby、Java、JS 等不一樣的語言。在後期改造時,咱們會將符合 Key-Value 模式的數據快速地導入 HBase 之中。
基於 HBase 的自身特色,咱們實現了它在內存層的 B+ 樹,而且持久化到咱們的磁盤之上,從而達到了理想的快速插入的速度。這也正是咱們願意選擇 HBase 做爲日誌方案的緣由。
二級業務架構
咱們直接來看二級業務架構的功能圖,它是由以下流程串聯而成的:
在完成了數據採集以後,爲了節省本身佔用磁盤的空間,許多應用會徹底依賴於咱們的日誌系統。所以在數據採集完之後,咱們增長了一個持久緩存。
完成緩存以後系統執行傳輸。傳輸的過程包括:過濾和轉換,這個過程能夠進行數據抽稀。值得強調的是:若是業務方儘早合做並給予咱們一些約定的話,咱們就可以經過格式化來實現結構化的數據。
隨後執行的是分流,其主要包括兩大塊:一種是 A 來源的數據走 A 通道,B 來源的數據走 B 通道。另外一種是讓 A 數據流入到咱們的存儲設備,並觸發保護機制。即爲了保障存儲系統,咱們額外增長了一個隊列。
例如:隊列爲 100,裏面的一個 chunk 爲 256 兆,咱們如今設置高水位爲 0.七、低水位爲 0.3。
在寫操做的堆積時,因爲咱們設置了 0.7,即 100 兆赫。那麼在一個 256 兆會堆積到 70 個 chunk 時,咱們往該存儲平臺的寫速度就已經跟不上了。
此時高水位點會被觸發,不容許繼續寫入,直到整個寫入過程把該 chunk 消化掉,並降至 30 個時,方可繼續往裏寫入。咱們就是用該保護機制來保護後臺以及存儲設備的。
接着是存儲,因爲整個數據流的量會比較大,所以在存儲環節主要執行的是存儲的索引、壓縮、和查詢。
最後是 UI 的一些分析算法,運用 SQL 的一些查詢語句進行簡單、快速地查詢。
一般從採集(logstash/rsyslog/heka/filebeat)到面向緩存的 Kafka 是一種典型的寬依賴。
所謂寬依賴,是指每一個 App 均可能跟每一個 Broker 相關聯。在 Kafka 處,每次傳輸都要在哈希以後,再把數據寫到每一個 Broker 上。
而窄依賴,則是其每個 Fluentd 進程都只對應一個 Broker 的過程。最終經過寬依賴過程寫入到 ES。
採集
如 Rsyslog 不但佔用資源最少,並且能夠添加各類規則,它還能支持像 TSL、SSL 之類的安全協議。
Filebeat 輕量,在版本 5.x 中,Elasticsearch 具備解析的能力(像 Logstash 過濾器)— Ingest。
這也就意味着能夠將數據直接用 Filebeat 推送到 Elasticsearch,並讓 Elasticsearch 既作解析的事情,又作存儲的事情。
Kafka
接着是 Kafka,Kafka 主要實現的是順序存儲,它經過 topic 和消息隊列的機制,實現了快速地數據存儲。
而它的缺點:因爲全部的數據都向 Kafka 寫入,會致使 topic 過多,引起磁盤競爭,進而嚴重拖累 Kafka 的性能。
另外,若是全部的數據都使用統一標籤的話,因爲不知道所採集到的數據具體類別,咱們將很難實現對數據的分治。
所以,在後面的優化傳輸機制方面,咱們改造並本身實現了順序存儲的過程,進而解決了必定要作持久化這一安全保障的需求。
Fluentd
Fluentd 有點相似於 Logstash,它的文檔和插件很是齊全。其多種插件可保證直接對接到 Hadoop 或 ES。
就接入而言,咱們能夠採用 Fluentd 到 Fluentd 的方式。即在原有一層數據接入的基礎上,再接一次 Fluentd。同時它也支持安全傳輸。固然咱們在後面也對它進行了重點優化。
ES+Kibana
最後咱們用到了 ES 和 Kibana。ES 的優點在於經過 Lucene 實現了快速的倒排索引。
因爲大量的日誌是非結構化的,所以咱們使用 ES 的 Lucene 進行包裝,以知足普通用戶執行非結構化日誌的搜索。而 Kibana 則基於 Lucene 提供可視化顯示工具。
下面介紹一下咱們碰到過的問題和現象,以下這些都是咱們着手優化的出發點:
傳輸服務器的 CPU 利用率低下,每一個核的負載不飽滿。
傳輸服務器 Full gc 的頻次太高。因爲咱們是使用 Ruby 來實現的過程,其內存默認設置的數據量有時會過大。
存儲服務器出現單波峯現象,即存儲服務器磁盤有時會忽然出現性能直線驟升或驟降。
頻繁觸發高水位。如前所述的高水位保護機制,一旦存儲磁盤觸發了高水位,則再也不提供服務,只能等待人工進行磁盤「清洗」。
若是 ES 的一臺機器「掛」了,則集羣就 hang 住了。即當發現某臺機器沒法通信時,集羣會認爲它「掛」了,則快速啓動數據恢復。而若是正值系統繁忙之時,則此類數據恢復的操做會更加拖累系統的總體性能。
因爲全部數據都被寫入 Kafka,而咱們只用到了一個 topic,這就形成了每一類數據都要通過不必定與之相關的規則鏈,並進行不必定適用的規則判斷,所以數據的傳輸效率總體被下降了。
Fluentd 的 host 輪詢機制形成高水位頻發。因爲 Fluentd 在與 ES 對接時遵循一個默認策略:首選前五臺進行數據寫入,即與前五臺的前五個接口交互。
在咱們的生產環境中,Fluentd 是用 CRuby 寫的。每個進程屬於一個 Fluentd 進程,且每個進程都會對應一個 host 文件。
而該 host 文件的前五個默認值即爲 ES 的寫入入口,所以全部機器都會去找這五個入口。
假若有一臺機器宕機,則會輪詢到下一臺。如此直接形成了高水位的頻繁出現、和寫入速度的降低。
衆所周知,對日誌的查詢是一種低頻次的查詢,即只有在出現問題時纔會去查看。可是在實際操做中,咱們每每經過檢索的方式所有取出,所以意義不大。
另外 ES 爲了達到較好的性能,會將數據存儲在 raid0 中,存儲的時間跨度每每會超過 7 天,所以其成本也比較高。
經過對數據的實時線分析,咱們發現並未達到寫入/寫出的平衡狀態。
爲了提升 Fluentd 的利用率,咱們用 Kafka 去數據的時候提升了量,原來是 5 兆,如今咱們改到了 6 兆。
若是隻是單純傳輸,不論計算的話,其實能夠改更高。只不過由於咱們考慮到這裏包含了計算的一些東西,因此只提到了 6 兆。
咱們的 Fluentd 是基於 JRuby 的,由於 JRuby 能夠多線程,可是咱們的 CRuby 沒有任何意義。
爲了提升內存,我把 Ruby 全部的內存機制瞭解了一下,就是散列的一些 host 文件,由於咱們每一個進程都選前五列就能夠了,我多開了幾個口。ES 的優化這一塊,在上 ES 以前,咱們已經有人作過一次優化了。
由於基於我剛纔說的有時候日誌量很高,有時候日誌量不多。咱們會考慮作動態配置。
由於 ES 就是支持動態配置的,因此它動態配置的時候,咱們在某些場景下能夠提升它的寫入速度,某些場景下能夠支持它的這種查詢效率。咱們能夠嘗試去作一些動態配置負載。
改造一:存儲下降
下降存儲在總體架構上並無太大變化,咱們只是在傳輸到 Fluentd 時把天數降下來,改爲了一天。
同時,咱們直接進行了分流,把數據往 Hadoop 裏寫,而把一些符合 Kibana 的數據直接放入 ES。
上面提過,日誌查詢是低頻次的,通常須要查詢兩天以上數據的可能性很小,所以咱們下降存儲是很是有意義的。
改造二:數據分治
咱們在日誌文件節點數較少(機器數量小於 5 臺)的狀況下,去掉了 Kafka 層。因爲 Fluentd 能夠支持數據和大文件存儲,所以數據可以被持久化地存入磁盤。
咱們給每一個應用都直接對應了一個 tag,以方便各個應用對應到本身的 tag、遵循本身的固定規則、並最終寫入 ES,這樣就方便了出現問題的各自定位。
另外,咱們運用延遲計算和文件切分也能快速地找到問題的根源。所以咱們節約了 Kafka 和 ES 各類計算資源。
在實際操做中,因爲 HBase 不用去作 raid,它本身徹底可以控制磁盤的寫入,所以咱們進行了數據壓縮。就其效果而言,ES 的存儲開銷大幅下降。
在後期,咱們也嘗試過一種更爲極端的方案:讓用戶直接經過客戶端的 Shell 去查詢數據,並採用本地緩存的留存機制。
優化效果
優化的效果以下:
服務器資源的有效利用。在實施了新的方案以後,咱們省了不少服務器,並且單臺服務器的存儲資源也節省了 15%。
單核處理每秒原來可以傳輸 3000 條,實施後提高到了 1.5~1.8 萬條。並且,在服務器單獨空跑,即不加任何計算時,單核每秒能傳輸近 3 萬條。
不多觸發 ES 保護機制。緣由就是咱們已把數據分流出來了。
之前歷史數據只能存 7 天,因爲咱們節省了服務器,所以咱們如今能夠存儲更長時間的數據。並且,對於一些他人查詢過的日誌,咱們也會根據最初的策略,有選擇性地保留下來,以便追溯。
關於日誌平臺優化,我總結了以下幾點:
因爲日誌是低頻次的,咱們把歷史數據存入了廉價存儲之中,普通用戶須要的時候,咱們再導到 ES 裏,經過 Kibana 的前端界面即可快速查詢到。而對於程序員來講,則不須要到 ES 即可直接查詢到。
數據存在的時間越長,則意義越小。咱們根據實際狀況制定了有效的、留存有意義數據的策略。
順序寫盤替代內存。例如:區別於日常的隨機寫盤,咱們在操做讀寫一個流文件時採起的是按順序寫數據的模式。
而在存儲量大的時候,則應當考慮 SSD。特別是在 ES 遇到限流時,使用 SSD 能夠提高 ES 的性能。
提早定製規範,從而可以有效解決後期分析等工做。
日誌格式
如上圖所示,經常使用的日誌格式類型包括:uuid、timestamp、host 等。
特別是 host,因爲日誌會涉及到幾百個節點,有了 host 類型,咱們就能斷定是哪臺機器上的標準。而圖中其餘的環境變量類型,則可以有效地追溯到一些歷史的信息。
在此我向你們推薦一個架構學習交流羣。交流學習羣號:478030634 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
日誌方案
如上圖所示,咱們經過 Rsyslog 能夠直接將採集端的數據寫入文件或數據庫之中。
固然,對於一些暫時用不上的日誌,咱們不必定非要實施過濾傳輸的規則。
如上圖,Fluentd 也有一些傳輸的規則,包括:Fluentd 能夠直接對接 Fluentd,也能夠直接對接 MongoDB、MySQL 等。
另外,咱們也有一些組件能夠快速地對接插件和系統,例如讓 Fluentd 和 Rsyslog 可以直接連到 ES 上。
這是我我的給你們定製的一些最基本的基線,我認爲日誌從採集、緩存、傳輸、存儲,到最終可視化,分紅了三套基線。
採集到存儲是最簡單的一個,像 Rsyslog 到 hdfs 或者其餘 filesystem,咱們有這種狀況。
比較常見的狀況,就是從採集、傳輸、到存儲可視化,而後造成最終咱們如今最複雜的一套系統,你們能夠根據實際狀況取捨。
最後是我考慮到一個實際狀況,假如這個案例,咱們儘量少的佔有服務器,而後傳輸須要過濾轉換,日誌能夠比較簡單,符合這種 Key value(KV)格式。
咱們能夠按照取了一個 Rsyslog、取了一個 Fluentd、取了一個 Hbase,取了一個 echars 等這麼一個方式作一個方案就能夠了。
我以爲 Rsyslog、Fluentd、heka 這些均可以作採集。而後傳輸這塊有 Fluentd 傳輸,由於 Fluentd 和 Kafka 到插件很是靈活能夠直接對接咱們不少存儲設備,也能夠對應不少的文件、連 ES 均可以。
可視化能夠用 Kibana,主要是跟 ES 結合得比較緊密,它們結合在一塊兒須要一點學習成本。
你們以爲文章對你仍是有一點點幫助的,你們能夠點擊下方二維碼進行關注。 《Java爛豬皮》 公衆號聊的不只僅是Java技術知識,還有面試等乾貨,後期還有大量架構乾貨。你們一塊兒關注吧!關注爛豬皮,你會了解的更多..............