rsyslog研究


第零章 綜述

最近因為工作需要研究了rsyslog,主要是把官網的文檔看了一遍,因為學習的過程中,發現中文資料很少,所以研究的差不多以后,決定拿出來分享一下。

rsyslog官網的文檔還是挺爛的(在我看完后,官網有了一次改版,可能好一些了),尤其是配置文件部分,每個版本都有改動,但是官網只有最新版本的參數介紹,好幾次我按照文檔的參數寫配置文件,或者報錯,或者參數不起作用,因此大家使用哪個版本的rsyslog,最好是下個該版本的源代碼,以供核查參數是否准確。

本文的結構,來自我的內部分享。

使用的rsyslog版本為:7.2.5

第一章 rsyslog整體架構

我主要使用rsyslog來保證日志的可靠性傳輸,日志中心宕機,client端可以本地保存日志,因此rsyslog與數據庫結合方面的知識在文章中沒有涉及。

Rsyslog架構,這是rsyslog官網上的一張圖,用來介紹rsyslog的架構,rsyslog的消息流是從輸入模塊->預處理模塊->主隊列->過濾模塊->執行隊列->輸出模塊。

在這個流程圖中,輸入、輸出、過濾三個部分稱為module,輸入模塊有imklg、imsock、imfile。輸出模塊有omudp、omtcp、omfile、omprog、ommysql、omruleset(后兩者我沒有研究,本文不會涉及)。過濾模塊研究不多,只會提到mmnormalize。

預處理模塊主要解決各種syslog協議實現間的差異,舉例說明如果日志系統client端使用rsyslog、server端使用syslog-ng,如果自己不做特殊處理syslog-ng是無法識別的。但是反過來,rsyslog的server端就可以識別syslog-ng發過來的消息。

Input模塊包括imklg、imsock、imfile、imtcp等,是消息來源。

Filetr模塊處理消息的分析和過濾,rsyslog可以根據消息的任何部分進行過濾,后面會介紹到具體的做法。

Output模塊包括omfile、omprog、omtcp、ommysql等。是消息的目的地。

Queue模塊負責消息的存儲,從Input傳入的未經過濾的消息放在主隊列中,過濾后的消息放入到不同action queue中,再由action queue送到各個輸出模塊。

1.1啟動參數

正常啟動:指定-f和-i就可以了,新版本不需要-c 5 這樣的參數。

rsyslogd -f /root/rsyslog_worker_dir/rsyslog.conf -i /root/rsyslog_worker_dir/rsyslog.pid

debug版本:debug消息會輸出到標注輸出,如果出現未預期的結果,可以嘗試使用debug方式,查看處理流程

rsyslogd -f /root/rsyslog_worker_dir/rsyslog.conf -i /root/rsyslog_worker_dir/rsyslog.pid -dn >debuglog

測試配置文件是否正確:

rsyslogd -N1 -f file

第二章 rsyslog的概念

2.1屬性替代

Rsyslog 預定義了一些屬性,來代表消息中的信息,我們可以在定義輸出格式、動態文件名的時候使用到這些屬性。這里面比較重要的屬性比如:msg(消息體)、hostname、pri(消息等級和類別)、time(時間有關),屬性的名稱中以$開頭的是從本地系統獲得的變量、不帶$是從消息中獲得變量。

屬性替代的語法格式:

%propname:fromChar:toChar:options:fieldname%

屬性替換的功能很強大,你可以使用起始字符獲取自己所需的字段,也可以使用正則表達式,也可以使用分隔符。舉幾個例子:為了兼容一個rfc協議,rsyslog規定如果用戶輸入的msg不是以空格開頭,rsyslog會自動補充一個空格,因此如果你希望輸出的時候去掉這個空格,就可以使用

%msg:2:$%    #選取msg變量中,起始位置為2,終止位置為結尾

我們經常需要根據空格來分析字符串,F表示使用字符分割,32是空格的ascii碼,例:

%msg:F,32:3%  #按照空格分隔,取第三個子串,

正則匹配可以匹配特定的文字和格式,我的正則比較差, 避免了使用這部分的內容,所以這部分沒有例子了。

屬性替代中還用到了一類特殊的以$!開頭的變量,這是使用mmnormalize模塊時特有的,可以實現類似於syslog-ng中parser模塊的功能。后面再講

2.2模板

模板的功能是定義輸出格式,或者定義omfile模塊的動態路徑、動態文件。需要使用上面提到的屬性替換。

模板定義的形式有四種,適用於不同的輸出模塊,一般簡單的格式,可以使用string的形式,復雜的格式,建議使用list的形式,使用list的形式,可以使用一些額外的屬性字段(property statement),例如:position.from、position.end。

如果不指定輸出模板,rsyslog會默認使用RSYSLOG_DEFAULT。

如果你只想輸出msg,可以定義模板

$template  t_msg, “%msg\n%” 

如果想按日期保存輸出,需要使用動態路徑。可以定義模板

$template  f_debug, “/data0/logs/%$year%-%$month%-%$day%/debug.log”

2.3Ruleset

Ruleset實現的是多實例的功能,可以針對syslog的來源使用不同的過濾規則。需要注意的是,在配置文件中需要先定義ruleset,才可以使用。比較典型的一個例子,針對不同的端口使用不同的過濾規則。

$Ruleset tcp1999

$RulesetCreateMainQueue on

Local3.*      @@10.0.0.44:1999

$Ruleset tcp2000

$RulesetCreateMainQueue on

Local4.*      @@10.0.0.44:2000

在定義好ruleset后,各個輸出模塊就可以指定自己使用的ruleset了,具體如何指定,可以查看輸出模塊的手冊,一般會有一個ruleset的參數,用來實現這個功能。

2.4Filter模塊

Rsyslog可以使用syslog標准的過濾規則,同時自己添加了一些擴展。比如可以在輸出中指定rsyslog自己的處理方式,可以指定輸出template,方法是在規則后面添加template的名字,用分號隔開。

例如我們可以編寫一個規則

Local3.*    -/data0/logs/local3.log;t_msg   #在這個輸出中使用t_msg的模板

Local4.*    -?f_local3_test;t_msg         #問號表示要使用模板定義的動態路徑

除了syslog標准的規則,rsyslog的作者還自己開發了一個叫做rainerscript的腳本語言,來定義更復雜的過濾過則,rainerscript可以對屬性進行startwith、contains、%(取余)等過濾規則,例如

If $pri-txt == local3.* and $msg contains “abc” then{  #pri為local3,且在消息中包含子串‘abc’

       *.*   -/data0/logs/local3.log;t_msg

}

還有第三種方式是使用屬性的表示方式,例如

:msg, regex, "^ [g-z]"    /root/rsyslog_worker_dir/2000.log   #以字母g到z開頭的消息,注意msg開頭有個空格

2.5隊列

隊列是rsyslog中比較重要的一個部分,作為使用者,我們需要了解的是隊列的種類:主隊列和工作隊列。從輸入模塊接收的消息會進入主隊列,主隊列中的消息,經過過濾模塊,會進入到相應的工作隊列;隊列的四種工作模式:direct mode、disk mode、FixedArray mode和LinkedList mode,前兩種是磁盤隊列,更可靠,但是性能也較差,后兩種是內存隊列,區別是前者是預分配隊列長度,后者是動態分配,如果你的系統日志流量比較平穩,可以使用預分配隊列,如果日志屬於突發型,可以使用動態隊列。此外,內存隊列還可以通過指定一個queuename來添加DA模式,DA模式主要是為了防止意外情況(進程關閉、server端宕機)下,內存隊列可以不丟失。

通過查看rsyslog的系統命令,可以知道rsyslog對隊列進行大量的可配參數,來定義隊列的行為。可以根據需要來進行優化。

第三章 實例

3.1 Tcp+DA模式實現可靠消息傳輸。

Rsyslog單獨使用了一篇文檔來介紹實現可靠消息傳輸。

首先rsyslog闡述了單獨使用tcp協議的不可靠性,比如server端宕機等等情況。為此如上面介紹隊列時提到的內容,我們需要在client配置一個本地文件,用來在server端宕機這種情況下,暫時保存消息。需要注意的是,隊列名是和過濾規則對應的,一個隊列只能用於一個過濾規則,例:

$ActionQueueType LinkedList

$ActionQueueFileName local3

$ActionResumeRetryCount -1

$ActionQueueSaveOnShutdown on

Local3.*                                            @@10.0.0.44:1999

$ActionQueueType LinkedList

$ActionQueueFileName local4

$ActionResumeRetryCount -1

$ActionQueueSaveOnShutdown on

Local4.*                                            @@10.0.0.44:1999

       此處只是為了說明問題,更簡單的寫法,是把兩條過濾規則寫成一條:local3.*;local4.*。還有一點需要強調的是,本地隊列只有在需要使用的時候才會創建,當后端出現短暫不可用是,rsyslog的內存隊列就可以保存消息,內存隊列不夠用時,才會創建本地隊列。

3.3 mmnormalize模塊

當我們需要定義一個復雜的輸出時,單純使用模板會顯得比較笨拙,這時候我們就可以使用mmnormalize這個模塊來幫助我們簡化模板。例如我們部門本身使用一套日志格式,但是某個重要客戶,需要將他自己的日志按照他所規定的格式保留一份,為此,我們需要定義一個過濾規則,過濾該用戶的日志,然后打散日志,重排,下面我會用模板和mmnormalize兩種方式來解決這個問題。

首先使用模板,我使用list的方式定義:

template(name="t_weiyouxi_rewrite" type="list"){

property(name="msg" field.Delimiter="32" field.Number="2")

constant(value=" ")

property(name="msg" field.delimiter="32" field.number="3")

constant(value=" ")

property(name="msg" field.delimiter="32" field.number="4")

constant(value="us - ")

property(name="msg" field.delimiter="32" field.number="6")

constant(value=" ")

property(name="msg" field.delimiter="32" field.number="7")

constant(value=" \"")

property(name="msg" field.delimiter="34" field.number="2")

constant(value="\"")

property(name="msg" field.delimiter="34" field.number="3")

constant(value="\"")

property(name="msg" field.delimiter="34" field.number="4")

constant(value="\" - \"UTRS1=")

property(name="msg" field.delimiter="34" field.number="7" position.from="2")

constant(value=";U_TRS2=-;SUP=-\" \"")

property(name="msg" field.delimiter="34" field.number="6")

constant(value="\" ")

property(name="hostname")

constant(value="\n")

}

這種方式寫出的模板是很冗長的,下面使用mmnormalize模塊實現,為此,我們需要先定義一個消息格式,來供mmnormalize使用,rulebase.rb:

rule=: %xxxdomain:word% %xxx-ip:ipv4% %xxx-resptime:number% %xxx-cputime:number% [%xxx-timestamp:char-to:]%] malibumytime 819 %xxx-version:number% "%xxx-method:word% %xxx-url:word% %xxx-protocol:char-to:"%" %xxx-retcode:number% %xxx-retsize:number% "%xxx-referer:char-to:"%" "%xxx-ua:char-to:"%" %xxx-cookie:word%

然后,rsyslog的配置文件中,我們可以將以上定義的字段當做屬性來使用(需要以$!開頭),如下:

$mmnormalizeRuleBase /path/to/rulebase.rb

$template t_weiyouxi_rewrite,  "%$!xxxdomain% %$!xxx-ip% %$!xxx-resptime%us - [%$!xxx-timestamp%] \"%$!xxx-method%  %$!xxx-url%  %$!xxx-protocol%\" %$!xxx-retcode% %$!xxx-retsize% \"%$!xxx-referer%\" - \"UTRS1=%$!xxx-cookie%;U_TRS2=-;SUP=-\" \"%$!xxx-ua%\" %hostname%\n"

       可以看出這種方式比使用模板要簡潔清楚多了。不過額外的你需要多使用一個配置文件。

3.4 omprog模塊

如文檔所表述的一樣,omprog可以指定第三方的程序來處理模塊,運行時,第三方的模塊被當做rsyslog的子進程啟動,兩者通過管道通信。此時過濾規則定義的模板,就是子進程的輸入格式。

$ActionOMProgBinary /root/rsyslog_worker_dir/prog/start.sh  #腳本可以保證第三方程序可以使用自己的啟動參數

local3.*          :omprog:;t_msg

3.5額外的測試。

1、測試了imtcp和imptcp的區別,測試了兩者的性能差不多,ptcp略低,這和官網說的ptcp性能更好不一致,可能我還沒有壓到極限,沒有測出真實數據,測試過程中imtcp的cpu使用較高,大概在130%,imptcp的cpu大概在70%左右,可以預見ptcp使用多線程技術,分擔了主線程的壓力。

2、其他部門的同事測試tcp+da可以解決server端宕機的問題,但是如果server端因為io較高,造成阻塞,rsyslog並不能解決這個問題,syslog阻塞是個很嚴重的問題,如果apache直接寫syslog,而syslog阻塞會導致apache無法處理請求。因此必須在server端加監控,如果io較高,就需要優化參數,或者增加server機器了。

3、使用-dn模式來測試mmnormalize模塊,如過mmnormalize沒有收到正確的rulebase,debug文件中會搜索‘unparser’會看到未解析的rulebase字符串,如果解析成功,可以搜索‘gennerate’,可以看到自定義的屬性,在真實消息中的值。

4、rsyslog中的參數有的是全局參數,例如Createmode,有的則是對應於某一ruleset或者某一過濾規則,所以使用前,需要對參數的有效范圍進行測試。

5、如果你希望client和server端都使用rsyslog,那么你不要修改兩者之間的傳輸模板。因為rsyslog 需要根據syslog協議來解析消息,如果你使用t_msg傳輸,那么server端無法識別該消息。

6、同事反饋之前使用syslog-ng時消息超過設置的最大消息長度,會分成兩條發送,rsyslog行為不同,超過設置的最大消息長度,超出部分會丟棄。

7、rsyslog默認會將特殊字符(\t)轉換成#009 由全局配置$EscapeControlCharactersOnReceive 決定,如果自己需要根據\t處理輸出時,需將該選項改為off。

8、配置文件每一行之前,只能包含空格,如果半酣其他字符,rsyslog不能識別該行。

9、使用omprog時,rsyslog通過管道將消息發送給第三方程序, 因此當消息量較大時,第三方程序要具備相應的處理能力,否則很容易造成管道阻塞,導致rsyslog阻塞。這個問題挺嚴重的,我們的經驗是server日志轉發到redis,但是開始的程序處理能力達不到,導致server端的tcp接收隊列阻塞。

3.6 未解決的問題

1、本想測試template和mmlognorm兩種方式那種更快,但是發現ab壓的時候,總是會多出一些輸出日志,不知道是不是壓力太大,導致有retry操作,發生概率大概3%,現有測試數據,兩者的性能差不多。

2、使用 -dn的debug模式,輸出太多,不使用debug模式的輸出又太少,希望找到其他的輸出參數,失敗了,估計要看代碼了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM