使用.Net Core實現FNV分佈式hash一致性算法

使用.Net Core實現FNV分佈式hash一致性算法

說到FNV哈希算法不得不提Memcached,咱們先簡單介紹一下Memcached。git

Memcached

Memcached分爲客戶端與服務端,Memcached是服務端,服務端自己不提供分佈式實現,只是一個單獨的k-v緩存;Memcached的分佈式是在客戶端類庫中實現的,也就是說你能夠根據本身的須要實現不一樣的分佈式方案,不必定非得使用FNV哈希算法github

Memcached經過FNV算法實現了服務的分佈式,並經過引入虛擬節點的辦法儘可能是服務器分佈的更均勻。已經有不少文章在介紹Memcached的分佈式實現原理了,因此我就不那麼多廢話了。算法

FNV分佈式hash算法實現

若是你還不瞭解FNV哈希算法,能夠先看一下我以前的文章,在那裏我摘錄了wiki上的FNV哈希算法實現公式。c#

FNV1算法實現

代碼實現上我將參考MD5算法的實現來編寫FNV1算法:數組

  1. 首先,我將建立一個FNV1類,該類須要實現HashAlgorithm,之因此實現HashAlgorithm,是由於該抽象類定義了hash算法通用的接口,這樣也可使咱們的實現與.net框架集成的更好,固然若是你不喜歡也能夠不實現HashAlgorithm,就當是寫了一個獨立的幫助類。緩存

  2. 而後,咱們重寫Create方法,這裏咱們將建立一個FNV1類的實例服務器

  3. 最後,咱們去實現這個FNV1類框架

    全部實現代碼以下:分佈式

//首先我將建立FNV1類 
public abstract class FNV1 : HashAlgorithm
{
    //重寫隱藏HashAlgorithm的Create方法
    public static new FNV1 Create()
    {
        return new Implementation();
    }
    //下面FNV1的實現咱們徹底是套用的公式沒有什麼好講的
    private sealed class Implementation : FNV1
    {
        private const uint OFFSETBASIS = 2166136261;
        private const uint PRIME = 16777619;
        private uint _hash;
        public override void Initialize()
        {
            _hash = OFFSETBASIS;
        }
        protected override void HashCore(byte[] array, int ibStart, int cbSize)
        {
            int end = ibStart + cbSize;
            for (var index = ibStart; index < end; index++)
            {
            _hash *= PRIME;
            _hash ^= array[index];
            }
        }
        protected override byte[] HashFinal()
        {
            return BitConverter.GetBytes(_hash);
        }
    }
}


## 使用方法

var bytes=Encoding.UTF8.GetBytes("Test");
var hashBytes=FNV1.Create().ComputerHash(bytes);
var hashValue=BitConverter.ToUInt32(hashBytes);

FNV其實還有FNV1a算法,與FNV1有些許的區別,這裏我就不一一實現了,你能夠參考FNV1的實現和FNV哈希算法來實現FNV1a算法。我有一個幫助類MicroFx.Cryptography分別實現了FNV1和FNV1a的32bit、64bit算法版本。

爲何使用FNV算法實現hash一致性

不管是分佈式算法仍是hash一致性算法都不僅有一種或幾種實現方案,但Memached爲何會選擇FNV算法,而不是md5,不是sha呢?我有本身的認識。

  1. 咱們先看幾行代碼,分別使用MD5,sha,FNV算法計算一個Test字符串的哈希值,而後對比hash結果中數組的長度

    var bytes = Encoding.UTF8.GetBytes("Test");
    var shabytes = SHA1.Create().ComputeHash(bytes); //shabytes長度爲20,及160bit
    var md5bytes=MD5.Create().ComputeHash(bytes);    //md5bytes長度爲16,及128bit
    var fnvbytes = FNV1a.Create().ComputeHash(bytes); //fnvbytes長度爲4,及32bit
    算法 取值範圍
    sha1 [0,2^160-1]
    md5 [0,2^128-1]
    fnv [0,2^32-1]

    從上表咱們能夠看出,FNV的取值範圍最小,若是將區間內的每個整數看作一個Memcached服務端節點,那麼FNV容納的數量最少,但相對於實際的環境下已經足夠多了,這樣咱們每次在計算一臺服務器屬於哪一個節點的時候速度上會比md五、sha1快不少。

  2. FNV的32bit計算結果值恰好是一個uint類型,.net core最大支持ulong也就是uint64,再大的話就須要咱們本身實現,因此這也是選擇FNV的一個緣由。(或許我這裏不該該拿.net舉例,但實際經常使用的高級語言最大也是64bit)

相關文章
相關標籤/搜索