1. 程式人生 > >高效能影象處理伺服器的實現(一)高效能非同步日誌

高效能影象處理伺服器的實現(一)高效能非同步日誌

      日誌是除錯一個伺服器的最好方法了,在大型的伺服器專案中,如果一直日誌的輸出總是有問題,或者輸出的資訊含糊不明,那麼,你的除錯過程將會非常痛苦,如果是普通的記憶體洩漏或者越界訪問,或者TCP通訊過程中的一些問題,那麼通過errno也許還能幫你一下,但如果是跑了一段時間的伺服器突然宕機,那麼定位問題將會非常的困難。由此可見,一個高效安全且保證輸出所有資訊(我這裡的保證輸出所有資訊表示即使伺服器立即停止,日誌系統也能把當下所有的資訊輸出到日誌檔案中)的日誌系統,是一個伺服器專案中不可或缺的一個環節,下面我將介紹在我的高效能影象處理伺服器中的日誌模組的一些編寫思路和具體細節。

      我的日誌系統框架是參照陳碩大大的muduo來進行編寫的,總的框架思路為:     

      1.採用了雙緩衝技術的buffer,具體思路為準備4個(如果短時間內資料寫入量巨大,buffer數量會隨情況增加,正常情況下為4個)buffer,其中兩個buffer(這裡稱之A,B)作為前端輸入,另外兩個buffer(這裡稱之C,D)作為後端預備輸入,當A,B寫滿或者達到寫入時間間隔時,交換AB和CD,然後後端將A,B的資訊寫入日誌檔案,前端如有資訊寫入則寫入到C,D中,如此迴圈往復。這樣做的好處是前端把訊息做了彙總,然後通知後端處理,避免頻繁喚醒執行緒,降低開銷。

      2.開啟一個專門的執行緒作為一個非同步日誌的後端處理執行緒,該執行緒的主要任務為固定時間或者收到通知後交換寫Buffer,然後將已寫好資料的Buffer中的資料寫入到檔案中。這麼做的好處是非同步處理,其他執行緒阻塞的時候不會影響到日誌資訊的寫入。

      3.編寫Logger類,通過過載<<操作符,將資訊寫入Logger的buffer中,當Logger析構的時候通過呼叫註冊在Logger中的output回撥將資訊寫入非同步日誌的buffer中。這麼做的好處是在應用程式中使用方便,並且可以方便的給日誌等級做分級處理。

      基本訊息處理框架如下:

然後再稍微訊息說明下非同步日誌的具體工作流程:

1.首先在LogStream聲明瞭幾個巨集定義,用來做日誌訊息等級分級,我的日誌分4級:

LOG_INFO(用於記錄普通的資訊,如有新的訊息寫入或者client接入等)

       LOG_TRACE(記錄用於除錯的資訊,如EPOLL中的事件發生等)

LOG_WARNING(記錄可能產生錯誤但不會讓程式立即崩潰的程式碼是否發生,如呼叫註冊的回撥事件時出現未定義的事件編號等)

 LOG_ERROR(記錄錯誤資訊,如記錄errno等)

2.每一條訊息寫入日誌前會給其新增頭尾資訊,如新增程式碼行數,發生時間等,這麼做的好處是方便定位錯位,我的日誌訊息標準格式如下:


 實際生成的日誌如下:


       同理,當log檔案過多時,log檔案的命名也需要規範,我的log檔案命名格式如下:

     main.cpp-time-2018.2.7.20.49.10.955452-pid-30075.log(1)

     有格式的日誌訊息在日誌訊息量巨大時可以起到很好的作用,你可以用awk工具輕鬆的提取你想要的資訊。

3.一條日誌訊息的完整寫入過程如下,以LOG_INFO為例


具體的程式碼見我的GitHub:https://github.com/zk3326312/ZK_ImageServer/tree/master/log,在log庫中有一個testAsynLogging檔案,可以用來測試日誌庫的寫入效能和是否能成功寫入,如果覺得可以的話幫我點個星吧,下一篇博文我將寫一個reactors in threads的網路庫編寫方法。