數據庫中間件分片算法之jumpstringhash
- 2020 年 1 月 16 日
- 筆記
前言
今天是這一系列分片算法的完結篇。今天介紹的算法美如畫,谷歌工程師僅僅用了5行代碼就解決了一個大問題。可見寫代碼這件事不在多,而在於精。算法真的可以改變世界。
1.hash分區算法
2.stringhash分區算法
3.enum分區算法
4.numberrange分區算法
5.patternrange分區算法
6.date分區算法
7.jumpstringhash算法
jumpstringhash分區算法的配置
<tableRule name="rule_jumpHash"> <rule> <columns>code</columns> <algorithm>func_jumpHash</algorithm> </rule> </tableRule> <function name="func_jumpHash" class="jumpStringHash"> <property name="partitionCount">2</property> <property name="hashSlice">0:2</property> </function>
和之前的算法一樣。需要在rule.xml中配置tableRule和function。
- tableRule標籤,name對應的是規則的名字,而rule標籤中的columns則對應的分片字段,這個字段必須和表中的字段一致。algorithm則代表了執行分片函數的名字。
- function標籤,name代表分片算法的名字,算法的名字要和上面的tableRule中的<algorithm>標籤相對應。class:指定分片算法實現類。此處需要填寫為"jumpstringhash"或者"com.actiontech.dble.route.function.PartitionByJumpConsistentHash"的分區規則,property指定了對應分片算法的參數。不同的算法參數不同。
- partitionCount:分片數量
- hashSlice:分片截取長度
在MyCAT中有一種分區算法叫一致性hash算法,來源於論文"Consistent hashing and random trees: distributed caching protocols for relieving hot spots on the World Wide Web"。而那之後Google的John Lamping和Eric Veach發佈了Jump Consistent Hash,一種零內存消耗、均勻、快速、簡潔的一致性哈希算法。而dble中只使用了Jump Consistent Hash而移除了一致性hash。這主要是因為跳躍法佔用內存消耗更小,均衡性更高,計算量也相對較小。
我們來看一下源代碼,這個是我從dble的PartitionByJumpConsistentHash.java中摘取的一部分:
public class test2 { private static final long CONSTANT = Long.parseLong("286293355577794175", 10) * 10 + 7; private static final long JUMP = 1L << 31; private static final long UNSIGNED_MASK = 0x7fffffffffffffffL; private static void checkBuckets(final int buckets) { if (buckets < 0) { throw new IllegalArgumentException("Buckets cannot be less than 0"); } } private static double toDouble(final long n) { double d = n & UNSIGNED_MASK; if (n < 0) { d += 0x1.0p63; } return d; } public static int jumpConsistentHash(final long key, final int buckets) { checkBuckets(buckets); long k = key; long b = -1; long j = 0; while (j < buckets) { b = j; k = k * CONSTANT + 1L; j = (long) ((b + 1L) * (JUMP / toDouble((k >>> 33) + 1L))); } return (int) b; } public static void main(String args[]) { System.out.println("======== bucket 4 =========n"); for (int i = 20000; i < 20020; i++) { System.out.println(i+":"+jumpConsistentHash(i, 4)); } System.out.println("======== bucket 3 =========n"); for (int i = 20000; i < 20020; i++) { System.out.println(i+":"+jumpConsistentHash(i, 3)); } } }
運行結果

從輸出結果來看,結論如下:
1).當buckets=1的時候,對任意key,全部落在0上面。
2).當buckets=2時時候,為了使hash的結果保持均勻,jumpConsistentHash(k,2)的結果有佔比1/2的結果保持為0,有1/2跳變為1。
由此規律是:當buckets從n變化到n+1後,jumpConsistentHash(k,n+1)的結果中,應該有佔比n/(n+1) 的結果保持不變,而有 1/(n+1) 跳變為n+1。所以當n=2變成n+1=3後,jumpConsistentHash(k,3)的結果,有佔比2/3的結果保持不變,而有1/3的跳變成了2。而隨着這個bucket越來越大,它所變化的概率也就越來越低。
接下來我們來詳細測試一下。
1.啟動加載配置
在啟動dble之後,就會讀取rule.xml文件,加載上述配置。然後根據partitionCount產生物理分區表。
2.運行過程
如果有用戶通過where查詢name='buddy'的時候,就會訪問jumpstringhash分片算法,首先根據配置的hashSlice進行截取,這裡hashSlice0,3會把bud截取出來,然後在對這個截取的字符串做hash值。然後把hash值作為key,partitionCount作為bucket傳到jumpConsistentHash函數中。計算出最終一致的hash值。
3.我們建表來測試一下
3.1 在rule.xml配置下列內容
<tableRule name="rule_jumpHash"> <rule> <columns>name</columns> <algorithm>func_jumpHash</algorithm> </rule> </tableRule> <function name="func_jumpHash" class="jumpStringHash"> <property name="partitionCount">4</property> <property name="hashSlice">0:3</property> </function>
3.2 在schema.xml配置下列內容
<table name="test_jumphash" primaryKey="id" rule="rule_jumpHash" dataNode="dn1,dn2,dn3,dn4"/>
3.3 登錄管理端口,reload配置
[root@mysql5 ~]# mysql -uman1 -p -P9066 -h192.168.56.185 -p654321 mysql> reload @@config; Query OK, 1 row affected (0.39 sec) Reload config success
3.4 然後使用服務端口登錄到dble上執行建表測試語句。

可以發現,我們插入的數據buddy,然後存放在了dn4上面。我們來看下是怎麼計算的,我們的截取的字符是0,3,也就是截取'bud',前面計算過這個串hash出來的值是97905。具體算法參考《數據庫中間件分片算法之stringhash
》。然後我們把97905作為key,partitionCount作為bucket帶入到jumpConsistentHash函數計算。得到的結果正好是3,也就是該數據一定落在dn4分片上。
public static void main(String args[]) { System.out.println(jumpConsistentHash(97905,4)); } } [root@mysql5 ~]# java test4 3
注意事項:
- 分片字段值為NULL時,數據恆落在0號節點之上;當真實存在於mysql的字段值為not null的時候,報錯 "Sharding column can't be null when the table in MySQL column is not null"
後記
今天介紹了Jump Consistent Hash
算法,目前dble用這個算法取代了Mycat中更加傳統的環割一致性hash算法。當然這個裏面具體的算法細節還和概率論的一些知識有關,這裡只是給大家演示了一下。更加詳細的該算法介紹可以參考下面的鏈接。
參考鏈接
1.jump Consistent hash:零內存消耗,均勻,快速,簡潔,來自Google的一致性哈希算法https://blog.helong.info/blog/2015/03/13/jump_consistent_hash/
2.一致性哈希算法(consistent hash)的黑科技https://blog.csdn.net/weixin_33866037/article/details/92487450
3.分佈式 | dble 沿用 jumpstringhash,移除 Mycat 一致性 hash 原因解析https://blog.csdn.net/ActionTech/article/details/100703198