天天看點

創業公司如何做資料分析(四)ELK日志系統

作為系列文章的第四篇,本文将重點探讨資料采集層中的elk日志系統。日志,指的是背景服務中産生的log資訊,通常會輸入到不同的檔案中,比如django服務下,一般會有nginx日志和uwsgi日志。這些日志分散地存儲在不同的機器上,取決于服務的部署情況了。如果我們依次登入每台機器去查閱日志,顯然非常繁瑣,效率也很低,而且也沒法進行統計和檢索。是以,我們需要對日志進行集中化管理,将所有機器上的日志資訊收集、彙總到一起。完整的日志資料具有非常重要的作用:

<b>資訊查找。</b>通過檢索日志資訊,定位相應的bug,找出解決方案。

<b>服務診斷。</b>通過對日志資訊進行統計、分析,了解伺服器的負荷和服務運作狀态,找出耗時請求進行優化等等。

<b>資料分析。</b>如果是格式化的log,可以做進一步的資料分析,統計、聚合出有意義的資訊,比如根據請求中的商品id,找出top10使用者感興趣商品。

elk是一套開源的集中式日志資料管理的解決方案,由elasticsearch、logstash和kibana三個系統組成。最初我們建設elk日志系統的目的是做資料分析,記得第一個需求是期望利用nginx的日志,從api請求的參數中挖掘出使用者的位置分布資訊。後來該系統在追蹤惡意刷量、優化耗時服務等方面都發揮了重要作用,而且随着對elasticsearch的認知加深,我們将其應用到了其他方面的資料存儲和分析中。<b>本文的重點是結合自身實踐來介紹如何使用elk系統、使用中的問題以及如何解決,文中涉及的elk版本是:elasticsearch 2.3、logstash 2.3、kibana 4。</b>

<b>elk整體方案</b>

elk中的三個系統分别扮演不同的角色,組成了一個整體的解決方案。logstash是一個etl工具,負責從每台機器抓取日志資料,對資料進行格式轉換和處理後,輸出到elasticsearch中存儲。elasticsearch是一個分布式搜尋引擎和分析引擎,用于資料存儲,可提供實時的資料查詢。kibana是一個資料可視化服務,根據使用者的操作從elasticsearch中查詢資料,形成相應的分析結果,以圖表的形式展現給使用者。

elk的安裝很簡單,可以按照“下載下傳-&gt;修改配置檔案-&gt;啟動”方法分别部署三個系統,也可以使用docker來快速部署。具體的安裝方法這裡不詳細介紹,我們來看一個常見的部署方案,如下圖所示,部署思路是:

第一,在每台生成日志檔案的機器上,部署logstash,作為shipper的角色,負責從日志檔案中提取資料,但是不做任何處理,直接将資料輸出到redis隊列(list)中;

第二,需要一台機器部署logstash,作為indexer的角色,負責從redis中取出資料,對資料進行格式化和相關處理後,輸出到elasticsearch中存儲;

第三,部署elasticsearch叢集,當然取決于你的資料量了,資料量小的話可以使用單台服務,如果做叢集的話,最好是有3個以上節點,同時還需要部署相關的監控插件;

第四,部署kibana服務,提供web服務。

創業公司如何做資料分析(四)ELK日志系統

在前期部署階段,主要工作是logstash節點和elasticsearch叢集的部署,而在後期使用階段,主要工作就是elasticsearch叢集的監控和使用kibana來檢索、分析日志資料了,當然也可以直接編寫程式來消費elasticsearch中的資料。

在上面的部署方案中,我們将logstash分為shipper和indexer兩種角色來完成不同的工作,中間通過redis做資料管道,為什麼要這樣做?為什麼不是直接在每台機器上使用logstash提取資料、處理、存入elasticsearch?

首先,采用這樣的架構部署,有三點優勢:

第一,降低對日志所在機器的影響,這些機器上一般都部署着反向代理或應用服務,本身負載就很重了,是以盡可能的在這些機器上少做事;

第二,如果有很多台機器需要做日志收集,那麼讓每台機器都向elasticsearch持續寫入資料,必然會對elasticsearch造成壓力,是以需要對資料進行緩沖,同時,這樣的緩沖也可以一定程度的保護資料不丢失;

第三,将日志資料的格式化與處理放到indexer中統一做,可以在一處修改代碼、部署,避免需要到多台機器上去修改配置。

其次,我們需要做的是将資料放入一個消息隊列中進行緩沖,是以redis隻是其中一個選擇,也可以是rabbitmq、kafka等等,在實際生産中,redis與kafka用的比較多。由于redis叢集一般都是通過key來做分片,無法對list類型做叢集,在資料量大的時候必然不合适了,而kafka天生就是分布式的消息隊列系統。

<b>logstash</b>

在官方文檔中,deploying and scaling logstash一文詳細介紹了各種logstash的部署架構,下圖是與我們上述方案相吻合的架構。logstash由input、filter和output三部分組成,input負責從資料源提取資料,filter負責解析、處理資料,output負責輸出資料,每部分都有提供豐富的插件。logstash的設計思路也非常值得借鑒,以插件的形式來組織功能,通過配置檔案來描述需要插件做什麼。我們以nginx日志為例,來看看如何使用一些常用插件。

創業公司如何做資料分析(四)ELK日志系統

<b>1. 配置nginx日志格式</b>

首先需要将nginx日志格式規範化,便于做解析處理。在nginx.conf檔案中設定:

創業公司如何做資料分析(四)ELK日志系統

<b>2. nginx日志–&gt;&gt;logstash–&gt;&gt;消息隊列</b>

這部分是logstash shipper的工作,涉及input和output兩種插件。input部分,由于需要提取的是日志檔案,一般使用file插件,該插件常用的幾個參數是:

path,指定日志檔案路徑。

type,指定一個名稱,設定type後,可以在後面的filter和output中對不同的type做不同的處理,适用于需要消費多個日志檔案的場景。

start_position,指定起始讀取位置,“beginning”表示從檔案頭開始,“end”表示從檔案尾開始(類似tail -f)。

sincedb_path,與logstash的一個坑有關。通常logstash會記錄每個檔案已經被讀取到的位置,儲存在sincedb中,如果logstash重新開機,那麼對于同一個檔案,會繼續從上次記錄的位置開始讀取。如果想重新從頭讀取檔案,需要删除sincedb檔案,sincedb_path則是指定了該檔案的路徑。為了友善,我們可以根據需要将其設定為“/dev/null”,即不儲存位置資訊。output部分,将資料輸出到消息隊列,以redis為例,需要指定redis server和list key名稱。另外,在測試階段,可以使用stdout來檢視輸出資訊。

創業公司如何做資料分析(四)ELK日志系統

<b>3. 消息隊列–&gt;&gt;logstash–&gt;&gt;elasticsearch</b>

這部分是logstash indexer的工作,涉及input、filter和output三種插件。在input部分,我們通過redis插件将資料從消息隊列中取出來。在output部分,我們通過elasticsearch插件将資料寫入elasticsearch。

創業公司如何做資料分析(四)ELK日志系統

這裡,我們重點關注filter部分,下面列舉幾個常用的插件,實際使用中根據自身需求從官方文檔中查找适合自己業務的插件并使用即可,當然也可以編寫自己的插件。

grok,是logstash最重要的一個插件,用于将非結構化的文本資料轉化為結構化的資料。grok内部使用正則文法對文本資料進行比對,為了降低使用複雜度,其提供了一組pattern,我們可以直接調用pattern而不需要自己寫正規表達式,參考源碼grok-patterns。

grok解析文本的文法格式是%{syntax:semantic},syntax是pattern名稱,semantic是需要生成的字段名稱,使用工具grok debugger可以對解析文法進行調試。例如,在下面的配置中,我們先使用grok對輸入的原始nginx日志資訊(預設以message作為字段名)進行解析,并添加新的字段request_path_with_verb(該字段的值是verb和request_path的組合),然後對request_path字段做進一步解析。

kv,用于将某個字段的值進行分解,類似于程式設計語言中的字元串split。在下面的配置中,我們将request_args字段值按照“&amp;”進行分解,分解後的字段名稱以“request_args_”作為字首,并且丢棄重複的字段。

geoip,用于根據ip資訊生成地理位置資訊,預設使用自帶的一份geolitecity database,也可以自己更換為最新的資料庫,但是需要資料格式需要遵循maxmind的格式(參考geolite),似乎目前隻能支援legacy database,資料類型必須是.dat。下載下傳geolitecity.dat.gz後解壓, 并将檔案路徑配置到source中即可。

translate,用于檢測某字段的值是否符合條件,如果符合條件則将其翻譯成新的值,寫入一個新的字段,比對pattern可以通過yaml檔案來配置。例如,在下面的配置中,我們對request_api字段翻譯成更加易懂的文字描述。

創業公司如何做資料分析(四)ELK日志系統
創業公司如何做資料分析(四)ELK日志系統

<b>elasticsearch</b>

elasticsearch承載了資料存儲和查詢的功能,其基礎概念和使用方法可以參考另一篇博文elasticsearch使用總結,這裡主要介紹些實際生産中的問題和方法:

關于叢集配置,重點關注三個參數:

第一,discovery.zen.ping.unicast.hosts,elasticsearch預設使用zen discovery來做節點發現機制,推薦使用unicast來做通信方式,在該配置項中列舉出master節點。

第二,discovery.zen.minimum_master_nodes,該參數表示叢集中可工作的具有master節點資格的最小數量,預設值是1。為了提高叢集的可用性,避免腦裂現象(所謂腦裂,就是同一個叢集中的不同節點,對叢集的狀态有不一緻的了解。),官方推薦設定為(n/2)+1,其中n是具有master資格的節點的數量。

第三,discovery.zen.ping_timeout,表示節點在發現過程中的等待時間,預設值是3秒,可以根據自身網絡環境進行調整,一定程度上提供可用性。

<b>關于叢集節點</b>,第一,節點類型包括:候選master節點、資料節點和client節點。通過設定兩個配置項node.master和node.data為true或false,來決定将一個節點配置設定為什麼類型的節點。第二,盡量将候選master節點和data節點分離開,通常data節點負載較重,需要考慮單獨部署。

<b>關于記憶體</b>,elasticsearch預設設定的記憶體是1gb,對于任何一個業務部署來說,這個都太小了。通過指定es_heap_size環境變量,可以修改其堆記憶體大小,服務程序在啟動時候會讀取這個變量,并相應的設定堆的大小。建議設定系統記憶體的一半給elasticsearch,但是不要超過32gb。參考官方文檔。

<b>關于硬碟空間</b>,elasticsearch預設将資料存儲在/var/lib/elasticsearch路徑下,随着資料的增長,一定會出現硬碟空間不夠用的情形,此時就需要給機器挂載新的硬碟,并将elasticsearch的路徑配置到新硬碟的路徑下。通過“path.data”配置項來進行設定,比如“path.data: /data1,/var/lib/elasticsearch,/data”。需要注意的是,同一分片下的資料隻能寫入到一個路徑下,是以還是需要合理的規劃和監控硬碟的使用。

<b>關于index的劃分和分片的個數</b>,這個需要根據資料量來做權衡了,index可以按時間劃分,比如每月一個或者每天一個,在logstash輸出時進行配置,shard的數量也需要做好控制。

<b>關于監控</b>,筆者使用過head和marvel兩個監控插件,head免費,功能相對有限,marvel現在需要收費了。另外,不要在資料節點開啟監控插件。

<b>kibana</b>

kibana提供的是資料查詢和顯示的web服務,有豐富的圖表樣闆,能滿足大部分的資料可視化需求,這也是很多人選擇elk的主要原因之一。ui的操作沒有什麼特别需要介紹的,經常使用就會熟練,這裡主要介紹經常遇到的三個問題。

<b>1. 查詢文法</b>

在kibana的discover頁面中,可以輸入一個查詢條件來查詢所需的資料。查詢條件的寫法使用的是elasticsearch的query string文法,而不是query dsl,參考官方文檔query-string-syntax,這裡列舉其中部分常用的:

單字段的全文檢索,比如搜尋args字段中包含first的文檔,寫作 args:first;

單字段的精确檢索,比如搜尋args字段值為first的文檔,寫作 args: “first”;

多個檢索條件的組合,使用 not, and 和 or 來組合,注意必須是大寫,比如 args:(“first” or “second”) and not agent: “third”;

字段是否存在,_exists_:agent表示要求agent字段存在,_missing_:agent表示要求agent字段不存在;

通配符:用 ? 表示單字母,* 表示任意個字母。

<b>2. 錯誤“discover: request timeout after 30000ms”</b>

這個錯誤經常發生在要查詢的資料量比較大的情況下,此時elasticsearch需要較長時間才能傳回,導緻kibana發生timeout報錯。解決這個問題的方法,就是在kibana的配置檔案中修改elasticsearch.requesttimeout一項的值,然後重新開機kibana服務即可,注意機關是ms。

<b>3. 疑惑“字元串被分解了”</b>

經常在qq群裡看到一些人在問這樣一個問題:為什麼查詢結果的字段值是正确的,可是做圖表時卻發現字段值被分解了,不是想要的結果?如下圖所示的client_agent_info字段。

創業公司如何做資料分析(四)ELK日志系統

得到這樣一個不正确結果的原因是使用了analyzed字段來做圖表分析,預設情況下elasticsearch會對字元串資料進行分析,建立反向索引,是以如果對這麼一個字段進行terms聚合,必然會得到上面所示的錯誤結果了。那麼應該怎麼做才對?預設情況下,elasticsearch還會建立一個相對應的沒有被analyzed的字段,即帶“.raw”字尾的字段,在這樣的字段上做聚合分析即可。

又會有很多人問這樣的問題:為什麼我的elasticsearch沒有自動建立帶“.raw”字尾的字段?然而在logstash中輸出資料時,設定index名稱字首為“logstash-”就有了這個字段。這個問題的根源是elasticsearch的dynamic template在搗鬼(可以檢視博文elasticsearch使用總結中的詳細介紹),dynamic temlate用于指導elasticsearch如何為插入的資料自動建立schema映射關系。

預設情況下,logstash會在elasticsearch中建立一個名為“logstash”的模闆,所有字首為“logstash-”的index都會參照這個模闆來建立映射關系,在該模闆中申明了要為每個字元串資料建立一個額外的帶“.raw”字尾的字段。可以向elasticsearch來查詢你的模闆,使用api:get http://localhost:9200/_template。

以上便是對elk日志系統的總結介紹,還有一個重要的功能沒有提到,就是如何将日志資料與自身産品業務的資料融合起來。

舉個例子,在nginx日志中,通常會包含api請求通路時攜帶的使用者token資訊,由于token是有時效性的,我們需要及時将這些token轉換成真實的使用者資訊存儲下來。

這樣的需求通常有兩種實作方式,一種是自己寫一個logstash filter,然後在logstash處理資料時調用;另一種是将logstash indexer産生的資料再次輸出到消息隊列中,由我們自己的腳本程式從消息隊列中取出資料,做相應的業務處理後,輸出到elasticsearch中。目前,團隊對ruby技術棧不是很熟悉,是以我們采用了第二種方案來實施。

目前,我們的資料增長相對緩慢,遇到的問題也有限,随着資料量的增加,未來一定會遇到更多的挑戰,也可以進一步探索elk。

<b>作者:mr-bruce來源:36大資料</b>

點選檢視:<b></b>

<a href="https://yq.aliyun.com/articles/73497" target="_blank">創業公司如何做資料分析(一)開篇</a>

<a href="https://yq.aliyun.com/articles/73618" target="_blank">創業公司如何做資料分析(二)營運資料系統</a>

<a href="https://yq.aliyun.com/articles/73671" target="_blank">創業公司如何做資料分析(三)使用者行為資料采集系統</a>

<a href="https://yq.aliyun.com/articles/73762" target="_blank">創業公司如何做資料分析(五)微信分享追蹤系統</a>

<a href="https://yq.aliyun.com/articles/73818" target="_blank">創業公司如何做資料分析(六)資料倉庫的建設</a>

繼續閱讀