2012-01-16 262 views
4

我正在構建一個日誌記錄系統,它將記錄請求並響應分佈在多個應用程序節點上的Web服務。我正在考慮使用MongoDB作爲存儲庫並實時登錄,或者在x次請求後更真實地將日誌轉儲到數據庫。該應用程序的設計是相當高的量,並建立在Perl。有沒有人有這樣的經驗?建議?或者這是否定的?MongoDB日誌記錄

回答

1

我已經在一個運行在兩個應用程序服務器上的webapp上完成了這項工作。在mongodb中寫入默認情況下是非阻塞的(java驅動程序只是爲您獲取請求並立即返回,我認爲它與perl相同,但您最好檢查一下),因爲您不想要您的用戶等待記錄日誌。

這樣做的缺點是,在某些故障情況下,您可能會丟失一些日誌(例如,在mongo獲取數據之前,您的應用程序失敗)。

+0

大。你在做實時記錄嗎?您的日誌記錄服務器如何負載密集? – MadHacker 2012-01-17 04:01:41

3

我見過很多公司都在使用MongoDB來存儲日誌。它的無模式對於應用程序日誌非常靈活,在這種日誌中架構往往會隨時間變化。此外,它的Capped Collection功能非常有用,因爲它會自動清除舊數據以保持數據適合內存。

人們通過正常分組或聚合MapReduce來聚合日誌,但速度並不快。特別是MongoDB的MapReduce只能在一個線程內工作,並且其JavaScript執行開銷很大。 New aggregation framework可以解決這個問題。

另一個問題是高通寫。儘管默認情況下MongoDB的插入方式是「即忘即忘」風格,但調用大量insert命令會導致嚴重的寫入鎖爭用。這可能會影響應用程序性能,並阻止讀者聚合/篩選存儲的日誌。

一種解決方案可能使用日誌收集器框架,如FluentdLogstashFlume。這些守護進程應該在每個應用程序節點上啓動,並從應用程序進程獲取日誌。

fluentd plus mongodb

他們緩衝日誌和異步寫入數據至其他系統,如MongoDB的/ PostgreSQL的/等寫入分批進行,所以這是一個很大比直接從應用程序編寫效率更高。該鏈接描述瞭如何將日誌從Perl程序放入Fluentd中。

0

爲您的應用程序的一些有趣的想法,我建議檢查出Graylog2,如果你還沒有準備好。他們相當有效地結合使用了MongoDB和Elasticsearch。在組合中添加強大的搜索引擎可以爲您提供一些有趣的查詢和分析選項。

僅供您參考,以下是專門用於記錄處理工具和技術的Elasticsearch page

如果您打算在處理之前排隊日誌條目(我會推薦),我建議Kestrel作爲一個固定的消息隊列選項。這就是Gaug.es所使用的,最近我一直在通過它。一個Java應用程序,它非常快速和原子化,它可以方便地說出Memcache協議。這是一種橫向擴展的好方法,並且內存緩存備份到一個日記文件中,以實現速度和耐用性的良好平衡。

2

我通過Log::Dispatch::MongoDB在多個應用中使用它;奇蹟般有效!

# Declaration 
use Log::Dispatch; 
use Log::Dispatch::MongoDB; 
use Log::Dispatch::Screen; 
use Moose; 

has log => (is => 'ro', isa => 'Log::Dispatch', default => sub { Log::Dispatch->new }, lazy => 1) 

... 

# Configuration 
$self->log->add(
    Log::Dispatch::Screen->new(
     min_level => 'debug', 
     name  => 'screen', 
     newline  => 1, 
    ) 
); 
$self->log->add(
    Log::Dispatch::MongoDB->new(
     collection => MongoDB::Connection->new(
      host => $self->config->mongodb 
     )->saveme->log, 
     min_level => 'debug', 
     name  => 'crawler', 
    ) 
); 

... 

# The logging facility 
$self->log->log(
    level => 'info', 
    message => 'Crawler finished', 
    info => { 
     origin => $self->origin, 
     country => $self->country, 
     counter => $self->counter, 
     start => $self->start, 
     finish => time, 
    } 
); 

而且這裏距離capped collection一個樣本記錄:

{ 
    "_id" : ObjectId("50c453421329307e4f000007"), 
    "info" : { 
      "country" : "sa", 
      "finish" : NumberLong(1355043650), 
      "origin" : "onedayonly_sa", 
      "counter" : NumberLong(2), 
      "start" : NumberLong(1355043646) 
    }, 
    "level" : "info", 
    "name" : "crawler", 
    "message" : "Crawler finished" 
}