分析VoltDB內存數據庫


轉自https://blog.csdn.net/olidrop/article/details/7065384

  https://blog.csdn.net/ransom0512/article/details/50440316

VoltDB的數據主要存儲在內存中,Shared Nothing的集群結構,單機是單線程處理事務,不是用鎖而是基於Optimistic的方法處理事務並發,所有的事務必須以存儲過程形式先提交到VoltDB系統。

適用場景

VoltDB適合OLTP系統,單個事務較小,但是事務總量非常之多的應用。比如金融,零售,WEB2.0等傳統OLTP應用。不適合進行范圍查詢或者頻繁多表Join這樣的場景。

設計思路

VoltDB通過內存存儲、數據分區和無鎖計算來實現高性能運算。

    • 內存存儲 
      VoltDB所有數據都保存在內存中(可靠性中會有數據刷到磁盤,見VoltDB ACID中可靠性設計), 內存存取速度已經比磁盤遠遠高出幾個數量級了,這就是VoltDB高性能的重要原因。
    • 數據分區 
      VoltDB對每個節點的內存進行管理,在每個節點上創建多個分區,所有分區表中的數據,都分散在各個分區中,然后在讀寫的時候,就可以實現多個分區並發進行,所以拓展性是線性提升的。 
      這種分區機制也會帶來問題,當集群需要擴容的時候,需要停止整個集群,然后再進行擴容;當集群啟動的時候,VoltDB會重新調整數據分布,在所有數據分布調整完畢之后,才開始提供服務。
    • 無鎖計算 
      VoltDB數據分區存放,在執行SQL語句的時候,客戶端就會根據條件自動判斷數據在哪個分區中,然后下發至該分區執行。如果查詢條件中不包含分區列,那么就會由客戶端進行統一控制,在每個分區上都進行查詢之后,再統一返回結果,這種場景會極大影響性能。 
      VoltDB的程序都是以存儲過程的方式執行的,支持使用java或者其他語言定義存儲過程。每個分區的存儲過程執行都是單線程線性執行的,這就保證了單分區的無鎖設計。當一個語句涉及到多個區分協調讀寫的時候,VoltDB會在協調,統一鎖定分區隊列,等該語句執行完畢之后,才會釋放鎖。所以多分區操作才會如此消耗性能。 
      VoltDB在分區管理上,建議每個物理CPU創建一個分區,這樣單個分區內的數據都在CPU的一級緩存和二級緩存上,避免在多個CPU之間的數據操作,最大限度的提升CPU利用率,避免並發鎖。所以理論上,VoltDB的CPU使用率是可以達到100%的。

高可用性

VoltDB使用K-safety、雙活、snapshot、WAL機制組合機制保證數據的高可用性。

    • K-Safety 
      其實就是N+1的副本機制,VoltDB在寫數據操作的時候,會在每個副本中執行該語句,這樣就可以保證數據被正確插入每個副本。這N+1的副本都可以同時提供訪問,同時允許最多N個副本丟失(分區故障), 當N+1個副本都不可用的時候,VoltDB就會停止服務進行修復。
    • 雙活 
      多集群雙活機制,兩個集群都可以提供服務,數據在多分區之間異步復制,當一個集群掛了的時候,另外一個集群提供服務,當異常集群恢復之后,會自動進行數據同步,只有數據一致的時候,才會提供服務。但是這種機制其實還是有問題,有可能導致數據不一致,因此同步復制機制還是需要的。
    • Snapshot 
      由於數據在內存中存放,當節點掉電的時候,數據就會丟失,所以VoltDB會定期對每個分區數據做快照,以備節點掉電時候進行恢復。
    • WAL 
      Write ahead log,VoltDB會在對數據進行插入操作的時候,預先進行寫日志操作,這個和傳統數據庫一樣,但是由於是順序寫入,所以性能還是比傳統數據庫要好很多。 
      Snapshot機制和WAL機制會導致造成性能5%左右的下降,不過這個也是為了完整ACID不得不做出的犧牲。

事務提交

既需要支持復雜的事務操作,又需要快速的執行過程,VoltDB采取了一個比較極端的事務提交方式。雖然VoltDB支持部分SQL語句接口,但是不允許用戶使用傳統的"BEGIN TRANSACTION"和"END TRANSACTION"的語法模式,而是完全基於存儲過程。用戶通過寫存儲過程完成應用程序的邏輯,作為一個先置條件將存儲過程提交到VoltDB。運行時,用戶程序調用存儲過程完成事務操作,所有事務的運行邏輯是由VoltDB在服務器進程中完成的。這種方式保證了事務不會被人為打斷,並且服務器可以預先判斷各個事務的邏輯,也為事務並發處理挖掘信息。

分區表和復制表

    • 分區表 
      創建表之后,需要手工執行分區語句為表進行分區。 
      PARTITION TABLE towns ON COLUMN state_num; 
      該語句表明使用state_numn字段為towns表進行分區。之后插入數據的時候,VoltDB會自動將數據插入指定分區。 
      目前VoltDB只支持Hash分區,后續可能會考慮支持范圍分區。 
      VoltDB的分區是一個邏輯上的概念,一個分區中可能包含多個表的多個數據分區的數據。VoltDB建議按照物理CPU的數量進行分區,每個分區獨立使用一個CPU,這樣可以避免CPU之間的鎖競爭。
    • 復制表 
      一個表,沒有指定分區,那么就是一個復制表。這個表的特征就是會在每個分區保存一份全量副本,這樣在和其他表在做Join查詢的時候,就不會跨節點查詢,大大加快Join速度。 
      復制表適合於數據比較穩定,只有少量更新的場景。如果數據要更新,就意味着要在每個分區上都執行一次插入操作,這種操作會顯著降低系統並發度。

數據分布

VoltDB使用Shared Nothing結構,整個數據庫的數據分散到集群的多台機器上。VoltDB的數據分布策略是基於哈希的,存儲在VoltDB中的每一張表,對數據的主鍵哈希取模后的結果對應於數據存儲的節點。相比較於BigTable基於主鍵的連續范圍分段的方法,哈希方法的好處是數據分散的均勻,沒有動態數據調整的煩惱。但也有很多缺點,采用這種方法后,集群的規模是事先確定好的,新增機器需要停止服務后重新分布數據。另外,數據哈希被分散后,數據的連續性被打亂了,在這個數據結構上做范圍查詢需要動用服務這張表的所有機器,這個后面會祥說。

上面這張圖描述了數據的分布方式,VoltDB集群的每台機器都會服務多張表。從圖里還能看到VoltDB的數據復制是基於機器單位的,藍色框圈住的兩台機器內的數據是完全同構的。

VoltDB的哈希分布數據的方法是系統設計的簡化,這種簡化讓VoltDB工程實現難度降低,可以快速的商用。天下沒有免費的午餐,這個設計也是VoltDB功能缺陷,導致VoltDB無法動態擴容以及其他一些問題。

數據一致性

同一份數據的多個副本之間需要保證數據一致性,VoltDB采用所有修改操作在每一個副本上單獨更新的方式。如何保證更新操作在所有副本上以相同的順序更改而不至於產生不一致,這就要提到VoltDB的並發控制方式。

VoltDB的事務並發控制需要依賴於集群內所有機器的時間是一致的,這個可以使用NTP之類的時間同步協議,保證機器之間的時間差異遠遠小於一個交換機下的兩台機器之間的Round Trip時間。VoltDB對於用戶每一次事務的調用分配一個時間戳,並且保證這個時間戳是全局有序的,雖然時間戳是由集群中的各台機器獨自分配的,但是加上機器的序號,可以保證(機器序號,時間戳)的組合值是全局有序的。一台服務器執行事務之前,需要等待Round Trip時間后,如果其他機器沒有開始比自己更早的事務,那么就執行自己的事務。以這種方式保證集群內多台機器之間事務的有序。數據的多個副本的更新操作也都以相同的順序進行修改,所有副本之間保證了一致性。

事務並發處理

為了充分發揮多核機器的性能,而又不引入多線程執行事務的復雜性,VoltDB的數據分片規模是按照集群核數來划分的。一台物理機器上可能運行多個VoltDB服務器進程,每個進程對應於一個核,服務器進程之間都是通過網絡進行通信。在單個進程內,只使用單線程,所有的事務執行都是順序進行的。

多個事務在多個服務器節點同時執行,VoltDB保證如果事務之間有沖突,那么事務的執行是完全隔離的,即達到SERIALIZABLE ISOLATION。VoltDB會事先分析好存儲過程之間的關系,如果兩個事務可能存在沖突,則不讓這兩個進程在同一個時間執行。

在VoltDB的並發處理中,每一個事務在執行之前都要等待一個Round Trip時間,顯然會增加事務執行的時延。這么做是為了確保別的節點沒有發起比這個事務更早的事務,保證事務執行的順序。在實現中,VoltDB用了另外一種優化方法。例如A,B兩個節點,分別要執行事務1和2,A節點開始執行事務1的時間是T1,如果A收到B發了事務2的執行需求,並且T2 > T1,那么A節點可以確認從B節點不會有更早的事務再發送過來,A節點就不必等Round Trip時間,可以直接執行事務1。當整個系統壓力比較大時,這個優化方法效果尤其明顯,事務的時延有效降低。

VoltDB還花了很大精力在處理事務之間的邏輯關系,盡可能對事務分門別類進行處理,以期獲得更好的性能。

范圍查詢的處理

VoltDB取巧的采用的哈希的方法做數據分布,在面對范圍查詢的需求時,再次吃到苦果。哈希方法打亂了數據的連續性,對於范圍查詢的處理能力顯著下降。VoltDB執行某張表的范圍查詢,需要發送這個查詢到這張表的所有數據分片上。在所有分片完成同樣的范圍查詢,再將結果匯總,才能得到全局的准確結果。所以VoltDB處理范圍查詢會很低效

數據持久

雖然Stonebraker在H-Store的論文里反復提到,在內存型數據庫里,即使使用Group Commit寫操作日志也是非常低效的,但是為了保證數據的持久性,VoltDB還是不得不采用記操作日志的辦法。VoltDB使用定期做Snapshot加上記操作日志來保證數據持久性,這種方法沒有什么特別的地方。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM