1. 程式人生 > >c++ 高性能日誌庫(muduo_AsyncLogging)

c++ 高性能日誌庫(muduo_AsyncLogging)

c++ reset IT 實現思路 for ava void 協調 前端

實現一個高效的網絡日誌庫要解決那些問題?
首先明確一下問題的模型,這是一個典型的多生產者 單消費者問題,對於前端的日誌庫使用者來說,應該做到非阻塞添加,作為後端的文件寫入,應該註意磁盤IO的瓶頸。

功能需求

  1. 日誌的級別分級
  2. 發生時間和具體線程信息
  3. 線程安全

實現思路

多個線程共有一個前端,通過後端寫入磁盤文件
異步日誌是必須的,所以需要一個緩沖區,在這裏我們使用的是多緩沖技術,基本思路是準備多塊Buffer,前端負責向Buffer中填數據,後端負責將Buffer中數據取出來寫入文件,這種實現的好處在於在新建日誌消息的時候不必等待磁盤IO操作,前端寫的時候也不會阻塞。

實現結構

LogStream 負責寫入消息的格式化
LogFile 負責文件寫入
AsyncLogging 負責實現 多緩沖技術 協調前後端

LogFile

LogStream

AsyncLogging

是及實現采用了四個緩沖區,這樣可以進一步減少前端等待,數據結構

typedef boost::ptr_vector<LargeBuffer> BufferVector;
typedef BufferVector::auto_type BufferPtr;
MutexLock lock;
Condition cond;
BufferPtr nextBuffer;
BufferVector buffers_;

append的具體實現
在當前的緩沖區和備用緩沖區中選擇一個足夠使用的進行寫入。

void AsynLogging::append(const
char* logline, int len){ LockGuard(mutex); if(curbuf->avail() > len){//當前緩沖區足夠 curbuf->append(logline,len); } else{ buffers.push_back(curbuf->release()); if(nextbuf){ curbuf = std::move(nextbuf); } else{ curbuf.reset(new
LargeBuffer); } curbuf->append(logline, len); cond.notify(); } }
  • 接收方的後端實現
    首先準備好兩塊空閑的buffer,已備在臨界區內交換,等待條件標量出發的條件又兩個,超時或者是前端寫滿了一個或者多個Buffer,當條件滿足時,先將當前緩沖移入buffer,並且立刻將空閑的newBuffer1作為當前緩沖,接下來將buffers和buffersToWrite交換,隨後將buffersToWrite寫入文件,重新設計設置Buffer。
void AsyncLogging::threadFunc(){
    BufferPtr nweBuffer1(new LargeBuffer);
    BufferPtr newBuffer2(new LargeBuffer);
    BufferVector bufferToWrite;
    while(running_){
    {
        MutexLockGuard lock(mutex);
        if(buffers.empty()){
            cond.wait_for(muted,flushInterval_);
        }
        buffers.push_back(currentBuffer_.release());
        currentBuffer = move(newBuffer1);
        buffersTowrite.swap(buffers_);
        if(!nextBuf){
            nextBuf = std::move(newBuffer2);
        }
    }
    }
}

c++ 高性能日誌庫(muduo_AsyncLogging)