背景
一般我们使用的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博客