背景
一般我們使用的hash就是md5 sha 之類的工具類,在負載均衡會要求類似同一個ip在增加節點時還是定位到之前的節點,這時就要用到一致性hash。具體實現代碼參考(基於google Guava):
使用谷歌 Guava 實現 Java 一致性哈希 (用於根據哈希Hash值平均分配的場景)一、介紹
MurmurHash算法:高運算性能,低碰撞率,由Austin Appleby創建於2008年,現已應用到Hadoop、libstdc++、nginx、libmemcached等開源系統。2011年Appleby被Google雇佣,隨后Google推出其變種的CityHash算法。
Java界中Redis,Memcached,Cassandra,HBase,Lucene都用它。
在Java的實現,Guava的Hashing類里有,上面提到的Jedis,Cassandra里都有Util類。
但存在的問題是由於Java的數據類型long與C語言中無符號長整型uint64_t有區別,導致Java輸出版本存在負數,針對這個問題進行了修改;另外需要注意的是中文不同編碼(UTF-8或GBK)會導致輸出結果的不同,使用中需要統一編碼。
p.s.一致性hash的實現算法,murmurhash和ketamahash。下面這篇文章有詳細的說明。
淺析ketamahash和murmurhash - 程序詩人 - 博客園二、原理

算法圖例

三、性能測試對比
import java.nio.charset.StandardCharsets; import org.apache.commons.codec.digest.DigestUtils; import com.google.common.hash.Hashing; public class Test { public static void main(String[] args) { System.out.println(murmur3Test("334324324234234sfsfsdfwwrtregreg")); long startTime=System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { Test.md5Test("KFETHGRETWERFSDFWEFWEFWF"); } long endTime=System.currentTimeMillis(); System.out.println("1000萬次md5Test算法程序運行時間: " + (endTime - startTime ) + "ms"); long startTime2=System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { Test.murmur3Test("KFETHGRETWERFSDFWEFWEFWF"); } long endTime2=System.currentTimeMillis(); System.out.println("1000萬次murmur3Test算法程序運行時間: " + (endTime2 - startTime2 ) + "ms"); } public static String murmur3Test(String primaryKey) { return Hashing.murmur3_32().hashString(primaryKey, StandardCharsets.UTF_8).toString() + "_" + primaryKey; } public static String md5Test(String primaryKey) { return DigestUtils.md5Hex(primaryKey)+ "_" + primaryKey; } }
結論:
MurmurHash算法比md5快一倍。
四、使用場景
1、根據uuid,通過hash算法進行取模分庫分表
2、用來計算出key的slot值
3、短鏈接
五、其他算法
ketamahash一致性哈希算法
由若干固定的虛擬節點來計算出每個虛擬節點的slots,數據存儲的時候,算出key的slot值,然后存入相鄰最近的虛擬節點
轉載hash函數MurmurHash_luoqinglong的專欄-CSDN博客