===================================
(接上文:《架構設計:系統間通訊(32)——其餘消息中間件及場景應用(下2)》)html
以上兩種方案中爲了讓業務系統可以集成日誌採集功能,咱們或多或少須要在業務系統端編寫一些代碼。雖然經過一些代碼結構的設計,能夠減小甚至徹底隔離這些代碼和業務代碼的耦合度,可是畢竟須要業務開發團隊花費精力對這些代碼進行維護,業務系統部署時業務對這些代碼的配置信息作相應的調整。前端
這裏咱們再爲讀者介紹一種非侵入式的日誌採集方案。咱們都知道業務系統被訪問時,都會產生一些訪問痕跡。 一樣以「瀏覽商品詳情」這個場景爲例,當訪問者打開一個「商品詳情」頁面時(URL記爲A),那麼首先Nginx的access日誌就會有相應的80端口的訪問日誌,若是「商品詳情」的信息並不是全靜態的,那麼接下來業務服務上工做的代碼還會在Log4j文件上輸出相應的訪問信息(若是開發人員使用了Log4j的話)。咱們要作的事情就是找一款軟件,將這些日誌信息收集起來並存放在合適的位置,以便數據分析平臺隨後利用這些數據進行分析工做。web
固然爲了保證這些日誌信息中有完整的原始屬性,業務系統的開發人員和運維人員應該事先協調一種雙方都承認的日誌描述格式,以及日誌文件的存儲位置和存儲規則等信息。apache
Flume is a distributed, reliable, and available service for efficiently collecting, aggregating, and moving large amounts of log data. It has a simple and flexible architecture based on streaming data flows. It is robust and fault tolerant with tunable reliability mechanisms and many failover and recovery mechanisms. It uses a simple extensible data model that allows for online analytic application.設計模式
以上文字引用來自Apache Flume官網(http://flume.apache.org/)。大意是:Flume是一個分佈式的、具備高可靠的、高可用性的用於有效地收集、彙總日誌數據的服務。它的架構基於數據流,簡單靈活。。。咱們要介紹的非侵入日誌採集方案,就基於Apache Flume進行實現。服務器
Apache Flume很是很是簡單,而且官方給出的用戶手冊已經足夠您瞭解它的使用方式和工做原理(http://flume.apache.org/FlumeUserGuide.html),因此本文並不會專門介紹Flume的安裝和基本使用,並試着將Flume的使用融入到實例講解中。若是您但願更深刻學習Flume的設計實現,筆者仍是創建您閱讀Flume的源代碼,在其官網的用戶文檔中已經給出了幾個關鍵的實現類,經過這些實現類便可倒查Flume使用的各類設計模式:網絡
Flume和業務服務系統在物理服務器上分別獨立工做,在操做系統層面上是兩個獨立的進程,並無任何關聯。Flume只對操做系統上的文件系統、或者指定的網絡端口又或者RPC服務進行數據流監控(Flume中稱之爲Source)。當指定的文件、指定的網絡端口或者指定的RPC服務有新的數據產生時,Flume就會按照預先的配置將這些數據傳輸到指定位置(Flume中稱之爲Sink)。這個指定位置能夠是網絡地址、能夠是文件系統還能夠是另外一個軟件。Source和Sink之間的數據流傳輸通告,稱之爲Channel。架構
上圖來源於Apache Flume官方網站,是一個關於Flume中Source、Sink的例子。在這個例子中,Flume採用一個HTTP Source,用來接收外部傳來的HTTP協議的數據;Flume的Sink端採用HDFS Sink,用來將從Channel中獲得的數據寫入HDFS。那麼基於上文介紹的Apache Flume工做特性,咱們採用以下思路進行日誌採集方案三的設計:app
上圖中業務系統工做在140、14一、142三個物理節點上,併產生Log4j文件。固然您也能夠直接使用JBOSS、Tomcat等服務的原生日誌文件做爲日誌數據來源。有的狀況下,咱們須要對Nginx等代理服務上Http請求狀況進行分析,那麼可使用Nginx的access.log文件做爲日誌數據的源是來源。您還能夠根據設計須要,在每個物理節點上同時監控多個文件。負載均衡
在140、14一、142三個物理節點上,還分別安裝了Apache Flume。他們的工做任務都是同樣的,即從指定的須要監控的日誌文件中讀取數據變化,經過配置好的Channel送到指定的Sink中。在上圖的設置中既是監控Log4j文件的變化,經過Channel使用Thrift RPC方式傳輸到遠程服務器192.168.61.138的6666端口。
物理節點192.168.61.138負責收集來自於140、14一、142三個物理節點經過Thrift RPC傳輸到6666端口的日誌數據信息。而且經過Channel傳輸到適當的存儲方案中,這些適當的存儲方案多是HDFS、多是某一種MQ還多是某種對象存儲系統(例如Ceph)、甚至可能就是本地文件系統。
上文已經說明,192.168.61.140物理節點上Apache Flume的主要任務是監控業務服務的Log4j日誌文件,當日志文件產生新的數據時,經過Flume中已經配置好的Channel發送至指定的Sink。配置信息以下:
agent.sources = s1
agent.channels = c1
agent.sinks = t1
# source ===========================
# log4j.log文件的變化將做爲flume的源
agent.sources.s1.type = exec
agent.sources.s1.channels = c1
agent.sources.s1.command = tail -f /logs/log4j.log
# channel ==================================
# 鏈接source和sink的通道
agent.channels.c1.type = memory
agent.channels.c1.capacity = 1000
# sink t1 ===================================
# 經過通道送來的數據,將經過 thrift RPC調用,送到138節點的6666端口
agent.sinks.t1.type = thrift
agent.sinks.t1.channel = c1
agent.sinks.t1.hostname = 192.168.61.138
agent.sinks.t1.port = 6666
192.168.61.141和192.168.61.142兩個物理節點也承載了業務服務,而且業務服務會將日誌輸出到一樣的Log4j的位置。因此這兩個節點上Apache Flume的配置和以上140物理節點中Apache Flume的配置一致。這裏就再也不對另外兩個物理節點的配置進行贅述了。
另外須要注意的是agent.sources.s1.command配置的Linux tail 命令。tail命令能夠顯示當前文件的變化狀況,若是您只代有-f參數,即表示從文件末尾的最後10行開始對文件的變化狀況進行監控。若是這樣配置,那麼當Flume啓動時,就會認爲Log4j文件中已經存在的10行記錄爲新收到的日誌數據,形成誤發。
要解決這個問題可使用-n參數,並指定從文件的最末尾開始監控文件變化狀況:
# 應該使用
tail -f -n 0 /logs/log4j.log
# 注意:tail -f /logs/log4j.log 命令至關於:
# tail -f -n 10 /logs/log4j.log
192.168.61.138節點上的Flume,用來收集140-142節點經過Thrift RPC傳來的日誌數據。這些數據收集後,將被138節點上的Flume存放到合適的位置。這些位置能夠是HDFS,HBASE、本地文件系統還能夠是Apache Kafka等。
agent.sources = s1
agent.channels = c1
agent.sinks = t1
# thrift ==================
# 使用thrift rpc監聽節點的6666端口,以便接收數據
agent.sources.s1.type = thrift
agent.sources.s1.channels = c1
agent.sources.s1.bind = 0.0.0.0
agent.sources.s1.port = 6666
# sink hdfs ==============
# agent.sinks.t1.type = hdfs
# agent.sinks.t1.channel = c1
# agent.sinks.t1.hdfs.path = hdfs://ip:port/events/%y-%m-%d/%H%M/%S
# agent.sinks.t1.hdfs.filePrefix = events-
# agent.sinks.t1.hdfs.round = true
# agent.sinks.t1.hdfs.roundValue = 10
# agent.sinks.t1.hdfs.roundUnit = minute
# sink=====================
# 爲了檢測整個配置是否正確,可先輸出到控制檯
agent.sinks.t1.type = logger
agent.sinks.t1.channel = c1
# channel=================
agent.channels.c1.type = memory
agent.channels.c1.capacity = 1000
以上配置文件中,爲了查看這個採集系統的配置是否成功,咱們將在Flume控制檯做爲Sink進行輸出。註釋的信息是HDFS做爲Sink的配置。
上一小節的解決方案三中,最薄弱的位置是承擔日誌數據彙總任務的138節點。整個日誌收集主架構中只存在一個這樣的彙總節點,一旦138節點因爲各類緣由宕機主架構就將崩潰。即便138節點可以穩定工做,因爲138節點同時承擔多個物理節點傳來的數據日誌,那麼它也極有可能成爲性能瓶頸。因此咱們須要找到一種方案三中薄弱位置的辦法。
還好,Apache Flume爲咱們提供了很是簡單實用的高可用模式:Load_balance模式和Failover模式。這兩種工做模式都是對多個Sink如何配合工做進行描述:
這種工做模式提供了多個sinks負載均衡的能力。Load_balance會維護一個active sinks列表,基於這個列表,使用round_robin(輪詢調度) 或者 random(隨機) 的選擇機制(默認爲:round_robin),向sinks集合。基本上這兩種選擇方式已經夠用了,若是您對調度選擇有特別的要求,則能夠經過繼承AbstractSinkSelector類來實現自定義的選擇機制。
這種工做模式提供了多個sinks的故障轉移能力。Failover維護了兩個sinks列表,Failover list和Live list,在Failover模式下,Flume會優先選擇優先級最高的Sink做爲主要的發送目標。當這個Sink連續失敗時Flume會把這個Sink移入Failover list,而且設置一個冷凍時間。在這個冷凍時間以後,Flume又會試圖使用這個Sink發送數據,一旦發送成功,這個Sink會被從新移入Live list。
爲了保證可以爲數據彙總節點分擔性能壓力,咱們使用Load_balance模式進一步演示對數據彙總節點的優化。
從上圖中能夠看到在方案三的優化方法中,咱們使用一個新的節點(192.168.61.139)和原有的138節點一塊兒構成一組負載節點,共同承擔日誌數據的彙總任務。那麼前端日誌監控節點(140、14一、142三個節點)也須要作相應的配置文件修改。
agent.sources = s1
agent.channels = c1
# 設置了兩個sink
agent.sinks = lt1 lt2
agent.sinkgroups = g1
# source ===========================
# 數據源仍是來自於log4j日誌文件的新增數據
agent.sources.s1.type = exec
agent.sources.s1.channels = c1
agent.sources.s1.command = tail -f -n 0 /log/log4j.log
# sink lt1 ===================================
agent.sinks.lt1.type = thrift
agent.sinks.lt1.channel = c1
agent.sinks.lt1.hostname = 192.168.61.138
agent.sinks.lt1.port = 6666
# sink lt2 ==================================
agent.sinks.lt2.type = thrift
agent.sinks.lt2.channel = c1
agent.sinks.lt2.hostname = 192.168.61.139
agent.sinks.lt2.port = 6666
# channel ==================================
agent.channels.c1.type = memory
agent.channels.c1.capacity = 1000
# sinkgroup ===============================
# 兩個sink:lt1 lt2 設置成一組sink。並使用load_balance模式進行工做
agent.sinkgroups.g1.sinks = lt1 lt2
agent.sinkgroups.g1.processor.type = load_balance
agent.sinkgroups.g1.processor.backoff = true
agent.sinkgroups.g1.processor.selector = random
141和142兩個日誌數據監控節點的配置和140節點的配置一致,因此一樣再也不贅述了。
agent.sources = s1
agent.channels = c1
agent.sinks = t1
# thrift==================
agent.sources.s1.type = thrift
agent.sources.s1.channels = c1
agent.sources.s1.bind = 0.0.0.0
agent.sources.s1.port = 6666
# sink=====================
agent.sinks.t1.type = logger
agent.sinks.t1.channel = c1
# channel=================
agent.channels.c1.type = memory
agent.channels.c1.capacity = 1000
新增的139節點上Flume的配置信息和原有138節點上Flume的配置信息是一致的。這樣保證了不管日誌數據被髮送到哪個節點,都能正確進行存儲。
日誌採集方案三也存在侷限性:這種方案不適合用於開放性日誌採集系統。也就是說,若是您的日誌採集系統須要像「百度站長統計工具」那樣,從設計之初的目標就是要發佈給互聯網上各個站點使用的。那麼這種基於操做系統日誌變化,並採用第三方軟件完成採集過程的架構方案就不適用。
另外,方案三咱們使用了Thrift RPC進行網絡通信。這個方式是能夠用於真正的生產環境的,可是須要進行更多的配置項指定。如下兩個連接地址是分別是使用thrift做爲source和sink時可使用的配置屬性。
http://flume.apache.org/FlumeUserGuide.html#thrift-source
http://flume.apache.org/FlumeUserGuide.html#thrift-sink
除了Thrift RPC之外,筆者還推薦使用Avro。
//TODO 這是一個釦子,後續的文章會講到
通過《架構設計:系統間通訊(19)——MQ:消息協議(上)》開始的14篇文章,咱們基本上介紹了消息隊列的基本知識和使用實戰。從下文開始咱們轉向ESB企業服務總線的知識講解。