MurmurHash算法及應用場景

算法簡介

Murmur哈希算法是一種非加密型哈希算法,適用於一般的哈希檢索操作,由Austin Appleby創建於2008年。

之所以說是非加密型,與追求安全的MD5算法不同,它不是專門設計為不可逆轉破解,而是追求高性能與低碰撞率。這兩個特性會在下文做具體代碼驗證。

算法解讀

Murmur哈希算法名稱由來就是它的計算過程:Multiply and Rotate,且在哈希的過程中需要經歷多次Multiply and Rotate,因此取名叫Murmur,核心思路就是下面這幾行代碼(Guava中的算法實現):

MurmurHash算法及應用場景

Guava中的Murmur3_32實現

可以看到是一個while循環,每次處理4個字符,對這四個字符做:

MurmurHash算法及應用場景

其中mixK1方法如下:

MurmurHash算法及應用場景

將計算到的k1旋轉rotateLeft方法:

MurmurHash算法及應用場景

再根據算出來的k1執行mixH1方法:

MurmurHash算法及應用場景

大家要記住幾個關鍵變量或常量:C1、C2、h1、k1。

k1怎麼來的?

int k1 = c0 | (c1 << 8) | (c2 << 16) | (c3 << 24);

h1就是seed,隨機數種子,可以自己生成或使用默認的。

其中的C1和C2常量如下:

MurmurHash算法及應用場景

為什麼是這個值呢?其實都是Austin Appleby經過大量實驗計算得出來的一個最優數字。

這個算法核心思想就是不斷的“k1 *= C1; k1 = rotateLeft(k1, r);”,所以取名叫murmurhash,這樣是不是就好記住一點,或者叫陌陌哈希,陌陌總能記住了吧?

實際應用

Murmur算法在Java中有很多具體的實現:

Guava的Hashing:

https://github.com/google/guava/blob/master/guava/src/com/google/common/hash/Murmur3_32HashFunction.java

Jedis中的MurmurHash:

https://github.com/xetorthio/jedis/blob/master/src/main/java/redis/clients/util/MurmurHash.java

Cassandra中的MurmurHash:

https://github.com/apache/cassandra/blob/aa7c7362a94dd3da81ff521589cd2e6f998ae4c1/src/java/org/apache/cassandra/utils/MurmurHash.java

性能測試

比較常用的MD5算法和Murmurhash算法對字符串加密的性能,先寫對應的兩個方法:

MurmurHash算法及應用場景

對隨機字符串10w次加密隨機生成的100位字符串測試耗時:

MurmurHash算法及應用場景

測試結果:

MD5總耗時:897ms

Murmurhash總耗時:294ms

低碰撞率

Murmurhash的哈希劇烈度要比Java自帶的HashCode()要高,高劇烈度即代表著低碰撞率,Hash表的低碰撞率代表著更高的性能。

代碼驗證一下Murmurhash和jdk自帶的hashcode的散列值:

MurmurHash算法及應用場景

輸出如下:

MurmurHash算法及應用場景

可以看到,對於兩個相近的字符串,hashcode的值只相差1位數,而Murmurhash卻相差十萬八千里。瞭解hash數據結構的相信大家已經知道意味著什麼了。

拓展閱讀

  • 大家都知道redis中的字典的概念,而字典的底層數據結構就是用哈希表來實現的,哈希算法採用的正式Murmurhash算法。
  • 經常用redis作為緩存數據庫的同學可能清楚,我們設置一個key的時候,不宜把key設置過長,否則會影響性能。
  • 大家可以自己寫一個測試用例,生成不同長度的key,讀寫1000次,看看鍵的長度對redis性能的影響。如果我們平時需要用到長key作為分佈式redis鎖的高併發場景,可以考慮採用Murmurhash算法把key縮短一下。
  • 當涉及到非加密安全要求的場景下,可以考慮取代MD5算法。


分享到:


相關文章: