• 三、MurmurHash使用
  • 四、性能测试

  • MurmurHash:(multiply and rotate) and (multiply and rotate) Hash,乘法和旋转的hash 算法。

    一、哈希函数

    散列函数(英语:Hash function)又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values,hash codes)的指纹。散列值通常用一个短的随机字母和数字组成的字符串来代表。好的散列函数在输入域中很少出现散列冲突。

    加密:加密存在数据库中的密码(password)字符串,由于散列算法所计算出来的散列值(Hash Value)具有不可逆(无法逆向演算回原本的数值)的性质,因此可有效的保护密码。

    压缩:把任意长度的输入通过散列算法变换成固定长度的输出。

    保护资料、确保传递真实的信息、散列表、错误校正、语音识别、信息安全。。。

    常见哈希算法

    MD系列(MD5)、SHA系列(SHA-1)、CRC,甚至JDK hashCode()也是哈希算法的一种。可以将他们分成三代:

    第一代:SHA-1(1993),MD5(1992),CRC(1975),Lookup3(2006)
    第二代:MurmurHash(2008)
    第三代:CityHash, SpookyHash(2011)

    分类可分为加密型、非加密型:

    加密型:MD系列(MD5)、SHA系列(SHA-1)

    非加密型:CRC、MurmurHash

    这里记录一下在第二代中几乎一统江湖的MurmurHash。

    二、murmurhash

    MurmurHash 是一种 非加密型哈希函数 ,适用于一般的哈希检索操作。由Austin Appleby在2008年发明,并出现了多个变种,都已经发布到了公有领域(public domain)。与其它流行的哈希函数相比,对于规律性较强的key,MurmurHash的随机分布特征表现更良好。

    MurMurHash3 比 MD5 快。

    2.低碰撞。

    MurMurHash3 128 位版本哈希值是 128 位的,跟 MD5 一样。128 位的哈希值,在数据量只有千万级别的情况下,基本不用担心碰撞。

    3.高混淆。

    散列值比较“均匀”,如果用于哈希表,布隆过滤器等, 元素就会均匀分布。

    广泛应用于各开源产品,Java 界中 Redis,Memcached,Cassandra,Hadoop,HBase,Lucene,spark,nginx,常见的大数据库底层,都使用了这个算法作为底层的存储算法。

    MD5 生成的哈希值是 128 比特的。这里的哈希值指的是二进制的值,而不是 HEX 或 base64 格式化后的人类可读的值。通常我们提到的 32 位 MD5 是指由 32 个字符组成的,HEX 格式的 MD5。MurMurHash 算法家族的最新一员为MurMurHash3,支持32位和128位,推荐使用128位的MurMurHash3。是原作者被Google挖去之后基于Murmur2的缺陷做了改进。

    32位的,在某些场景下,比如哈希的对象长度小于 128 位,或者存储空间要求占用小,或者需要把字符串转换成一个整数,这一特性就能帮上忙。当然,32 位哈希值发生碰撞的可能性就比 128 位的要高得多。当数据量达到十万时,就很有可能发生碰撞。

    贴一个网上的简单 MurMurHash2、MurMurHash3、MD5 的 benchmark:

    https://github.com/spacewander/lua-resty-murmurhash3/blob/master/README.md#when-should-i-use-it

    这里的结论:MurMurHash3 128 位版本的速度是 MD5 的十倍。有趣的是,MurMurHash3 生成 32 位哈希的用时比生成 128 位哈希的用时要长。原因在于MurMurHash3_128 针对现代 x64 平台cpu进行了优化。

    Murmur是一个良好的通用散列函数系列,适用于非加密用法。MurmurHash提供以下好处:

    简单(根据生成的汇编指令数量)。
    良好的分布(几乎所有键组和铲斗尺寸均通过卡方检验。
    好 雪崩 行为(最大偏差0.5%)。
    良好的碰撞阻力(通过Bob Jenkin的frog.c酷刑测试。对于4字节键没有碰撞,没有小的(1到7位)差异)。
    在Intel/AMD硬件上表现出色,散列质量和CPU消耗之间的良好折衷。
    

    您当然可以使用它来散列UUID(就像任何其他高级散列函数一样:CityHash,Jenkins,Paul Hsieh等等)。现在,Redis bitset限制为4 GB位(512 MB)。因此,您需要将128位数据(UUID)减少到32位(散列值)。无论散列函数的质量如何,都会发生碰撞。

    使用像Murmur这样的工程散列函数可以最大限度地提高分布质量,并最大限度地减少碰撞次数,但它不提供任何其他保证。

    三、MurmurHash使用

    Java版:google guava 包中提供了使用工具类:

    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1.1-jre</version>
    
    import java.nio.charset.StandardCharsets;
    import com.google.common.hash.HashFunction;
    import com.google.common.hash.Hashing;
    public class MurmurHashTest {
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                String hexHashString = getHexHashString("qwerqwerqwer");
                System.out.println(hexHashString);
        public static String getHexHashString(String str) {
            HashFunction hashFunction = Hashing.murmur3_128();
            return hashFunction.hashString(str, StandardCharsets.UTF_8).toString();
    

    四、性能测试

    public class MurmurHashTest {
        public static void main(String[] args) {
            long l = System.nanoTime();
            for (int i = 0; i < 10000 * 10000; i++) {
                String hexHashString = getHexHashString("yzh123456qwer杨子");
                // System.out.println(hexHashString);
            long time = System.nanoTime() - l;
            System.out.println("一亿数据,一共花费时间:" + time / (1000 * 1000 * 1000) + "秒");
            long ns = time / (10000 * 10000);
            System.out.println("一亿数据,每条数据花费时间:" + ns + "纳秒");
        public static String getHexHashString(String str) {
            HashFunction hashFunction = Hashing.murmur3_128();
            return hashFunction.hashString(str, StandardCharsets.UTF_8).toString();
    
    一亿数据,一共花费时间:20秒
    一亿数据,每条数据花费时间:200纳秒
    

    MD5的性能测试:

    public class MurmurHashTest {
        public static void main(String[] args) {
            long l = System.nanoTime();
            for (int i = 0; i < 10000 * 10000; i++) {
                String hexHashString = getHexMD5String("yzh123456qwer杨子");
                // System.out.println(hexHashString);
            long time = System.nanoTime() - l;
            System.out.println("一亿数据,一共花费时间:" + time / (1000 * 1000 * 1000) + "秒");
            long ns = time / (10000 * 10000);
            System.out.println("一亿数据,每条数据花费时间:" + ns + "纳秒");
        public static String getHexMD5String(String str) {
            return DigestUtils.md5DigestAsHex(str.getBytes());
    

    MD5结果:

    一亿数据,一共花费时间:32秒
    一亿数据,每条数据花费时间:323纳秒
    

    本人测试的字符串比较短,也可能是jar包不同版本以及使用的MacOS版本问题,虽然MurmurHash是比MD5快,但没有达到10倍的性能差距。

    其它性能测试,含 hutool 包下的MurmurHash.hash64的使用:

    package com.yy.armor.engine.core;
    import java.nio.charset.StandardCharsets;
    import cn.hutool.core.lang.MurmurHash;
    import com.google.common.hash.HashFunction;
    import com.google.common.hash.Hashing;
    import org.springframework.util.DigestUtils;
    public class MurmurHashTest {
        public static void main(String[] args) {
            String hexHashString = getHexHashStringWithGoogle128("user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36");
            System.out.println("getHexHashStringWithGoogle128=" + hexHashString);
            String hexHashString2 = getHexHashStringWithGoogle32("user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36");
            System.out.println("getHexHashStringWithGoogle32=" + hexHashString2);
            String hexHashString3 = getHexHashStringWithHutool64("user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36");
            System.out.println("getHexHashStringWithHutool64=" + hexHashString3);
            String hexHashString4 = getHexMD5String("user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36");
            System.out.println("getHexMD5String=" + hexHashString4);
            long l = System.nanoTime();
            for (int i = 0; i < 10000 * 10000; i++) {
                getHexHashStringWithGoogle128("user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36");
            long time = System.nanoTime() - l;
            System.out.println("一亿数据,getHexHashStringWithGoogle128一共花费时间:" + time / (1000 * 1000 * 1000) + "秒");
            long l2 = System.nanoTime();
            for (int i = 0; i < 10000 * 10000; i++) {
                getHexHashStringWithGoogle32("user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36");
            long time2 = System.nanoTime() - l2;
            System.out.println("一亿数据,getHexHashStringWithGoogle32一共花费时间:" + time2 / (1000 * 1000 * 1000) + "秒");
            long l3 = System.nanoTime();
            for (int i = 0; i < 10000 * 10000; i++) {
                getHexHashStringWithHutool64("user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36");
            long time3 = System.nanoTime() - l3;
            System.out.println("一亿数据,getHexHashStringWithHutool64一共花费时间:" + time3 / (1000 * 1000 * 1000) + "秒");
            long l4 = System.nanoTime();
            for (int i = 0; i < 10000 * 10000; i++) {
                getHexMD5String("user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36");
            long time4 = System.nanoTime() - l4;
            System.out.println("一亿数据,getHexMD5String一共花费时间:" + time4 / (1000 * 1000 * 1000) + "秒");
        public static String getHexHashStringWithGoogle128(String str) {
            HashFunction hashFunction = Hashing.murmur3_128();
            return hashFunction.hashString(str, StandardCharsets.UTF_8).toString();
        public static String getHexHashStringWithGoogle32(String str) {
            HashFunction hashFunction = Hashing.murmur3_32();
            return hashFunction.hashString(str, StandardCharsets.UTF_8).toString();
        public static String getHexHashStringWithHutool64(String data) {
            long hash64 = MurmurHash.hash64(data);
            return Long.toHexString(hash64);
        public static String getHexMD5String(String str) {
            return DigestUtils.md5DigestAsHex(str.getBytes());
    
    getHexHashStringWithGoogle128=3f3d5e5f32f9fff6a34dfa6329a83bf7
    getHexHashStringWithGoogle32=2cb92c51
    getHexHashStringWithHutool64=4742386bfc5110a8
    getHexMD5String=05fbb1053d692f9f6730d1a24e577a92
    一亿数据,getHexHashStringWithGoogle128一共花费时间:36秒
    一亿数据,getHexHashStringWithGoogle32一共花费时间:19秒
    一亿数据,getHexHashStringWithHutool64一共花费时间:18秒
    一亿数据,getHexMD5String一共花费时间:62秒
                                        MurmurHash是一种非加密的高效哈希函数,由 Austin Appleby 开发。它主要用于哈希表和数据分布等场景。Base62编码是一种将数据压缩成更短字符串的编码方式,它使用 62 个字符:0-9、A-Z 和 a-z。Base62 编码广泛用于生成简短、可读性强的标识符。通过结合使用MurmurHash和Base62编码,我们可以高效生成短链接,解决长 URL 带来的不便。这种方法不仅适用于 URL 缩短,还可以广泛应用于生成唯一标识符和缓存键等场景。
    一致性哈希提出了在动态变化的Cache环境中,哈希算法应该满足的4个适应条件:
    平衡性(Balance)
    平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。
    单调性(Monotonicity)
    单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的
                                        MurmurHash2是一种广泛使用的非加密哈希函数,由Austin Appleby在2008年设计。它旨在提供高速的哈希计算,同时保持较低的碰撞率。MurmurHash的名字来源于两个操作:“乘法(multiply)”和“旋转(rotate)”,这两个操作是算法的核心部分。MurmurHash算法有几个版本,MurmurHash2是其中的一个版本,其它版本包括MurmurHash1、MurmurHash3等。高性能:它非常快,尤其是对小数据块的哈希计算,这使得它非常适合用于哈希表等数据结构。分布均匀。
      MurmurHash 是一种非加密型哈希函数,适用于一般的哈希检索操作。 由Austin Appleby在2008年发明, 并出现了多个变种,都已经发布到了公有领域(public domain)。与其它流行的哈希函数相比,对于规律性较强的key,MurmurHash的随机分布特征表现更良好。—摘自w...
                                        MurmurHash是一种高效、分布均匀且广泛应用的非加密哈希函数。它在数据处理和存储的多个领域都有着重要的应用,尤其适合那些对性能有高要求的场景。然而,需要注意的是,MurmurHash不适用于安全敏感的应用。
                                        1.数据库中索引概念
    在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。
    2.索引优点和缺点
    索引可以避免全表扫描,加快查询速度。多数查询可以仅扫描少量索引页及数据页,而不是遍历所有...
                                        MurmurHash 是一种高性能的哈希算法,由 Austin Appleby 在 2008 年创建。它是一种非加密哈希算法,可以快速地计算出任意数据的哈希值。MurmurHash 算法的特点是快速、高效、低碰撞、低冲突,适用于各种哈希表、哈希集合、哈希映射等数据结构。它的哈希值分布均匀,哈希冲突率低,能够更好地处理哈希碰撞和哈希冲突。MurmurHash 算法的原理是将输入数据分成若干个块,每个块都使用不同的哈希函数计算出一个哈希值,然后将这些哈希值进行混合和运算,得到最终的哈希值。
                                        Murmurhash: 是一种非加密型哈希函数,适用于一般的哈希检索操作。高运算性能,低碰撞率,由Austin Appleby创建于2008年,现已应用到Hadoop、libstdc++、nginx、libmemcached等开源系统。2011年Appleby被Google雇佣,随后Google推出其变种的CityHash算法。
    一致性哈希算法的主要步骤:
    首先求出缓存服务器结...
                                        MurmurHash是一种高效的非加密哈希函数,适用于哈希表中的一般哈希任务。MurmurHash的名称来源于Murmur,意为一种低频的声音,体现了其设计的低碰撞率和高性能。名称来自两个基本操作,乘法(MU)和旋转(R),在其内部循环中使用。与其它流行的哈希函数相比,对于规律性较强的key,MurmurHash的随机分布特征表现更良好。MurmurHash与加密散列函数不同,它不是专门设计为难以被对手逆转,因此不适用于加密目的。
                                        加密哈希和非加密哈希-MM是非加密哈希
    首先了解下加密哈希和非加密哈希,
    加密哈希函数旨在保证安全性,很难找到碰撞。即:给定的散列h很难找到的消息m;很难找到产生相同的哈希值的消息m1和m2。
    非加密哈希函数只是试图避免非恶意输入的冲突。作为较弱担保的交换,它们通常更快。如果数据量小,或者不太在意哈希碰撞的频率,甚至可以选择生成哈希值小的哈希算法,占用更小的空间。
    Smhasher-评价哈希算法的...
                                        Murmur哈希是一种非加密函数的哈希函数,下面我们在介绍哈希函数之前我们需要了解一下什么是好的哈希函数。
    1.好的哈希函数应该卡方测试(chi-squared test)
    卡方测试:
    Xc2=∑i=0N−1(Oi−Ei)2/Ei,其中Oi为观察量,而Ei为估计量{X_c^2 = \sum_ {i=0}^{N-1}(O_i-E_i)^2/E_i},其中O_i为观察量,而E_i为估计量Xc2​=∑i=0N−1​(Oi​−Ei​)2/Ei​,其中Oi​为观察量,而Ei​为估计量
    我们测试的方案就是给出大量的数据