murmurhash3 学习笔记

简介: ## 背景 由于项目中有报文排重需求,所以会将报文字符串作为分布式锁key。 考虑到报文不定长并且散列性不太好,如其作为锁key,特别是当key值过大时,使用redis进行读写都会有相对的性能下降。 ``` 参考文献里测试对比: 长度为10:写平均耗时0.053ms,读0.040ms 长度为20000:写平均耗时0.352ms,读0.084ms ``` 一种简单的方案是

背景

由于项目中有报文排重需求,所以会将报文字符串作为分布式锁key。
考虑到报文不定长并且散列性不太好,如其作为锁key,特别是当key值过大时,使用redis进行读写都会有相对的性能下降。

参考文献里测试对比:
长度为10:写平均耗时0.053ms,读0.040ms
长度为20000:写平均耗时0.352ms,读0.084ms

一种简单的方案是对报文进行一次md5,然后拿来做key。
考虑到md5的性能并不高,找到了更合适的murmurhash3非加密哈希算法:

Screen Shot 2018-09-10 at 5.46.22 PM.png

算法图例

murmurhash_diagram.png

(可以看到里面有c1, c2, n 三个很特别的常量,据算法作者Austin Appleby讲,都是他血汗地用大量测试数据调测出来的,为了不被其他好事之徒当头一暴击,他保留继续微调的权利。)

参考文档里都说murmurhash3棒棒的,但是不实践下还是不能随意拿来进献给Boss, 我找了一个代码,做了一个性能对比,测试使用了Google的guava里的Hashing.murmur3_32(),对比apache的commons-lang3的md5Hex算法。

测试源码

public class HashTest {

    public static String md5Test(String primaryKey) {
        return DigestUtils.md5Hex(primaryKey).substring(0, 4) + "_" + primaryKey;
    }

    public static String murmur3Test(String primaryKey) {
        return Hashing.murmur3_32().hashString(primaryKey, StandardCharsets.UTF_8).toString().substring(0, 4) + 
            "_" + primaryKey;
    }
}

跑测试源码如下(为方便直接用了Spock单测脚本):


@Unroll
class HashTestSpec extends Specification {

    def "HashTest md5 & murmurhash3"() {
        long startTime=System.currentTimeMillis()
        for (int i = 0; i < 10000; i++) {
            HashTest.md5Test(getRandomString(10))
        }
        long endTime=System.currentTimeMillis()
        print "1万次md5算法程序运行时间: " + (endTime - startTime ) + "ms"
        print "\n"

        long startTime2=System.currentTimeMillis()
        for (int i = 0; i < 10000; i++) {
            HashTest.murmur3Test(getRandomString(10))
        }
        long endTime2=System.currentTimeMillis()
        print "1万次murmurhash3算法程序运行时间: " + (endTime2 - startTime2 ) + "ms"
        expect:
        1==1
    }
}

对比测试结果:
1万次md5算法程序运行时间: 235ms
1万次murmurhash算法程序运行时间: 73ms

有4倍的差距。

按参考文档建议,换成murmur3_128,1万次murmurhash算法程序运行时间: 51ms, 果然更优秀。

getRandomString的参考代码也一并附上,方便好事之徒做复现。

    public static String getRandomString(int length){
        String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random=new Random();
        StringBuffer sb=new StringBuffer();
        for(int i=0;i<length;i++){
            int number=random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

参考

目录
相关文章
|
SQL 开发框架 JSON
honeycomb使用|学习笔记
快速学习honeycomb使用
683 0
honeycomb使用|学习笔记
|
存储 消息中间件 弹性计算
尘央大佬带你学| 学习笔记
快速学习尘央大佬带你学。
152 0
尘央大佬带你学| 学习笔记
|
开发者
整合的实现 | 学习笔记
快速学习整合的实现.
整合的实现 | 学习笔记
|
数据采集 SQL 消息中间件
第三阶段总结|学习笔记
快速学习第三阶段总结
131 0
第三阶段总结|学习笔记
|
数据可视化 Java 开发工具
超详细的vimtutor学习笔记(中)
第一讲 编辑 1.1 移动光标 使用 h、j、k、l 键可以使光标实现左、下、上、右的移动。 也可以使用 ↑ ↓ ← → 进行上下左右的移动。
106 0
|
存储 Java 开发者
BinaryTree|学习笔记
快速学习BinaryTree
BinaryTree|学习笔记
|
前端开发 Java 网络架构
合法性检查|学习笔记
快速学习合法性检查
178 0
|
云安全 安全 网络安全
总结 | 学习笔记
快速学习总结
104 0
|
Python
雨痕大神的《学习笔记系列》
雨痕大神的《学习笔记》可以在他的GitHub(https://github.com/qyuhen/book)下载,7000+的Star,足以证明认可度。 笔记系列陆陆续续在出版,已出版的有: 《Python 3学习笔记(上卷)》https://www.
3706 0
|
Java 开发者
接口标准|学习笔记
快速学习接口标准
103 0
接口标准|学习笔记