多服務器的日志合並統計
——apache日志cronolog輪循和webalizer的合並統計
作者: 車東
[email protected]
你完全不必耐心地看完下面的所有內容,因為結論無非以下2點:
1 用 cronolog 干淨,安全地輪循apache日志
2 用 sort -m 合並排序多個日志
這篇文章主要根據個人的使用經歷:
1 先介紹apache日志的合並方法;
2 然後根據由此引出的問題說明日志輪循的必要性和解決方法,介紹如何通過cronolog 對apache日志進行輪循;
中間有很多在設計日志合並過程中一些相關工具的使用技巧和一些嘗試的失敗經歷…… 我相信解決以上問題的路徑不止這一條途徑,以下方案肯定不是最簡便或者說成本最低 的,希望能和大家有更多的交流。
{0} 多服務器日志合並統計的必要性:
越來越多大型的WEB服務使用DNS輪循來實現負載均衡:使用多個同樣角色的服務器做前 台的WEB服務,這大大方便了服務的分布規劃和擴展性,但多個服務器的分布使得日志 的分析統計也變得有些麻煩。如果使用webalizer等日志分析工具對每台機器分別做日
志統計:
1 會對數據的匯總帶來很多麻煩,比如:統計的總訪問量需要將SERVER1 SERVER2...上 指定月份的數字相加。
2 會大大影響統計結果中唯一訪客數unique visits,唯一站點數unique sites的等指 標的統計,因為這幾個指標並非幾台機器的代數相加。
統一日志統計所帶來的好處是顯而易見的,但如何把所有機器的統計合並到一個統計結 果裡呢?
首先也許會想:多個服務器能不能將日志記錄到同一個遠程文件裡呢?我們不考慮使用 遠程文件系統記錄日志的問題,因為帶來的麻煩遠比你獲得的方便多的多……
因此,要統計的多個服務器的日志還是:分別記錄=>並通過一定方式定期同步到後台=> 合並=>後用日志分析工具來進行分析。
首先,要說明為什麼要合並日志:因為webalizer沒有將同一天的多個日志合並的功能 先後運行
webalizer log1
webalizer log2
webalizer log3
這樣最後的結果是:只有log3的結果。
能不能將log1< <
因為一個日志的分析工具不是將日志一次全部讀取後進行分析,而且流式的讀取日志並 按一定時間間隔,保存階段性的統計結果。因此時間跨度過大(比如2條日志間隔超過5 分鐘),一些日志統計工具的算法就會將前面的結果“忘掉”。因此, log1< <
{1} 日志合並問題:多個服務的合並統計就是要把日志按時間排序後合並成一個文件 典型的多個日志文件的時間字段是這樣的:
log1 log2 log3
00:15:00 00:14:00 00:11:00
00:16:00 00:15:00 00:12:00
00:17:00 00:18:00 00:13:00
00:18:00 00:19:00 00:14:00
14:18:00 11:19:00 10:14:00
15:18:00 17:19:00 11:14:00
23:18:00 23:19:00 23:14:00
日志合並必須是按時間將多個日志的交叉合並。合並後的日志應該是:
00:15:00 來自log1
00:15:00 來自log2
00:16:00 來自log1
00:17:00 來自log3
00:18:00 來自log2
00:19:00 來自log1
.....
如何合並多個日志文件?
下面以標准的clf格式日志(apache)為例:
apche的日志格式是這樣的:
%h %l %u %t \"%r\" %>s %b
具體的例子:
111.222.111.222 - - [03/Apr/2002:10:30:17 +0800] "GET /index.Html HTTP/1.1" 200 419
最簡單的想法是將日志一一讀出來,然後按日志中的時間字段排序
cat log1 log2 log3 sort -k 4 -t " "
注釋:
-t " ": 日志字段分割符號是空格
-k 4: 按第4個字段排序,也就是:[03/Apr/2002:10:30:17 +0800] 這個字段
-o log_all: 輸出到log_all這個文件中
但這樣的效率比較低,要知道。如果一個服務已經需要使用負載均衡,其服務的單機日 志條數往往都超過了千萬級,大小在幾百M,這樣要同時對多個幾百M的日志進行排序, 機器的負載可想而之……
其實有一個優化的途徑,要知道:即使單個日志本身已經是一個“已經按照時間排好序 “的文件了,而sort對於這種文件的排序合並提供了一個優化合並算法:使用 -m merge合並選項, 因此:合並這樣格式的3個日志文件log1 log2 log3並輸出到log_all中比較好方法是:
sort -m -t " " -k 4 -o log_all log1 log2 log3
注釋:
-m: 使用 merge優化算法
注意:合並後的日志輸出最好壓縮以後再發給webalizer處理
有的系統能處理2G的文件,有的不能。有的程序能處理大於2G的文件,有的不能。盡量 避免大於2G的文件,除非確認所有參與處理的程序和操作系統都能處理這樣的文件。所 以輸出後的文件如果大於2G,最好將日志gzip後再發給webalizer處理:大於2G的文件 分析過程中文件系統出錯的可能性比較大,並且gzip後也能大大降低分析期間的I/O操 作。
日志的按時間排序合並就是這樣實現的。
{2} 日志的輪循機制:
讓我們關心一下數據源問題:webalizer其實是一個按月統計的工具,支持增量統計: 因此對於大型的服務,我可以按天將apache的日志合並後送給webalizer統計。WEB日志 是如何按天(比如每天子夜00:00:00)截斷呢?
如果你每天使用crontab:每天0點准時將日志備份成Access_log_yesterday mv /path/to/apache/log/access_log /path/to/apache/log/access_log_yesterday 的話:你還需要:馬上運行一下:apache restart 否則:apache會因為的日志文件句
柄丟失不知道將日志記錄到哪裡去了。這樣歸檔每天子夜重啟apache服務會受到影響。 比較簡便不影響服務的方法是:先復制,後清空
cp /path/to/apache/log/access_log /path/to/apache/log/access_log_yesterday echo >/path/to/apache/log/access_log
嚴肅的分析員會這樣做發現一個問題:
但cp不可能嚴格保證嚴格的0點截斷。加入復制過程用了6秒,截斷的 access_log_yesterday日志中會出現復制過程到00:00:06期間的日志。對於單個日志統 計這些每天多出來幾百行日志是沒有問題的。但對於多個日志在跨月的1天會有一個合
並的排序問題:
[31/Mar/2002:59:59:59 +0800]
[31/Mar/2002:23:59:59 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
要知道[01/Apr/2002:00:00:00 這個字段是不可以進行“跨天排序”的。因為日期中使 用了dd/mm/yyyy,月份還是英文名,如果按照字母排序,很有可能是這樣的結果:排序 導致了日志的錯誤
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[31/Mar/2002:59:59:59 +0800]
[31/Mar/2002:23:59:59 +0800]
[31/Mar/2002:59:59:59 +0800]
[31/Mar/2002:23:59:59 +0800]
[31/Mar/2002:59:59:59 +0800]
[31/Mar/2002:23:59:59 +0800]
[31/Mar/2002:59:59:59 +0800]
[31/Mar/2002:23:59:59 +0800]
這些跨天過程中的非正常數據對於webalizer等分析工具來說簡直就好像是吃了一個臭 蟲一樣,運行的結果是:它可能會把前一個月所有的數據都丟失!因此這樣的數據會有 很多風險出現在處理上月最後一天的數據的過程中。
問題的解決有幾個思路:
1 事後處理:
。所以一個事後的處理的方法是:用grep命令在每月第1天將日志跨月的日志去掉,比 如:
grep -v "01/Apr" access_log_04_01 > access_log_new
修改SORT後的日志:所有跨天的數據去掉。也許對日志的事後處理是一個途徑,雖然 sort命令中有對日期排序的特殊選項 -M(注意是:大寫M),可以讓指定字段按照英文 月份排序而非字母順序,但對於apache日志來說,用SORT命令切分出月份字段很麻煩。 (我嘗試過用 "/"做分割符,並且使用“月份” “年:時間”這兩個字段排序)。雖然 用一些PERL的腳本肯定可以實現,但最終我還是放棄了。這不符合系統管理員的設計原 則:通用性。 並且你需要一直問自己:有沒有更簡單的方法呢? 還有就是將日志格式改成用TIMESTAMP(象SQUID的日志就沒有這個問題,它的日志本身 就是使用TIMESTAMP做時間時間戳的),但我無法保證所有的日志工具都能識別你在日 期這個字段使用了特別的格式。
2 優化數據源:
最好的辦法還是優化數據源。將數據源保證按天輪循,同一天的日志中的數據都在同一 天內。這樣以後你無論使用什麼工具(商業的,免費的)來分析日志,都不會因為日志 復雜的預處理機制受到影響。
首先可能會想到的是控制截取日志的時間:比如嚴格從0點開始截取日志,但在子夜前1 分鐘還是後一分鐘開始截取是沒有區別的,你仍然無法控制一個日志中有跨2天記錄的
問題,而且你也無法預測日志歸檔過程使用的時間。
因此必須要好好考慮一下使用日志輪循工具的問題,這些日志
首先可能會想到的是控制截取日志的時間:比如嚴格從0點開始截取日志,但在子夜前1 分鐘還是後一分鐘開始截取是沒有區別的,你仍然無法控制一個日志中有跨2天記錄的
問題,而且你也無法預測日志歸檔過程使用的時間。
因此必須要好好考慮一下使用日志輪循工具的問題,這些日志