在大型網站中常常會遇到大流量的數據輸出問題,過于頻繁的輸出到DB、文件、第三方系統都會帶來不穩定性和低效率。因此需要采用一定的方式來解決這個問題,其實這部分內容的簡單處理框架早就用在實際項目中,不過今天正好有外部的朋友問起我,我就整理了一下作為google的開源代碼放上去了,這里也簡單介紹一下,有興趣的朋友可以去看看,最好是能夠給一些建議。
場景:
應用頻繁訪問接口服務器,需要控制每個應用在可配置時間段內(例如一分鐘)對于某一服務的訪問次數,同時需要記錄每一次訪問內容到數據庫中。
幾個點:
1. 高并發情況下,集群服務器需要全局計數。(需要將更新和判斷作為原子操作,而非兩階段操作,保證高并發事務)
2. 異步日志批量輸出。防止高頻率訪問第三方系統(DB,本地IO),提高性能。
3. 采用黑名單簡化計數器判斷。
1,3通過memcache就可以實現,如果需要使用客戶端可以看看google code上的:http://code.google.com/p/memcache-client-forjava/
這里主要在說一下2,在很多場景中都會有這樣的需求,一些需要輸出到DB或者文件的內容需要緩存起來異步批量操作,提高性能也降低對于第三方系統的壓力。大致設計結構圖如下:
自上而下來看,ThreadA,B,C都是程序中其他模塊的線程,他們需要輸出記錄到數據庫或者DB中。當有數據到達需要輸出時,僅僅只是將數據放入阻塞隊列中,而有一個消費者線程池中的線程發現隊列中有數據就將數據寫入其中某一個線程的數據分頁中(每一個線程維護一個自己的內存分頁,當頁滿或者到達了配置的輸出間隔時間以后就將頁內數據交給輸出線程池中的輸出線程完成批量數據輸出)。
下面是三個類圖,囊括了這個小工具框架的所有類:
上圖是對外提供的異步輸出模板,其他模塊可以直接使用模板來輸出數據。

上圖是異步輸出器包,是異步輸出模板的內置邏輯實現,其他線程直接使用異步輸出模板來輸出記錄。

上圖是消費者和輸出線程的接口和默認實現類,可以替換及擴展。
整個框架基本都可以通過配置文件擴展每一個角色(異步輸出類,消費者,寫出者),擴展方式就是通過在classpath下增加目錄META-INF/services/然后將需要擴展的接口作為文件名稱,內容就是接口的實現類,這樣既可擴展和替換任何一個角色的具體實現。
具體的代碼和測試用例可以去http://code.google.com/p/asynwriter/ 下載。