您當前的位置:首頁 > 舞蹈

細說雙Buffer緩衝池

作者:由 文刀 發表于 舞蹈時間:2019-03-28

緩衝機制是對資料持久化的延遲,減少不必要的IO,提高資料落盤的效率。本文將會詳細探討擁有雙Buffer的緩衝池(下文統稱TwinsBufferPool)是如何實現的,讀者可以依此推廣,得到N-Buffer的實現原理。

在此篇文章中,緩衝區(Buffer)和緩衝池(BufferPool)是兩個重要的概念,很明顯,兩者構成了一個包含與被包含的關係,一個緩衝池內可以有一個或者多個緩衝區協同工作,緩衝池中的所有緩衝區被組織成了一個環形佇列,一前一後的兩個緩衝區可以互相替換角色。

當然,在整個過程中,還會有其他輔助工具的出現,在下文都會逐一闡述。

一、設計要點

1、可擴充套件性。毫無疑問,可擴充套件性是對一個設計良好的軟體的一項基本要求,而一個軟體的可擴充套件的地方通常是有很多處的,這在某種程度上會依賴於程式設計者的經驗,如果僅僅侷限於產品需求,可能會嚴重限制了軟體的可擴充套件性。緩衝池是一種相對通用的中介軟體,擴充套件點相對比較多,比如:緩衝區數量可指定,執行緒安全與否,緩衝區閾值調配等等。

2、易用性。設計出來的中介軟體應該是對使用者友好的,使用過程中不會有繁瑣的配置,奇形怪狀的API,更不能有諸多不必要的Dependencies,如果能做到程式碼無侵入性,那就非常完美了。基於這個要求,TwinsBufferPool做成了一個Spring Boot Starter的形式,加入到專案裡的dependencies中即可開啟使用。

3、穩定性。這就是衡量一箇中間件好壞的重要KPI之一,從外觀上看,同樣是一艘船,破了一個洞和完好無缺將會是一個致命的區別,使用者期望自己搭上了一艘完整的船,以便能航行萬里而無憂。

4、高效性。說到穩定性,那就不得不說高效了,如果能幫助使用者又好又快的解決問題,無疑是最完美的結果。關於TwinsBufferPool的穩定性和高效性兩個指標,會在文中附上jemeter的壓測結果,並加以說明。

二、設計方案

這一小節將會給出TwinsBufferPool完整的設計方案,我們先從配置說起。

每個引數都會提供預設值,所以不做任何配置也是允許的。如下是目前TwinsBufferPool能提供的配置引數(yml):

buffer

capacity

2000

threshold

0。5

allow-duplicate

true

pool

enable-temporary-storage

true

buffer-time-in-seconds

120

下面附上引數說明表:

細說雙Buffer緩衝池

TwinsBufferPool引數表

以上引數比較淺顯易懂,這裡重點解釋enable-temporary-storage和buffer-time-in-seconds這兩個引數。

根據引數說明,很明顯可以感受到,這兩個引數是為了預防突發情況,導致資料丟失。因為緩衝區都是基於記憶體的設計的,這就意味著緩衝的資料隨時處於一種服務重啟,或者服務宕機的高風險環境中,因此,才會有這兩個引數的誕生。

因為TwinsBufferPool良好的介面設計,對於以上兩個引數的實現機制也是高度可擴充套件的。TwinsBufferPool預設的是基於Redis的實現,使用者也可以用MongoDB,MySQL,FileSystem等方式實現。由此又會衍生出另外一個問題,由於各種異常情況,導致臨時儲存層遺留了一定量的資料,需要在下次啟動的時候,恢復這一部分的資料。

總而言之,資料都是透過flush動作最終持久化到磁碟上。

細說雙Buffer緩衝池

緩衝池主要結構

因為大多數實際業務場景對於緩衝池的併發量是有一定要求的,所以預設就採用了執行緒安全的實現策略,受到JDK中ThreadPool的啟發,緩衝池也具備了自身狀態管理的機制。如下列出了緩衝池所有可能存在的狀態,以及各個狀態的流轉。

/**

* 緩衝池暫未就緒

*/

private

static

final

int

ST_NOT_READY

=

1

/**

* 緩衝池初始化完畢,處於啟動狀態

*/

private

static

final

int

ST_STARTED

=

2

/**

* 如果安全關閉緩衝池,會立即進入此狀態

*/

private

static

final

int

ST_SHUTTING_DOWN

=

3

/**

* 緩衝池已關閉

*/

private

static

final

int

ST_SHUTDOWN

=

4

/**

* 正在進行資料恢復

*/

private

static

final

int

ST_RECOVERING

=

5

細說雙Buffer緩衝池

緩衝池狀態機

透過上述的一番分析,設計的方案也呼之欲出了,下面給出主要的介面設計與實現。

細說雙Buffer緩衝池

BufferPool介面定義

透過以上的講解,也不難理解BufferPool定義的介面。緩衝池的整個生命週期,以及內部的一些運作機制都得以體現。值得注意的是,在設計上,將緩衝池和儲存層做了邏輯分離,使得擴充套件性進一步得到增強。

儲存相關的介面包含了一些簡單的CURD,目前預設是用Redis作為臨時儲存層,MongoDB作為永久儲存層,使用者可以根據需要實現其他的儲存方式。

下圖展現的是TwinsBufferPool的實現方式,DataBuffer是緩衝區,必須依賴的基礎元素。因為設計的是環形佇列,所以依賴了CycleQueue,這個環形佇列的interface也是自定義的,在JDK中沒有找到比較合適的實現。

細說雙Buffer緩衝池

BufferPool介面實現

值得注意的是,BufferPool介面定義是靈活可擴充套件的,TwinsBufferPool只是提供了一種基於環形佇列的實現方式,使用者也可以自行設計,使用另外一種資料結構來支撐緩衝池的運作。

三、壓測報告

使用的是個人的PC電腦,機器的配置如下:

處理器:i5-7400 CPU 3。00GHZ 四核

記憶體:8。00GB

作業系統:Windows10 64位 基於x64的處理器

執行環境如下:

jdk 1。8。0_144

SpringBoot_2。1。0,內建Tomcat9。0

Redis_v4。0。1

MongoDB_v3。4。7

測試工具:

jemeter_v5。1

總共測試了四組引數,每組引數主要是針對最大容量,閾值和最大緩衝時間三個引數來做調整。

第一組:

buffer

capacity

1000

threshold

0。8

pool

buffer-time-in-seconds

60

第二組:

buffer

capacity

5000

threshold

0。8

pool

buffer-time-in-seconds

60

第三組:

buffer

capacity

5000

threshold

0。8

pool

buffer-time-in-seconds

300

第四組:

buffer

capacity

10000

threshold

0。8

pool

buffer-time-in-seconds

300

總共採集了9個指標:CPU佔用率,堆記憶體/M,執行緒數,錯誤率,吞吐量/sec,最長響應時間/ms,最短響應時間/ms,平均響應時間/ms,資料丟失量。

限於篇幅,只展示4個指標:堆記憶體,資料丟失量,平均響應時間,吞吐量。

細說雙Buffer緩衝池

堆記憶體/mb

細說雙Buffer緩衝池

資料丟失量

細說雙Buffer緩衝池

平均響應時間/ms

細說雙Buffer緩衝池

吞吐量/sec

總體來看,隨著每秒併發量的增加,各項指標呈現了不太樂觀的趨勢,其中最不穩定的是第四組引數,波動較為明顯,綜合表現最佳的是第二組引數,其次是第三組。

資料丟失量是一個比較讓人關心的指標,從圖中可以得知,在併發量達到4000的時候,開始有資料丟失的現象,而造成這一現象的原因並非是TwinsBufferPool實現程式碼的Bug,而是請求超時導致的“Connection refused”,因為每個Servlet執行容器都會有超時機制,如果排隊請求時間過長,就是直接被拒絕了。因此,看資料丟失量和錯誤率曲線,這兩者是一致的。如果設定成不超時,那麼將是零丟失量,零錯誤率,所帶來的代價就是平均響應時間會拉長。

因為受限於個人的測試環境,整個測試過程顯得不是很嚴謹,得出來的資料也並不是很完美,不過,我這裡提供了一些最佳化調整的建議:

1、硬體環境。正所謂“巧婦難為無米之炊”,如果提供的硬體效能本身就是有限的話,那麼,在上面執行的軟體也難以得到正常的發揮。

2、軟體架構。這個想象的空間很大,其中有一種方案我認為未來可以納入到RoadMap中:多緩衝池的負載均衡。我們可以嘗試在一個應用中啟用多個緩衝池,透過排程演算法,將緩衝資料均勻的分配給各個緩衝池,不至於出現只有一個緩衝池“疲於奔命”的狀況,最起碼系統的吞吐量會有所提升。

3、其他中介軟體或者工具的輔助,比如加上訊息中介軟體可以起到削峰的作用,各項指標也將會有所改善。

4、引數調優。這裡的引數指代的不僅僅是緩衝池的引數,還有包括最大連線數,最大執行緒數,超時時間等諸多外部引數。

四、總結

本文詳細闡述了雙Buffer緩衝池的設計原理,以及實現方式,並對TwinsBufferPool實施了壓測,也對測試結果進行了一番分析。

歡迎關注我的微信訂閱號:

技術匯

如果想檢視完整的測試報告,可在訂閱號內回覆關鍵詞:

測試報告

,即可獲取到下載連結。

如果想深入研究TwinsBufferPool原始碼的讀者,可在訂閱號內回覆關鍵詞:

緩衝池