over 3 years ago

在 NoSQL 陣營中,CassandraHBase 這兩個同樣受到 BigTable 啓發,但踏上不一樣道路的近親,常被放在一起比較。兩者當然都各有優缺點,也都還在各自進化中,本文並不打算觸及這些爭論,只談談 Cassandra 的 cluster 設定。

Cassandra 部署起來很簡單。由於每一個節點都可以扮演幾乎完全相同的角色,不僅避開 SPOF 問題,更簡化了部署的複雜度,不必像 HBase 還得仰賴 ZooKeeper 等外來援兵(當然啦,如果你本來就打算用上整個 Hadoop 重砲,那就不能算是缺點了)。

部署起來有多簡單?看這位老兄秀的 “How to set up a 4 node Cassandra cluster in under 2 minutes” 影片,就知道有多神了。

儘管理論上是這樣沒錯,但魔鬼藏在細節裡,還是有一些地方要留意一下。

Hotspots

前一陣子將 Cassandra 部署到兩台主機,實際運作兩周後,發現兩台主機的負載極度不平衡:

% nodetool status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address      Load       Tokens  Owns   Host ID     Rack
UN  xx.xx.xx.xx  9.51 GB    1       99.9%  xxxxxxxxxx  rack1
UN  yy.yy.yy.yy  8.58 GB    1       0.1%   yyyyyyyyyy  rack1

在 "Owns" 那一欄呈現出很誇張的情況⋯⋯

分散式系統的直覺告訴我,如果沒有其他可疑之處,應該要先試著朝 consistent hashing 的方向去處理。

上網搜尋一下,找到(理論上)應該是正解的資訊:

照著上述文件,執行 token-generator,並依序回答問題:

% token-generator
Token Generator Interactive Mode
--------------------------------

 How many datacenters will participate in this Cassandra cluster? 1
 How many nodes are in datacenter #1? 2


DC #1:

  Node #1:                                        0

  Node #2:   85070591730234615865843651857942052864

然後,將 token-generator 的輸出,填入 Cassandra 設定檔 cassandra.yamlinitial_token 欄⋯⋯結果還是沒有改善。

一陣亂試亂試,試到最後居然連 Cassandra 都開不起來了⋯⋯

怒⋯⋯

兇手在這裡

隔天,回頭逐行檢視設定檔 cassandra.yaml 內容,突然發現 Cassandra 1.2 預設的 “partitioner” 居然是 Murmur3Partitioner,而不是之前在網路上或書本上常常提到的 RandomPartitioner。官方說帖是:

RandomPartitioner distributes rows across the cluster evenly by md5. This is the default prior to 1.2 and is retained for compatibility.

Murmur3Partitioner is similar to RandomPartioner but uses Murmur3_128 hash function instead of md5. When in doubt, this is the best option.

The Murmur3Partitioner provides faster hashing and improved performance than the previous default partitioner (RandomPartitioner).

「呃,剛剛用的官方工具 token-generator 好像只有針對 RandomPartitioner 來計算?」

的確如此,看它的 help,完全沒有這個參數:

% token-generator --help
Usage: token-generator <nodes_in_dc1> [<nodes_in_dc2> [...]]

Given a list of numbers indicating the number of nodes in each separate
datacenter, outputs a recommended list of tokens to use with
RandomPartitioner: one for each node in each datacenter.

Options:
  -h, --help            show this help message and exit
  --ringrange=RINGRANGE
                        Specify a numeric maximum token value for your ring,
                        different from the default value of 2^127.
  --graph               Show a rendering of the generated tokens as line
                        segments in a circle, colored according to datacenter
  -n, --nts             Optimize multi-cluster distribution for
                        NetworkTopologyStrategy [default]
  -o, --onts            Optimize multi-cluster distribution for
                        OldNetworkTopologyStrategy
  --test                Run in test mode, outputting an HTML file to display
                        various generated ring arrangements.

「嗯,會不會就是因為這樣,所以才不適用?因為它根本不認得 Murmur3Partitioner⋯⋯」

「咦,這不是官方欽定的工具嗎?怎麼會這麼顧慮不周,沒有隨之改版升級呢⋯⋯」

針對 Murmur3Partitioner 重新計算

於是,改用 Cassandra 1.2 官方文件 “Generating Tokens” 所介紹的公式:

% python -c 'print [str(((2**64 / number_of_tokens) * i) - 2**63) for i in range(number_of_tokens)]'

2 代入 number_of_tokens,得到一組數字:

% python -c 'print [str(((2**64 / 2) * i) - 2**63) for i in range(2)]'
['-9223372036854775808', '0']

不想把 initial_token 寫死在設定檔 cassandra.yaml 裡面,因此,我改用 nodetool move 命令來設定:

% nodetool  -h xx.xx.xx.xx  move   \\-9223372036854775808
% nodetool  -h yy.yy.yy.yy  move   0

再看一次這兩台主機的負載情況變得如何了:

% nodetool status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address      Load       Owns   Host ID     Token                   Rack
UN  xx.xx.xx.xx  66.39 KB   50.0%  xxxxxxxxxx  -9223372036854775808    rack1
UN  yy.yy.yy.yy  65.41 KB   50.0%  yyyyyyyyyy  0                       rack1

嗯,"Owns" 那一欄正常多了!

Cassandra Token Calculator

網路上有人寫了一份 Cassandra Token Calculator,可以讓你任意指定要用 Murmur3Partitioner 還是 RandomPartioner,很方便。

順手試了一下 Murmur3Partitioner 的輸出,因為,照流量成長的趨勢看來,搞不好很快就需要用到這份小抄了⋯⋯ :D

2 nodes:

  1. -9223372036854775808
  2. 0

3 nodes:

  1. -9223372036854775808
  2. -3074457345618258603
  3. 3074457345618258602

4 nodes:

  1. -9223372036854775808
  2. -4611686018427387904
  3. 0
  4. 4611686018427387904

5 nodes:

  1. -9223372036854775808
  2. -5534023222112865485
  3. -1844674407370955162
  4. 1844674407370955161
  5. 5534023222112865484
用 Ansible 及 Vagrant 做的伺服器組態設定公版 →
 
comments powered by Disqus