Vnodes簡短歷史
Vnodes又叫Virtual Nodes。是Cassandra在1.2版本里引入的功能,已經在生產環境中使用了近8年了。從2.0版本開始,因為預設配置裡num_tokens一般會設成256,所以如果你沒有修改過預設引數,那很有可能你一直都在使用這個功能。
當初引入vnodes主要是為了改善增加節點時的靈活性。在pre-1.2時代(也就是沒有vnodes功能的時候),每次叢集擴容都必須要讓節點數翻倍,比如3個節點擴容到6個節點,下次需要擴容的時候再增加到12個節點。這是因為每個節點都只擁有一個token範圍,增加新節點的時候就是把每個token範圍一分為二,讓每個新節點都負責一半的token範圍。但是,如果要保證整個叢集的token範圍是均勻分佈的,每次新增加的節點數需要跟已有的節點數一致。這樣每次翻倍的擴容方式顯然對運維和資源計劃造成了很大的挑戰。
有了vnodes以後,預設情況下每個物理節點會負責256個token範圍,增加一個新的節點只需要從每個已有節點的256個token範圍中取出若干個,合起來湊成256個新token範圍分配給新來的節點就好了。整個叢集的token範圍分佈還是均勻的。
Vnodes功能在1.2版推出以後,受到了廣大生產環境Cassandra運維人員的歡迎,所以在2.0版裡,vnodes功能被預設啟用,而且這個num_tokens引數預設的被配置成了256。
Vnodes帶來的問題
可是,隨著越來越多的Cassandra叢集開始在生產環境裡使用vnodes,它的一些不盡如人意的地方逐漸開始體現出來。
最大的一個問題,體現在執行nodetool repair的時候:因為repair是按照節點的token範圍來安排一個個的小任務,以進行副本之間的比較和修復工作;一個節點擁有的token範圍的數量越多,這樣的小任務就越多;當一個節點擁有了256個token範圍,並且儲存了幾百GB資料的時候,每個keyspace的repair小任務加起來所花的時間動輒就會達到幾小時甚至數天;生產環境中一般會有幾個keyspace,再加上nodetool repair -pr需要10天之內在所有的節點上都執行一輪,這會對運維帶來比較大的困難。
另外,當一個節點擁有了256個token範圍時,增加新節點的bootstrap過程也會帶來多得多的SSTable數量,需要消耗大量的CPU才能把這些大量的小SSTable消化掉。
比較棘手的是,這些問題並不是簡單的在配置中降低num_tokens取值就可以解決的。把num_tokens設定成一個更小的值比如16,當然會大大改善repair和bootstrap,但是這樣面臨著兩個主要的挑戰:
- Cassandra 1.2原有的vnodes演算法設計一般假設每個節點會有數百個token範圍,使用的是隨機重新分配的演算法,token範圍數量多的時候沒問題,但是token範圍數量降低到十幾個的時候,很容易出現資料不均勻分配的情況(如下圖所示),而且節點增加的越多,這種不均勻的現象會越嚴重;
- 一個資料中心的vnodes數量在資料中心初始化的時候就確定了,將來想要改的話,只能啟用新的資料中心遷移資料。
Datacenter: us-east-1 ===================== Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns (effective) Host ID Rack UN 172.1*.3*.1* 1.55 TiB 16 4.1% f683ab0e-a687-400f-80fb-28f7b4471ffc b UN 172.1*.3*.1** 1.05 TiB 16 2.9% 2097cd01-4161-44a9-a944-d5445e8c5e02 c UN 172.1*.3*.2* 720.26 GiB 16 3.0% e6593e3a-bb1c-499c-a99b-73781cfcd076 c UN 172.1*.3*.2* 1.3 TiB 16 4.0% 99670a7c-a55f-4a43-8e4b-a3cccc71f08f a UN 172.1*.3*.1** 961.67 GiB 16 3.2% a4bb1648-3582-4f05-a1e6-3125e9c3c46c b UN 172.1*.3*.1** 1.29 TiB 16 4.4% 890e98d3-d88d-4d8c-89b4-7e9444bb69be a UN 172.1*.3*.2* 1.42 TiB 16 4.0% 3f2817da-9dc5-4122-8977-5d3d93669b4e c UN 172.1*.3*.1** 710.53 GiB 16 4.9% 72405162-f121-46d4-a220-a1fd2db868e8 b UN 172.1*.3*.3* 2.38 TiB 16 7.1% f15c768c-0175-4646-bc68-7b20a74d7f0d b UN 172.1*.3*.1** 2.68 TiB 16 7.3% 2f444803-7787-474a-9ed9-8555147023d3 c UN 172.1*.3*.1** 1.59 TiB 16 5.2% bd838966-23e2-44b2-986c-729ede679604 c UN 172.1*.3*.5* 808.48 GiB 16 4.3% 1fe83c82-1fb2-4570-9aae-7805370f24b0 b
新版本是怎樣解決問題的
針對上面提到的第一個挑戰,Cassandra 3.0裡啟用了新的token分配演算法,並且增加了一個新的引數allocate_tokens_for_keyspace,這個貪心演算法雖然不能完全避免token範圍熱點的情況出現,但是它的最大好處是,在叢集中繼續增加節點的話,token範圍的熱點會越來越少,資料分配會越來越均勻。
Cassandra 4.0在此基礎之上又做了更多的改進,3.0裡的引數allocate_tokens_for_keyspace將被allocate_tokens_for_local_replication_factor取代。這樣配置的工作更加簡單,因為不再需要在初始化一個資料中心的時候提供一個keyspace的名字。
有了這樣演算法的加持,社群也逐漸開始建議所有使用者在新建資料庫的時候,把num_tokens引數直接改成一個比256小得多的取值。最新的討論可以看這個JIRA和這個郵件列表的討論。社群現在達成的共識是在4.0版本中把預設的num_tokens設定成16,並且預設啟用新的token分配演算法。如果4.0 release測試過程不再發現新的問題,在4.0正式版釋出以後,所有執行新版本的叢集將會是每節點擁有16個token範圍,以兼顧運維操作的高效,和資料分配的均勻。