1. 程式人生 > >[轉載] Cassandra 負載不均衡 與 解決方法

[轉載] Cassandra 負載不均衡 與 解決方法

最近在看Cassandra,但自打配起一個集群后,負載就不均衡了。

AddressStatusStateLoadOwnsToken
134154547520101788379756316570162344774
10.20.223.115UpNormal138.43KB32.81%19836060994110698319501384270720800576
10.20.223.116UpNormal143.39KB7.93%33327637713098975372896733928855304024
10.20.223.113UpNormal143.46KB28.38%81617185997645741434910225007556485361
10.20.223.114UpNormal133.3KB3.01%86736862331839877952832406350985306765
10.20.223.117UpNormal138.43KB5.90%96770512718388865179675126530244922092
10.20.223.112UpNormal138.52KB21.97%134154547520101788379756316570162344774

    將 auto_bootstrap 設為 true後,只有一個節點的Token發生了變化。整體均衡度沒有明顯變化。

     由於是初次接觸Cassandra,懷疑是否有做過錯誤的配置而未被發現。

     於是嘗試重新搭建環境、增、刪節點,均以失敗告終。

      也有朋友懷疑是資料量少或執行時間少導致的。但我看官方的資料,僅1G資料3個節點都是均衡的,我認為還是配置問題,而且官方介紹負載均衡的演算法與Token有關。於是按官方說明手動計算Token

def tokens(nodes):
    for x in xrange(nodes):
        print 2 **
127 / nodes * x

     然後手動指定(conf/cassandra.yaml) initial_token值,啟動後發現Token值並非讀取這個配置。應該是頭一次啟動計算後寫入到了System空間裡了。

    然後手動更新所有節點的Token值:bin/nodetool -host 10.20.10.31 -port 8080 move 88888888888888888888888888888888888888

    注意:Move過程會按新環移動現有資料,完成之後再檢視節點資訊。神了!雖然當前沒有資料,但我已經感覺到問題被解決了:

AddressStatusStateLoadOwnsToken
170141183460469231731687303715884105726
10.20.223.111UpNormal169.96KB14.29%24305883351495604533098186245126300818
10.20.223.112UpNormal175.13KB14.29%48611766702991209066196372490252601636
10.20.223.113UpNormal175.13KB14.29%72917650054486813599294558735378902454
10.20.223.114UpNormal180.48KB14.29%97223533405982418132392744980505203272
10.20.223.115UpNormal169.93KB14.29%121529416757478022665490931225631504090
10.20.223.116UpNormal175.07KB14.29%145835300108973627198589117470757804908
10.20.223.117UpNormal169.96KB14.29%170141183460469231731687303715884105726

    OK,加些資料看看是否均衡吧:

AddressStatusStateLoadOwnsToken
170141183460469231731687303715884105726
10.20.223.111UpNormal1.26GB14.29%24305883351495604533098186245126300818
10.20.223.112UpNormal1.26GB14.29%48611766702991209066196372490252601636
10.20.223.113UpNormal1.26GB14.29%72917650054486813599294558735378902454
10.20.223.114UpNormal1.26GB14.29%97223533405982418132392744980505203272
10.20.223.115UpNormal1.26GB14.29%121529416757478022665490931225631504090
10.20.223.116UpNormal1.26GB14.29%145835300108973627198589117470757804908
10.20.223.117UpNormal1.26GB14.29%170141183460469231731687303715884105726

     實在是太均衡了,原來就是Token惹的禍!

另外的一篇文章:

有一個多月沒有更新過blog了,有點慚愧。不管何種理由,不管工作生活有何種變動,有一些我們內心真正追求的東西,不能放棄。昨天晚上,世界盃大幕拉開,在等待揭幕戰的過程中,看了一段Cassandra關於dht部分的原始碼。要在生產系統中運維,則資料如何分佈不得不做周詳細緻的考慮。

將Cassandra用於實際的生成環境,一個必須要考慮的關鍵問題是Token的選擇。Token決定了每個節點儲存的資料的分佈範圍,每個節點儲存的資料的key在(前一個節點Token,本節點Token]的半開半閉區間內,所有的節點形成一個首尾相接的環,所以第一個節點儲存的是大於最大Token小於等於最小Token之間的資料。

根據採用的分割槽策略的不同,Token的型別和設定原則也有所不同。 Cassandra (0.6版本)本身支援三種分割槽策略:

RandomPartitioner:隨機分割槽是一種hash分割槽策略,使用的Token是大整數型(BigInteger),範圍為0~2^127,因此極端情況下,一個採用隨機分割槽策略的Cassandra叢集的節點可以達到2^127+1個節點。嗯,為什麼是2^127?因為Cassandra採用了MD5作為hash函式,其結果是128位的整數值(其中一位是符號位,Token取絕對值為結果)。採用隨機分割槽策略的叢集無法支援針對Key的範圍查詢。假如叢集有N個節點,每個節點的hash空間採取平均分佈的話,那麼第i個節點的Token可以設定為:

 i * ( 2 ^ 127 / N )

下面的測試程式是從org.apache.cassandra.utils.FBUtilities類抽取出來的計算MD5值的函式,輸入任何字元都可以得到其對應的MD5的整數值,利用該值和節點的Token對比即可知道該Key對應的資料歸屬於哪個節點:

OrderPreservingPartitioner:如果要支援針對Key的範圍查詢,那麼可以選擇這種有序分割槽策略。該策略採用的是字串型別的Token。每個節點的具體選擇需要根據Key的情況來確定。如果沒有指定InitialToken,則系統會使用一個長度為16的隨機字串作為Token,字串包含大小寫字元和數字。

CollatingOrderPreservingPartitioner:和OrderPreservingPartitioner一樣是有序分割槽策略。只是排序的方式不一樣,採用的是位元組型Token,支援設定不同語言環境的排序方式,程式碼中預設是en_US。

分割槽策略和每個節點的Token(Initial Token)都可以在storage-conf.xml配置檔案中設定:

<Partitioner>org.apache.cassandra.dht.RandomPartitioner</Partitioner>
<InitialToken>10633823966279300000000000000000000000</InitialToken>

節點初始化完成以後,Token值做為元資料會保留在system keyspace中,每次啟動會以該值為準,即使再改動配置檔案中的InitialToken也不會產生任何影響。

Saved Token found: 10633823966279300000000000000000000000

通過nodetool的ring命令,可以檢視叢集各個節點的Token,這些Token值最好備份下來,當出現節點徹底順壞時,可以重新設定同樣的Token,確保資料分佈可以不受節點損壞的影響。

 nodetool -h test ring
Address       Status     Load          Range                                      Ring
                                       85070591730234600000000000000000000000
192.168.0.1 Up         0 bytes       10633823966279300000000000000000000000     |<--|
192.168.0.2 Up         0 bytes       85070591730234600000000000000000000000     |-->|

PS: 在我的0.6.2的一個測試叢集中,使用nodetool時不小心連到了9160埠,結果每次都會把節點搞掛,百試百靈。而且直接telnet到9160埠,隨便傳送個字元,也會把節點搞崩潰。不知道是我的測試環境的原因,還是Thrift有bug,這樣節點的健壯性就有問題了,這個埠只能接受協議格式內的資訊。對Java和Thrift都不太瞭解,把這個問題丟擲來,希望有大牛能幫忙找到原因。

Update:之前貼的nodetool錯連9160埠的報錯可能有點誤導大家,因為jmx用的預設的8080埠,連9160埠jmx報錯是正常的,問題是節點不應該崩潰的。看了/var/log/cassandra/system.log中記錄的節點錯誤資訊,報的是OOM,Cassandra的java程序都消失了。調整了一下jvm引數,將heap的最小記憶體從預設的256MB設定到1G(-Xms1G),還是有同樣的問題。另外,我的java環境是jre1.6.0_18。