ELK轉EFK

背景

做爲中國最大的在線教育站點,目前滬江日誌服務的用戶包含網校,交易,金融,CCTalk 等多個部門的多個產品的日誌搜索分析業務,每日產生的各種日誌有好十幾種,天天處理約10億條(1TB)日誌,熱數據保留最近7天數據,冷數據永久保存。node

爲何作日誌系統

首先,什麼是日誌? 日誌就是程序產生的,遵循必定格式(一般包含時間戳)的文本數據nginx

一般日誌由服務器生成,輸出到不一樣的文件中,通常會有系統日誌、 應用日誌、安全日誌。這些日誌分散地存儲在不一樣的機器上。json

一般當系統發生故障時,工程師須要登陸到各個服務器上,使用 grep / sed / awk 等 Linux 腳本工具去日誌裏查找故障緣由。在沒有日誌系統的狀況下,首先須要定位處理請求的服務器,若是這臺服務器部署了多個實例,則須要去每一個應用實例的日誌目錄下去找日誌文件。每一個應用實例還會設置日誌滾動策略(如:天天生成一個文件),還有日誌壓縮歸檔策略等。瀏覽器

這樣一系列流程下來,對於咱們排查故障以及及時找到故障緣由,形成了比較大的麻煩。所以,若是咱們能把這些日誌集中管理,並提供集中檢索功能,不只能夠提升診斷的效率,同時對系統狀況有個全面的理解,避免過後救火的被動。安全

我認爲,日誌數據在如下幾方面具備很是重要的做用:服務器

  • 數據查找:經過檢索日誌信息,定位相應的 bug ,找出解決方案網絡

  • 服務診斷:經過對日誌信息進行統計、分析,瞭解服務器的負荷和服務運行狀態架構

  • 數據分析:能夠作進一步的數據分析,好比根據請求中的課程 id ,找出 TOP10 用戶感興趣課程。併發

針對這些問題,爲了提供分佈式的實時日誌蒐集和分析的監控系統,咱們採用了業界通用的日誌數據管理解決方案 - 它主要包括 Elasticsearch 、 Logstash 和 Kibana 三個系統。一般,業界把這套方案簡稱爲ELK,取三個系統的首字母,可是咱們實踐以後將其進一步優化爲EFK,F表明Filebeat,用以解決Logstash致使的問題。下面,咱們展開詳細介紹。app

文中涉及的 ELK stack 版本是:

Elasticsearch 5.2.2Logstash 5.2.2Kibana 5.2.2Filebeat 5.2.2Kafka 2.10

Logstash :數據收集處理引擎。支持動態的從各類數據源蒐集數據,並對數據進行過濾、分析、豐富、統一格式等操做,而後存儲以供後續使用。

Kibana :可視化化平臺。它可以搜索、展現存儲在 Elasticsearch 中索引數據。使用它能夠很方便的用圖表、表格、地圖展現和分析數據。

Elasticsearch :分佈式搜索引擎。具備高可伸縮、高可靠、易管理等特色。能夠用於全文檢索、結構化檢索和分析,並能將這三者結合起來。Elasticsearch 基於 Lucene 開發,如今使用最廣的開源搜索引擎之一,Wikipedia 、StackOverflow、Github 等都基於它來構建本身的搜索引擎。

Filebeat :輕量級數據收集引擎。基於原先 Logstash-fowarder 的源碼改造出來。換句話說:Filebeat就是新版的 Logstash-fowarder,也會是 ELK Stack 在 shipper 端的第一選擇。

既然要談 ELK 在滬江系統中的應用,那麼 ELK 架構就不得不談。本次分享主要列舉咱們曾經用過的 ELK 架構,並討論各類架構所適合的場景和優劣供你們參考

簡單版架構

image

這種架構下咱們把 Logstash 實例與 Elasticsearch 實例直接相連。Logstash 實例直接經過 Input 插件讀取數據源數據(好比 Java 日誌, Nginx 日誌等),通過 Filter 插件進行過濾日誌,最後經過 Output 插件將數據寫入到 ElasticSearch 實例中。

這個階段,日誌的收集、過濾、輸出等功能,主要由這三個核心組件組成 Input 、Filter、Output

Input:輸入,輸入數據能夠是 File 、 Stdin(直接從控制檯輸入) 、TCP、Syslog 、Redis 、Collectd 等

Filter:過濾,將日誌輸出成咱們想要的格式。Logstash 存在豐富的過濾插件:Grok 正則捕獲、時間處理、JSON 編解碼、數據修改 Mutate 。Grok 是 Logstash 中最重要的插件,強烈建議每一個人都要使用 Grok Debugger 來調試本身的 Grok 表達式

grok {
      match => ["message", "(?m)\[%{LOGLEVEL:level}\] \[%{TIMESTAMP_ISO8601:timestamp}\] \[%{DATA:logger}\] \[%{DATA:threadId}\] \[%{DATA:requestId}\] %{GREEDYDATA:msgRawData}"]
    }

Output:輸出,輸出目標能夠是 Stdout (直接從控制檯輸出)、Elasticsearch 、Redis 、TCP 、File 等

這是最簡單的一種ELK架構方式,Logstash 實例直接與 Elasticsearch 實例鏈接。優勢是搭建簡單,易於上手。建議供初學者學習與參考,不能用於線上的環境。

集羣版架構

image

這種架構下咱們採用多個 Elasticsearch 節點組成 Elasticsearch 集羣,因爲 Logstash 與 Elasticsearch 採用集羣模式運行,集羣模式能夠避免單實例壓力太重的問題,同時在線上各個服務器上部署 Logstash Agent,來知足數據量不大且可靠性不強的場景。

數據收集端:每臺服務器上面部署 Logstash Shipper Agent 來收集當前服務器上日誌,日誌通過 Logstash Shipper 中 Input插件、Filter插件、Output 插件傳輸到 Elasticsearch 集羣

數據存儲與搜索:Elasticsearch 配置默認便可知足,同時咱們看數據重要性來決定是否添加副本,若是須要的話,最多一個副本便可

數據展現:Kibana 能夠根據 Elasticsearch 的數據來作各類各樣的圖表來直觀的展現業務實時情況

這種架構使用場景很是有限,主要存在如下兩個問題

  • 消耗服務器資源:Logstash 的收集、過濾都在服務器上完成,這就形成服務器上佔用系統資源較高、性能方面不是很好,調試、跟蹤困難,異常處理困難

  • 數據丟失:大併發狀況下,因爲日誌傳輸峯值比較大,沒有消息隊列來作緩衝,就會致使 Elasticsearch 集羣丟失數據

這個架構相對上個版本略微複雜,不過維護起來一樣比較方便,同時能夠知足數據量不大且可靠性不強的業務使用。

引入消息隊列

image

該場景下面,多個數據首先經過 Lostash Shipper Agent 來收集數據,而後通過 Output 插件將數據投遞到 Kafka 集羣中,這樣當遇到 Logstash 接收數據的能力超過 Elasticsearch 集羣處理能力的時候,就能夠經過隊列就能起到削峯填谷的做用, Elasticsearch 集羣就不存在丟失數據的問題。

目前業界在日誌服務場景中,使用比較多的兩種消息隊列爲 :Kafka VS Redis。儘管 ELK Stack 官網建議使用 Redis 來作消息隊列,可是咱們建議採用 Kafka 。主要從下面兩個方面考慮:

  • 數據丟失:Redis 隊列多用於實時性較高的消息推送,並不保證可靠。Kafka保證可靠但有點延時

  • 數據堆積:Redis 隊列容量取決於機器內存大小,若是超過設置的Max memory,數據就會拋棄。Kafka 的堆積能力取決於機器硬盤大小。

綜合上述的理由,咱們決定採用 Kafka 來緩衝隊列。不過在這種架構下仍然存在一系列問題

  • Logstash shipper 收集數據一樣會消耗 CPU 和內存資源

  • 不支持多機房部署

這種架構適合較大集羣的應用部署,經過消息隊列解決了消息丟失、網絡堵塞的問題。

多機房部署

image

隨着滬江業務的飛速增加,單機房的架構已經不能知足需求。不可避免的,滬江的業務須要分佈到不一樣機房中,對於日誌服務來講也是不小的挑戰。固然業界也有很多成熟的方法,好比阿里的單元化、騰訊的 SET 方案等等。單元化在這邊不詳細展開,你們能夠參考微博的【單元化架構】

最終咱們決定採用單元化部署的方式來解決 ELK 多機房中遇到的問題(延時、專線流量過大等),從日誌的產生、收集、傳輸、存儲、展現都是在同機房裏面閉環消化,不存在跨機房傳輸與調用的問題。由於交互緊密的應用盡可能部署在同機房,因此這種方案並不會給業務查詢形成困擾。

Logstash、Elasticsearch、Kafka、Kibana 四個集羣都部署到同一機房中,每一個機房都要每一個機房本身的日誌服務集羣,好比A機房業務的日誌只能傳輸給本機房 Kafka ,而A機房 Indexer 集羣消費並寫入到A機房 Elasticsearch 集羣中,並由A機房 Kibana 集羣展現,中間任何一個步驟不依賴B機房任何服務。

引入Filebeat

image

Filebeat 是基於原先 logstash-forwarder 的源碼改造出來的,無需依賴 Java 環境就能運行,安裝包10M不到。

若是日誌的量很大,Logstash 會遇到資源佔用高的問題,爲解決這個問題,咱們引入了Filebeat。Filebeat 是基於 logstash-forwarder 的源碼改造而成,用 Golang 編寫,無需依賴 Java 環境,效率高,佔用內存和 CPU 比較少,很是適合做爲 Agent 跑在服務器上。

下面看看Filebeat的基本用法。編寫配置文件,從 Nginx access.log 中解析日誌數據

# filebeat.ymlfilebeat.prospectors:
- input_type: log
  paths: /var/log/nginx/access.log
  json.message_key:

output.elasticsearch:
  hosts: ["localhost"]
  index: "filebeat-nginx-%{+yyyy.MM.dd}"

咱們來看看壓測數據

壓測環境

  • 虛擬機 8 cores 64G內存 540G SATA盤

  • Logstash 版本 2.3.1

  • Filebeat 版本 5.5.0

壓測方案

Logstash / Filebeat 讀取 350W 條日誌 到 console,單行數據 580B,8個進程寫入採集文件

壓測結果

項目 workers cpu usr 總共耗時 收集速度
Logstash 8 53.7% 210s 1.6w line/s
Filebeat 8 38.0% 30s 11w line/s

Filebeat 所消耗的CPU只有 Logstash 的70%,但收集速度爲 Logstash 的7倍。從咱們的應用實踐來看,Filebeat 確實用較低的成本和穩定的服務質量,解決了 Logstash 的資源消耗問題。

最後,分享給你們一些血淚教訓,但願你們以我爲鑑。

1. Indexer 運行一段時間後自動掛掉

忽然有一天監控發現日誌不消費了,排查下來發現消費Kafka數據的indexer 掛掉了。因此,Indexer 進程也是須要用 supervisor 來監控的,保證它時刻都在運行。

2. Java異常日誌輸出

開始咱們在經過 grok 切割日誌的時候,發現Java 的 Exception 日誌輸出以後,會出現換行的問題。後來使用 Logstash codec/multiline 插件來解決。

input {
    stdin {
        codec => multiline {
            pattern => "^\["
            negate => true
            what => "previous"
        }
    }
}

3. 因爲時區致使日誌8小時時差

Logstash 2.3版本 date插件配置以下,查看解析結果發現@timestamp比中國時間早了8小時。

解決方案 Kibana 讀取瀏覽器的當前時區,而後在頁面上轉換時間內容的顯示。

  date {
    match => [ "log_timestamp", "YYYY-MM-dd HH:mm:ss.SSS" ]
    target => "@timestamp"
  }

4.Grok parse failure

咱們遇到線上node日誌忽然有幾天日誌查看不出來。後來拉出原始日誌對比才發現生成出來的日誌格式不正確,同時包含 JSON 格式和非 JSON格式的日誌。可是咱們用grok解析的時候採用是json格式。建議你們輸出日誌保證格式一致同時不要出現空格等異常字符,可使用在線grok debug (http://grokdebug.herokuapp.com/) 來調試正則。

總結

基於 ELK stack 的日誌解決方案的優點主要體現於

  • 可擴展性:採用高可擴展性的分佈式系統架構設計,能夠支持每日 TB 級別的新增數據。

  • 使用簡單:經過用戶圖形界面實現各類統計分析功能,簡單易用,上手快

  • 快速響應:從日誌產生到查詢可見,能達到秒級完成數據的採集、處理和搜索統計。

  • 界面炫麗:Kibana 界面上,只須要點擊鼠標,就能夠完成搜索、聚合功能,生成炫麗的儀表板

相關文章
相關標籤/搜索