及時有效地搜索日誌是 SRE (Site Reliability Engineer) 平常工做的重要內容。LinkedIn 從使用 Splunk 到創建基於 ES 和 kafka 的日誌分發、索引系統,爲 SRE 提供了近似實時的搜索平臺來檢索超過 400 多個子系統的日誌。在本文中,來自LinkedIn的李虓將和你們分享這套系統從無到有的一些技術架構經驗。css
本文整理自李虓在QCon上海2016的演講,原題爲:《LinkedIn 基於 Kafka 和 ElasticSearch 的實時日誌分析系統》。回覆關鍵詞「領英」,下載完整版PPT。java
寫在前面node
今天,和跟你們分享咱們在用ElasticSearch和Kafka作日誌分析的時候遇到的問題,系統怎麼樣一步一步演變成如今這個版本。你若是想拿ElasticSearch和Kafka來作日誌分析的話,會有一些啓發。全文主要包括如下幾個Topic:python
日誌分析系統的基本需求;nginx
LinkedIn的日誌系統演進過程;shell
咱們的經驗和教訓。安全
爲何要作日誌分析系統?服務器
首先,什麼是日誌?簡單的說日誌就是一個結構化的數據+時間戳。計算機開始日誌就已經存在,從那時候就有各類各樣的工具來幫咱們分析、解析或者查找日誌。網絡
一開始作這個東西的時候,不少團隊以爲不是很須要,工程師登陸到服務器上面作一些cat或者grep和簡單的表達式處理就夠了,能夠找到須要的信息。若是不夠的話,好比在不少臺機器上的話,有mssh、cssh等工具。架構
還不夠的話,能夠本身寫工具,有一次我發如今咱們的生產服務器上面,有一個SRE寫了一套系統,從本身的臺式機,作了一個ssh tunnel到實際的生產系統裏面作了遠程代碼調用,遠程把那些文件拿回來,這是一個一級的安全生產事故,是很是不負責任的事情,可是這也就暴露了咱們確實有這個需求。
當咱們有五萬臺服務器,五百多個微服務的時候,你不可能期望每一個人都很是熟練的去解決這樣的事情。開發或者運維常常會遇到這樣的需求,好比拿某兩個時間點之間的全部的日誌,只須要看WARN或者ERROR或者FATAL的消息,而且有十幾個錯誤是已知的,要忽略。
這個服務是跑在好幾個數據中心幾百臺服務器上面,還須要關心有沒有新的錯誤,這個錯誤是否是因爲某個特定的用戶形成的,或者某些特定的用戶行爲形成的,好比說他post了什麼,或者request的長度超過一個固定長度;這個服務器上的錯誤信息有沒有和其餘服務器上的錯誤信息相關聯。給我30分鐘我有可能寫出來一個四五行的grep命令去幾百臺服務器上把日誌拉下來,但若是在凌晨三點鐘,這就是一個不太可能的任務。
日誌分析系統須要知足如下基本的要求:
對於重要的日誌,知足索引,檢索、排序、分類,而且提供必定程度的可視化、分析日誌的功能;
可根據數據規模橫向擴展。由於互聯網的發展很是很是的快,咱們但願找到一個解決方案,不要過了一年甚至半年,當服務器或者用戶數量加倍之後,解決方案就徹底不可用。須要找到一個方案,當用戶數量加倍時,簡單的加幾臺機器或者服務器就能夠繼續使用;
這套系統可以很輕易的擴展,由於不少公司已經有了不少的報警或者監控系統。能夠方便的經過API或者經過擴展接入到已經有的監控、報警,或者其餘系統裏面。
還有一些其餘擴展性的需求,包括日誌採樣,提升安全性、保護日誌裏面包含的信息,也是後面着重談的一個問題。
LinkedIn日誌系統演進
回到四年前,從LinkedIn成立到2012年咱們有一個系統叫Splunk,很是好用,只有一個問題,太貴了。2012年的時候,咱們當時生產環境有3、四千臺的服務器,續簽第二年的合約時他們的報價是2000萬美圓一年。這實在是不能夠接受的,而且那個時候是2012年,咱們如今的服務器臺數、用戶請求數已經翻了差很少十倍,當時的價格若是是2000萬,如今更多,由於它是根據數據量來算license的。
從2012年到2014年,由於咱們當時決定不用Splunk,就進入了一個混沌期,這段時間很是痛苦,你們都有需求,可是沒有人有方法,不少人開始搞本身的小動做,作些小工具。我以前看了一下內部工具庫,裏面有2、三十個用python或者shell寫的小工具,這些小工具是用來找一個時間段內的log或者特定用戶的log,可是有很大的浪費,不少工具重複的寫,也很是難維護。
2014年到2015年這一年多的時間咱們痛下決心,必定要作一套可以橫跨LinkedIn全部log的系統,而且推廣到整個LinkedIn。當時選擇了ELK,它的優勢就是:開源,發佈週期很是快,固然也有缺點,它很是的新,因此有不少小毛病。
相信你們不少人已經知道ELK是什麼——ElasticSearch、Logstash、Kibana。ElasticSearch就是基於Lucene的儲存,索引,搜索引擎;Logstash是提供輸入輸出以及轉換處理插件的日誌標準化管道;Kibana提供可視化和查詢ES的用戶界面。
LinkedIn日誌系統演進V1
每一個人花30分鐘就能夠在本身的電腦或者生產環境上搭一個這樣的東西,Log經過Logstash讀出來,放到ElasticSearch裏,而後Kibana去讀。這步作完之後其實就能達到很是好的效果。LinkedIn全部的業務羣都會要求有一個異常面板,好比說支付系統業務羣,它大概有十個左右不一樣的小服務。
當報警系統發現支付系統有了各類各樣的問題以後,咱們第一步就是到異常面板來看Log裏面有沒有什麼東西,能夠根據時間線上看,有沒有哪些新的服務在近期有了新的log或者error log數量不同。而且它會根據不一樣的exception/java stack拿出來作count,這也給分析帶來很大的幫助,還能夠寫出不少複雜的query。
第一個版本很是簡單,咱們只把它應用到了一兩個很是關鍵的系統上。這套系統作完以後咱們作了一個對比,平均故障解決時間從之前的五十幾分鍾縮短到小於30分鐘。咱們的線上系統通常最快會花5到10分鐘纔有一個不是很關鍵的警報出來,若是能很快發現問題在哪裏,解決這個問題,好比說一個簡單的rollback操做,在幾百臺機器上也會花5到10分鐘的時間,真正留給人根據log去判斷問題在哪裏的時間也只有短短的5到10分鐘。
若是不是有一個異常面板能看到全部的信息,好比有沒有哪一個服務器的異常比其餘服務器多,有沒有一個異常是忽然今天出了不少次的,或者有沒有一個服務器今天出了不少的異常,最起碼要花二十到三十分鐘的時間手工的看log。
第一個版本有幾個問題,第一是Logstash Agent的維護不是很理想,Logstash是基於Ruby的,啓動它就要有幾十兆內存被jvm吃掉,咱們想避免在每一個機器上都要起一個Logstash。而且在咱們使用過程當中Logstash很是不穩定,莫名其妙就死掉了,還須要一個守護進程守護它。第二個是log標準化,也是很是頭疼的問題。
第一個Logstash Agent的問題經過引入Kafka解決,引入Kafka後不須要每一個host上有agent。LinkedIn內部有專門的SRE團隊維護Kafka,很便宜,不須要花錢去維護。對於Log標準化,咱們花了很是多的時間看,LinkedIn有99%的服務都是java service,有15種以上log,最重要的是access log和application log。咱們作的一件事情是經過java Container logger標準化直接寫入Kafka。有的程序直接寫到kafka,不上磁盤,有的程序還要同時寫到磁盤裏面,這是可配置的。
這些是經過LinkedIn standard container一塊兒rollout到全部的service上。開發人員什麼都不用管,只要在程序裏寫logger.info/logger.error,那些信息就會直接進到Kafka。對於程序日誌,默認警告以上的級別進入Kafka,能夠在線經過jmx控制。對於訪問日誌,咱們有10%採樣,能夠經過ATS入口動態控制。
LinkedIn日誌系統演進V2
這是第二個版本,能夠看到在生產環境的Java service那邊,Host上已經沒有Logstash,全部的log直接寫入Kafka,Logstash從Kafka裏消費這些日誌,寫到ElasticSearch裏面去。
第二個版本還會出現一些問題,好比說一個服務出現問題的時候會影響整個ELK cluster。咱們出現過這樣的狀況,一個團隊寫了一個新的服務,把全部的log的級別都定義成error,整個ElasticSearch就被它沖垮了。不少時候還會出現網絡飽和的狀況。
很簡單,第二步很是簡單的決定就是把它進行拆分優化:
首先按照業務功能拆分ELK cluster,好比說負責支付的,跟錢有關的系統用一個集羣;全部跟用戶登錄有關的系統,安全有關的系統用一個集羣;
將Logstash和ElasticSearch分開運行。ElasticSearch是磁盤密集的操做,Logstash是CPU密集的操做,咱們當時想把他們放到一個物理機上,可是試下來相互影響仍是挺大的,因此決定把Logstash跟其餘的系統混用,與ElasticSearch分開運行;
對於每一個Kafka話題,Logstash數量很多於話題partition數量。LinkedIn有500多個服務,每一個服務會產生訪問日誌、程序日誌兩個Kafka topic。Logstash消費Kafka的時候,若是consumer數量少於partition數量,會觸發Kafka一個隱藏的漏洞,致使Kafka partition不均勻,出現各類詭異的問題。咱們的建議是,通常狀況下,每一個topic有四到八個partition,而後根據狀況設置相應數量的Logstash。
LinkedIn日誌系統演進V3
根據業務需求拆分,咱們拆出來20幾個這樣的相同的集羣,這個版本,還有一些問題。首先是跨業務分組集羣的查詢,雖然不少的時候,一個問題在一個業務分組裏面就能找到,可是還有不少的時候要跨到另一個集羣裏面才能找到問題究竟是從哪開始的。
第二,千萬不要跨數據中心作ElasticSearch的集羣,很是很是差,根本跑不起來。即便兩個數據中心很是近這樣作也很差,尤爲當數據量上來以後,會有一些很是詭異的問題。數據量很是大的ElasticSearch集羣咱們會要求它所有在一個機架上,若是有一個服務器在另外一個機架上都會出現timeout的問題。
爲了解決剛剛說的問題,咱們引入Tribe,用下來的感受能夠用,可是這明顯不是一個他們支持的功能。Tribe理念很好,可是它不支持分層,咱們須要兩種不一樣的Tribe,首先要能跨業務分組,還要跨數據中心。
最好的狀況是作一個分層的結構,數據中心在最外面,業務分組在最裏面,可是從設計理念上是另一個概念,因此不行。只能退而求其次,在一個數據中內心面會有跨全部業務分組的一個Tribe,還會對相同的業務分組有一個跨數據中心的Tribe,有兩個不一樣類型的Tribe進行查詢。
LinkedIn日誌系統演進V4
到這一步,基本上功能實現的差很少了,就開始慢慢的把500多個服務的日誌打到Kafka裏面,大概花了一兩個月,發現consume跟不上,遇到了性能瓶頸。用ElasticSearch超過50或者100臺服務器,就會遇到不少這樣的瓶頸。咱們花了三個月的時間,作了各類性能調優。
這一步算是最後一步,首先理解了一下本身的業務邏輯,咱們要作的事情很是明白,很是單一,就是須要實時的,或者準實時的log來作在線的trouble shooting,基本上不會用到14天之前的數據,保留14天之前的數據就是爲了看兩週的週期而已。
今天的問題都解決不完,根本沒有時間考慮幾個月以前的問題,實際的業務狀態是24小時以內的日誌查詢的最多,14天之前用的很是少,查詢速度要求在15秒以內,超過30秒就timeout了。索引速度30秒之內能夠接受,超過5分鐘會觸發警報。
LinkedIn日誌系統演進V5
採用冷熱分區的方式解決這個問題,咱們測試了不少種不一樣的硬件,最後選定了在很是重要和數據量很大的集羣上用ssd作熱索引,24小時以內的索引所有上到SSD機器上,超過24小時就挪到普通的機器上。至關於在集羣裏邊,有一個熱的Cluster,數據全面走到熱的cluster裏面,24小時之後,會被挪到冷的cluster。作了這個以後,系統變得比較穩定,功能也正常,內部會根據需求保留7到14天的數據。
這步以後,咱們把它推廣到LinkedIn整個公司,次日我接到法務和安所有的電話。當咱們作了一個很是容易的系統,把全部的log展示給全部人的時候,若是你們能很輕易的把4億用戶的用戶名、密碼、郵箱等信息搜出來,這個事情就很是嚴重,因此咱們又作了幾個調整。
第一個是按期掃描全部的ES,根據特定的關鍵字來防止敏感信息進入日誌,若是進入立刻報警。還有用戶隱私的問題,全部Elasticsearch的查詢記錄一樣送入Kafka,並對敏感業務部門的訪問進行隔離,全部訪問日誌按期審覈。咱們的作法是在前面加一個Nginx,在nginx上能夠作訪問控制,把用戶全部的訪問日誌所有送回Kafka作按期審覈,有一個掃描進程按期的掃描各類各樣的關鍵字。
LinkedIn日誌系統演進現狀
這是咱們如今生產系統裏的狀態,有20多個針對不一樣業務模塊的ELK集羣,1000+服務器,主要都是Elasticsearch。1分鐘以內生產系統發生的log咱們這邊就能夠搜索,全部的log保留7到14天。如今大概有500億的索引文檔,500到800T,以前測試時推到1500到2000T都是能夠工做的。
由於咱們是500多個service,20多個集羣,沒有辦法很好的維護這麼多集羣,因此是每一個業務模塊的SRE團隊維護本身的Elasticserach集羣。Virtual Team模式確保ELK的及時更新。還有一點比較關鍵,須要保證你的ES不會被沒有受權的用戶訪問,默認的狀況下是不接受SSL鏈接的,SearchGuard和Sheild這兩種解決方式都是能夠解決這個問題的。
我想着重提一下采樣方式,這個是比較有意思的,也是比較通用的方式。採樣方式是10%+特定的用戶,爲何要這麼作?咱們調過不一樣的比例,發現不影響,若是有問題,10%的採樣就能發現。爲何還要特定用戶呢?不少時候,有一些active的用戶會常常給你報錯,給你反饋意見,須要及時去看到底發生了什麼事情。
對LinkedIn來講有大概百分之零點幾的power user在網站上很是活躍,作不少事情,咱們須要把他們的log加到sample裏。全部的用戶請求,都是經過Apache Traffic Server進入數據中心,在這層它會去訪問LiX,詢問是否要對當前用戶打標籤,若是打了標籤就把這個標籤放在InvocationContext裏面。
從前臺到後臺全部的服務器只要touch到這個request,都會在InvocationContext裏看到一個requestID。經過java container的bydefault獲得requestID,把那條訪問的日誌發到Kafka裏面,經過這樣的方式作成sample。
這樣作有兩點好處,一點是若是有什麼問題,只須要把他的memberID或者requestID拿到最上面一層Tribe裏面,系統就會出現關於這條request的全部service的log。99.9%的狀況能夠一目瞭然的知道哪裏出了問題。作微服務的你們都知道,dependence很是亂,咱們LinkedIn的狀況,一個request會touch二三十個service。因此說有這樣一個方式是很是重要的。
平常運維之坑
我想聊一下咱們遇到的幾個坑,ES集羣的默認名字是大坑,若是不改集羣名字就把它放在本身的電腦上或者測試系統上跑,一旦相同子網的人加了一個新的node也沒有更名字,就會自動加到你的集羣裏面。無論怎麼樣必定要改你的集羣名字。
Master、Data、Client節點不要混用,使用單ES節點;JVM不要allocate超過30G的heap,咱們測試發現30G左右的heap能夠達到最好的performance,若是超過30G就沒有辦法徹底使用;JVM版本的兼容性也是一個超級大的坑,它不是最新的兼容,也不是哪一個版本之後,或者之前兼容,是有幾個版本兼容,再幾個版本不兼容,再幾個版本兼容。有一些兼容性的問題必定要注意。
平常運維之硬件
講一下剛纔已經提到的硬件的選擇,要根據數據量,業務的狀況,索引和查詢速度的要求決定,像咱們的要求是必定要索引快,由於要作實時的故障排查,數據的類型咱們只作兩個,一個是訪問log,一個是application log,這些決定了咱們使用的硬件是12核/64G/2x1TB的硬盤,有八九百臺都是這樣的配置。
有一小部分是數據量很是大可是對查詢的速度要求不是很高,好比作自動查詢的那套,咱們會把數據丟到JBODs裏面,索引速度優先考慮的話,會用100臺左右的SSD。
平常運維之集羣
集羣沒有magic number,必需要用實際的生產數據,一遍一遍試,才能試出來用什麼樣的配置能達到最好的效果,這幾個是咱們的learning:
橫向擴展,不要縱向擴展,不要試圖用更大的memory或者最快的CPU,不會有太大的效果,咱們大概測過四五個版本,基本上沒怎麼成功;
每一個shard不要超過50G,只要超過50G咱們的shard就會莫名其妙的失聯;
關閉冗餘,咱們把replication關了是爲了更快。關了以後若是出現硬件故障,從Kafka那邊讀,數據很快就能回來;
天天建新的索引,有一個集羣由於數據量很是大,會作每一個小時的索引,二三個數據量比較小的集羣每週作一個索引;
只分析必要字段,IP字段、設備版本,這些字段徹底沒有必要作分析,只要能整字段查找就好了,把它關掉,能夠省不少的空間,index速度也會快不少。
平常運維之工具
還有就是一些工具,剛剛提到主動掃描敏感信息的就是一個script在後臺根據一些關鍵字掃描敏感信息;結合警報系統,相信每一個公司都有本身的警報系統,ElasticAlert是一個開源的解決方案,咱們本身也有內建的,根據讀出來的信息的關鍵字作警報;循環刪除index用的Curator;系統健康狀態監控是本身作的監控系統,官方的Marvel也很好用。
提升代碼質量
作完這套系統之後,咱們並非徹底被動的狀態,只能用這套系統來作故障排查,咱們發現這套系統裏面有些指標能夠很好的反映開發人員的代碼的質量。
請求數/日誌總行數,對於每一個service都不同,可是大概有一個區間,若是出了這個區間,可能這個service就有一些問題;
請求數量/錯誤(異常)行數,這個也有一個區間,咱們這邊的區間是1000個請求,大概產生2000到5000行的日誌,500到3000行的異常數量,這個是咱們能夠接受的,常常會有service超出這個範圍10倍,經過這個就能發現異常有沒有處理。
經過這些發現一些有意思的metric返回給開發人員,幫助他們提升代碼的質量,這是一個比較有意思的發現。國外和國內你們作的東西不少很像,遇到的問題也很像,但願能給你們一些啓發。