Logstash實踐: 分布式系統的日志監控

配圖:中山公園正門街景 攝影: 怡文圣美

文/怡文圣美
2015.11.04

1. 前言

服務端日志你有多重視?

  1. 我們沒有日志
  2. 有日志,但基本不去控制需要輸出的內容
  3. 經常微調日志,只輸出我們想看和有用的
  4. 經常監控日志,一方面幫助日志微調,一方面及早發現程序的問題

只做到第1點的,你可以洗洗去睡了。很多公司都有做到第2點和第3點,這些公司的服務端程序基本已經跑了很長時間了,已比較穩定,確實無需花太多時間去關注。如果一個新產品,在上線初期,我覺得就有必要做到第4點。

日志怎么看?

  1. 都說了,我們沒有日志
  2. 線上日志逐個tail+grep
  3. 編寫腳本,下載某個時間范圍內的全部日志到本地再搜索

tail+grep或者把日志下載下來再搜索,可以應付不多的主機和不多的應用部署場景。但對于多機多應用部署就不合適了。這里的多機多應用指的是同一種應用被部署到幾臺服務器上,每臺服務器上又部署著不同的多個應用。可以想象,這種場景下,為了監控或者搜索某段日志,需要登陸多臺服務器,執行多個tail -Fgrep命令。一方面這很被動。另一方面,效率非常低,數次操作下來,你心情也會變糟。

這篇文章講的就是如何解決分布式系統的日志管理問題。先給大家看看最終的效果:

日志實時監控效果圖

單個屏幕上所有服務器的日志實時滾動著顯示。每條日志開頭還標明日志的來源(下圖)。

每行日志標有來源信息

實現這種效果的原理是后臺跑著一個程序,這個程序負責匯總所有日志到一個本地文件中。只要執行tail -f這個文件就可以做到監控日志了。因為所有日志都匯總在一個文件里了,所以日志搜索的時候只要搜索這一個文件就可以了。

本文介紹的,能夠匯總日志文件的工具名字叫Logstash。使用JRuby編寫,開源,主流,免費,使用簡單。

2. Logstash部署架構

Logstash的理念很簡單,它只做3件事情:

  1. Collect:數據輸入
  2. Enrich:數據加工,如過濾,改寫等
  3. Transport:數據輸出

別看它只做3件事,但通過組合輸入和輸出,可以變幻出多種架構實現多種需求。這里只拋出用以解決日志匯總需求的部署架構圖:

Logstash部署架構

解釋術語:

  • Shipper:日志收集者。負責監控本地日志文件的變化,及時把日志文件的最新內容收集起來,輸出到Redis暫存。
  • Indexer:日志存儲者。負責從Redis接收日志,寫入到本地文件。
  • Broker:日志Hub,用來連接多個Shipper和多個Indexer。

無論是Shipper還是Indexer,Logstash始終只做前面提到的3件事:

  • Shipper從日志文件讀取最新的行文本,經過處理(這里我們會改寫部分元數據),輸出到Redis,
  • Indexer從Redis讀取文本,經過處理(這里我們會format文本),輸出到文件。

一個Logstash進程可以有多個輸入源,所以一個Logstash進程可以應付一臺服務器上的所有日志。Redis是Logstash官方推薦的Broker角色“人選”,支持訂閱發布和隊列兩種數據傳輸模式,推薦使用。輸入輸出支持過濾,改寫。Logstash支持多種輸出源,可以配置多個輸出實現數據的多份復制,也可以輸出到Email,File,Tcp,傳遞給其他程序作為輸入,或者安裝插件實現和其他系統的對接,如搜索引擎Elasticsearch。

總結:Logstash概念簡單,通過組合可以滿足多種需求。

3. Logstash的安裝,搭建和配置

3.1. 安裝Java

下載JDK壓縮包。
一般解壓到/user/local/下,形成/usr/local/jdk1.7.0_79/bin這種目錄結構。
配置JAVA_HOME環境變量:echo 'export JAVA_HOME=/usr/local/jdk1.7.0_79' >> ~/.bashrc

3.2 安裝Logstash

官網下載Logstash的壓縮包。
一般也解壓到/usr/local/下,形成/usr/local/logstash-1.4.3/bin這種目錄結構。

Logstash的運行方式為主程序+配置文件。Collect,Enrich和Transport的行為在配置文件中定義。配置文件的格式有點像json,又有點像php。

3.3. 編寫Shipper角色的配置文件:shipper.conf
input {
    file {
        path => [
            # 這里填寫需要監控的文件
            "/data/log/php/php_fetal.log",
            "/data/log/service1/access.log"
        ]
    }
}

如上,input描述的就是數據如何輸入。這里填寫你需要收集的本機日志文件路徑。

output {
    # 輸出到控制臺
    # stdout { }

    # 輸出到redis
    redis {
        host => "10.140.45.190"   # redis主機地址
        port => 6379              # redis端口號
        db => 8                   # redis數據庫編號
        data_type => "channel"    # 使用發布/訂閱模式
        key => "logstash_list_0"  # 發布通道名稱
    }
}

如上,output描述的就是數據如何輸出。這里描述的是輸出到Redis

data_type的可選值有channellist兩種。用過Redis的人知道,channel是Redis的發布/訂閱通信模式,而list是Redis的隊列數據結構。兩者都可以用來實現系統間有序的消息異步通信。channel相比list的好處是,解除了發布者和訂閱者之間的耦合。舉個例子,一個Indexer在持續讀取Redis中的記錄,現在想加入第二個Indexer,如果使用list,就會出現上一條記錄被第一個Indexer取走,而下一條記錄被第二個Indexer取走的情況,兩個Indexer之間產生了競爭,導致任何一方都沒有讀到完整的日志。channel就可以避免這種情況。這里的Shipper和下面將要提到的Indexer配置文件中都使用了channel

filter {
    mutate {
        # 替換元數據host的值
        replace => ["host", "10.140.46.134 B[1]"]
    }
}

如上,filter描述的是如何過濾數據。mutate是一個自帶的過濾插件,它支持replace操作,可以改寫數據。這里改寫了元數據中的host字段,替換成了我們自己定義的文本。

Logstash傳遞的每條數據都帶有元數據,如@version,@timestamp,host等等。有些可以修改,有些不允許修改。host記錄的是當前的主機信息。Logstash可能不會去獲取主機的信息或者獲取的不準,這里建議替換成自己定義的主機標示,以保證最終的日志輸出可以有完美的格式。

3.4 編寫Indexer角色的配置文件:indexer.conf
input {
    redis { 
        host      => "10.140.45.190"    # redis主機地址
        port      => 6379               # redis端口號
        db        => 8                  # redis數據庫編號
        data_type => "channel"          # 使用發布/訂閱模式
        key       => "logstash_list_0"  # 發布通道名稱
    } 
}

如上,input部分設置為從redis接收數據

output { 
    file { 
        path           => "/data/log/logstash/all.log" # 指定寫入文件路徑
        message_format => "%{host} %{message}"         # 指定寫入格式
        flush_interval => 0                            # 指定刷新間隔,0代表實時寫入
    }
}

如上,output部分設置為寫入本地文件

官方文檔里flush_interval為緩沖時間(單位秒)。我實踐下來不是秒而是數量,Logstash會等待緩沖區寫滿一定數量后才輸出。這對線上調試是不能接受的,建議上線初期設為0。程序穩定后,隨著日志量的增大,可以增大flush_interval的值以提高文件寫入性能。

Indexer的配置文件中,我明確指定了message_format的格式,其中%{host}對應的就是之前手動設置的host元數據。

3.5. 啟動Logstash
# 先在Indexer主機上啟動
nohup /usr/local/logstash-1.4.3/bin/logstash agent -f indexer.conf &>/dev/null &
# 再在Shipper主機上啟動
nohup /usr/local/logstash-1.4.3/bin/logstash agent -f shipper.conf &>/dev/null &
# 最后在Indexer上觀察日志
tail -f /data/log/logstash/all.log

我們來測試一下,切到Shipper主機上,模擬日志產生:

echo "Hello World" >> /data/log/php/php_fetal.log

再切換到Indexer主機上,如果出現:10.140.46.134 B[1] Hello World,說明Logstash部署成功。

3.6. 日志著色腳本

使用awk配合echo,可以匹配你想要高亮的文本并改變他們的前景色和背景色。就像效果圖里的那樣。這里附上我寫的腳本,把腳本中的關鍵信息替換成你想要匹配的文本即可:

tail -f /data/log/logstash/all.log | awk '{ 
     if (match($0, /.*(PHP Deprecated|PHP Notice|PHP Fatal error|PHP Warning|ERROR|WARN).*/)) { print "\033[41;37;1m"$0"\033[0m" } 
else if (match($0, /.*關鍵信息1.*/)) { print "\033[32;1m"$0"\033[0m" } 
else if (match($0, /.*關鍵信息2.*/)) { print "\033[36;1m"$0"\033[0m" }
else { print $0 } }'

So easy,媽媽再也不用擔心我的日志。。。

4. 還有什么

有些公司需要挖掘日志的價值,那僅僅收集和實時顯示是不夠的,需要把逼格上升到日志分析技術層面。

一個完整的日志分析技術棧需要實時收集,實時索引和展示三部分組成,Logstash只是這其中的第一個環節。Logstash所屬的Elastic公司,已經開發了完整的日志分析技術棧,它們是Elasticsearch,Logstash,和Kibana,簡稱ELK。Elasticsearch是搜索引擎,而Kibana是Web展示界面。

日志分析技術棧

如果你搭建了完整的技術棧,你的老板就可以在圖形化界面上按不同的維度去搜索日志了。

Kibana界面

還可以做一些高大上的統計和計算。

Kibana界面

當然,我認為90%的公司是沒有必要這么做的,能做到在控制臺里監控和搜索就能滿足需要了。但我們也可以看看剩下的那10%的公司是怎么做的,比如:新浪是如何分析處理32億條實時日志的?


參考文獻:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • 本期簡說提高軟件產品質量有三個方面需要把握(本篇文章談ELK的使用): 一、持續集成 二、自動化 三、ELK日志分...
    隔壁老田_閱讀 2,489評論 0 2
  • 概述 監控預警平臺, eagle + eye (鷹眼)的合體詞, 寓意可以快速發現問題, 并及時作出響應,Eagl...
    Kungfu貓熊閱讀 7,454評論 0 52
  • //聊聊Flume和Logstash的那些事兒 - 簡書http://www.lxweimin.com/p/349e...
    葡萄喃喃囈語閱讀 5,402評論 1 12
  • 上個周末,我和孩子一起去參加了楊之光美術中心的寫生課。這次的寫生活動安排在上海自然博物館。 這是崽崽...
    solarxue閱讀 1,146評論 0 0