系統架構設計之--異步日誌記錄篇

一. 背景

    目前我們開發的絕大部分系統是都需要記錄業務日誌的(包括不限於操作日誌),比如電子商務夠物結帳的時候,相關的購買信息,支付信息你要記錄下來吧,因爲將來某一天你可能要和客戶對帳的.再舉個例子,平時大家都會去銀行轉帳,銀行背地裏一定把你轉帳的相關信息都記錄下來了,比如,轉出帳戶,轉出時間,轉出金額,轉入帳戶等等.銀行也經常說要多久以後到帳(比如5分鐘),如果不到的話你可以憑單去銀行對帳的.

二. 現狀

    目前絕大部分系統設計之初都是把日誌這個動作,作爲同步記錄的,下面以僞碼描述一下.

    using(transcation a){

         book.pay();//購買一本書並付款

         operate.add(); //增加一條事務日誌.        

    }

三. 問題分析

    1. 如果用的是一個connection,那麼事務將保證是一個本地事務,保證最大的性能.但如果按上述做法設計,即N個對象一起保存數據(N>=2)那麼將會引起一個分佈式事務,性能就會降低10倍以上,響應時間也相應變慢.

    2. 併發訪問下的數據連接,在這個最簡單的事務裏打開兩個連接,book一個,operate一個.考慮.net數據連接池默認100個情況,只考慮這個簡單業務操作的話,強併發最多隻能支持50個客戶同時訪問.

    3.網絡訪問,數據庫訪問是一個非常耗時的操作,將一個正常事務執行時間延長1倍,客戶體驗效率不好.

    4.每個業務操作都要調用,日誌函數,導致日誌不能批量寫入,性能比較差

    5.業務日誌有可能和生產庫放在同一個數據庫,不利於維護和查詢優化以及數據量巨大時,數據分區等操作.不利於提交生產數據庫性能

四. 解決方案

    1. 支持兩種數據寫入方法,一種同步日誌寫入,即上面以前做法,一種異步日誌,異步日誌是對同步日誌的一種包裝.

    2. 異步日誌主要是利用一日誌文件來保證異步寫入,比如日誌文件爲operate.log. 當系統調用需要寫日誌時,異步日誌方法將日誌寫入到operate.log文件中,然後返回.

    3. 後臺有個獨立線程每隔X秒,讀取全部日誌文件,調用同步日誌類中批量寫方法寫入日誌數據庫.

    4. 僞代碼如下:

        using(transcation a){

           book.pay();//購買一本書並付款

           operate.aysAdd(); //異步增加一條事務日誌.        

        }

        aysAdd(){

           FileStream stream = File.Open(path);

           stream.WriteLine(); //異步寫日誌文件

        }

        ThreadProc(){

           while(true){

               FileStream stream = File.Open(path);

               stream.ReadAllLine(); //同步讀取文件

               operate.BatchSave(); //批量保存日誌信息

               Thread.Sleep(N); //睡眠N秒,繼續批量保存數據

           }

        }

五. 方案分析以及保障制度

    1. 不是同步保存,那我係統斷電,或者IIS重起怎麼辦? 答:當實例化日誌類時候,將首先讀取operate.log,並保存入庫,保證日誌文件不會丟失.

    2. 如果寫文件過程中寫入失敗怎麼辦?答:這裏說了,異步日誌是對同步模型的一個包裝,是一個典型的裝飾器模式.如果寫文件失敗,則轉成同步模式去保存數據,不會丟失任何業務數據.

    3. 你那裏是同步寫還是異步寫?如果是異步寫文件那斷電怎麼辦?如果是同步寫日誌,那性能和以前對比有什麼提高嗎?

        答: 1. 同步寫日誌文件,即一定要保證日誌文件能寫入到文本文件,才能提交整個事務.

             2. 只有異步寫入數據的時候纔會遇到這種問題,突然斷電,日誌文件丟失.

             3. 做了一個性能測試,每秒可以寫入1,000,000條業務日誌到文件裏,極高提升系統性能.批量提交日誌文件到數據庫,共享一個連接,而且Sql組成批語句,更可以節省數量級的性能損耗

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章