精华内容
下载资源
问答
  • 多种哈希算法代码,用于文件校验、简单加密等场合。
  • 哈希摘要 - 数字签名/指纹 - 单向哈希函数(没有反函数不可逆) 应用领域: 1. 数据库种的用户敏感信息保存成哈希摘要 2. 给数据生成签名验证数据没有被恶意篡改 3. 云存储服务的妙传功能(去重功能) ''' class ...
    # -*- coding:utf8 -*-
    '''
    哈希摘要 - 数字签名/指纹 - 单向哈希函数(没有反函数不可逆)
    应用领域:
    1. 数据库种的用户敏感信息保存成哈希摘要
    2. 给数据生成签名验证数据没有被恶意篡改
    3. 云存储服务的妙传功能(去重功能)
    '''
    
    
    class StreamHasher():
        """摘要生成器"""
    
        def __init__(self, algorithm='md5', size=4096):
            """初始化方法
            @params:
                algorithm - 哈希摘要算法
                size - 每次读取数据的大小
            """
            self.size = size
            cls = getattr(__import__('hashlib'), algorithm.lower())
            self.hasher = cls()
    
        def digest(self, file_stream):
            """生成十六进制的摘要字符串"""
            # log = file_stream.read(self.size)
            # while log:
            #     self.hasher.update(log)
            #     log = file_stream.read(self.size)
            for data in iter(lambda: file_stream.read(self.size), b''):
                self.hasher.update(data)
            return self.hasher.hexdigest()
    
        def __call__(self, file_stream):
            return self.digest(file_stream)
    
    
    def main():
        """主函数"""
        hasher1 = StreamHasher()
        hasher2 = StreamHasher('sha1')
        hasher3 = StreamHasher('sha256')
        with open('zbar-0.10.tar.bz2', 'rb') as file_stream:
            print(hasher1.digest(file_stream))
            file_stream.seek(0, 0)
            print(hasher2.digest(file_stream))
            file_stream.seek(0, 0)
            print(hasher3(file_stream))
    
    
    if __name__ == '__main__':
        main()
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    展开全文
  • 9种哈希算法代码

    2012-08-02 09:34:00
    // 这个算法在开源的SDBM中使用,似乎对很多不同类型的数据都能得到不错的分布。 unsigned int SDBMHash(const char *str) { unsigned int hash = 0 ; while (*str) { // equivalent to: hash = 65599*...
    // 这个算法在开源的SDBM中使用,似乎对很多不同类型的数据都能得到不错的分布。
    unsigned int SDBMHash(const char  *str)
    {
        unsigned int hash =  0 ;
        while  (*str)
        {
            // equivalent to: hash = 65599*hash + (*str++);
            hash = (*str++) + (hash << 6 ) + (hash <<  16 ) - hash;
        }
    
        return  (hash &  0x7FFFFFFF );
    }
    
    // 从Robert Sedgwicks的 Algorithms in C一书中得到。
    // 已经添加了一些简单的优化的算法,以加快其散列过程。
    unsigned int  RSHash(const char  *str)
    {
        unsigned int  b =  378551 ;
        unsigned int  a =  63689 ;
        unsigned int  hash =  0 ;
    
        while  (*str)
        {
            hash = hash * a + (*str++);
            a *= b;
        }
        return  (hash &  0x7FFFFFFF );
    }
    
    // Justin Sobel写的一个位操作的哈希函数。
    unsigned int  JSHash(const char  *str)
    {
        unsigned int  hash =  1315423911 ;
    
        while  (*str)
        {
            hash ^= ((hash << 5 ) + (*str++) + (hash >>  2 ));
        }
    
        return  (hash &  0x7FFFFFFF );
    }
    
    // 该散列算法是基于贝尔实验室的彼得J温伯格的的研究。
    // 在Compilers一书中(原则,技术和工具),建议采用这个算法的散列函数的哈希方法。
    unsigned int  PJWHash(const char  *str)
    {
        unsigned int  BitsInUnignedInt = (unsigned  int )(sizeof(unsigned  int ) *  8 );
        unsigned int  ThreeQuarters  = (unsigned  int )((BitsInUnignedInt  *  3 ) /  4 );
        unsigned int  OneEighth = (unsigned  int )(BitsInUnignedInt /  8 );
        unsigned int  HighBits = (unsigned  int )( 0xFFFFFFFF ) << (BitsInUnignedInt
    
                                                   - OneEighth);
        unsigned int  hash   =  0 ;
        unsigned int  test   =  0 ;
    
        while  (*str)
        {
            hash = (hash << OneEighth) + (*str++);
            if  ((test = hash & HighBits) !=  0 )
            {
                hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
            }
        }
    
        return  (hash &  0x7FFFFFFF );
    }
    
    // 和PJW很相似,在Unix系统中使用的较多。
    unsigned int  ELFHash(const char  *str)
    {
        unsigned int  hash =  0 ;
        unsigned int  x  =  0 ;
        while  (*str)
        {
            hash = (hash << 4 ) + (*str++);
            if  ((x = hash & 0xF0000000L) !=  0 )
            {
                hash ^= (x >> 24 );
                hash &= ~x;
            }
        }
        return  (hash &  0x7FFFFFFF );
    }
    
    // 这个算法来自Brian Kernighan 和 Dennis Ritchie的 The C Programming Language。
    // 这是一个很简单的哈希算法,使用了一系列奇怪的数字,形式如31,3131,31...31,看上去和DJB算法很相似。
    unsigned int  BKDRHash(const char  *str)
    {
        unsigned int  seed =  131 ;  // 31 131 1313 13131 131313 etc..
        unsigned int  hash =  0 ;
        while  (*str)
        {
            hash = hash * seed + (*str++);
        }
        return  (hash &  0x7FFFFFFF );
    }
    
    // 这个算法是Daniel J.Bernstein 教授发明的,是目前公布的最有效的哈希函数。
    unsigned int  DJBHash(const char  *str)
    {
        unsigned int  hash =  5381 ;
    
        while  (*str)
        {
            hash += (hash << 5 ) + (*str++);
        }
        return  (hash &  0x7FFFFFFF );
    }
    
    // 这是本文作者Arash Partow贡献的一个哈希函数,继承了上面以旋转以为和加操作。
    unsigned int  APHash(const char  *str)
    {
        unsigned int  hash =  0 ;
        int  i;
    
        for  (i= 0 ; *str; i++)
        {
            if  ((i &  1 ) ==  0 )
            {
                hash ^= ((hash << 7 ) ^ (*str++) ^ (hash >>  3 ));
            }
            else
            {
                hash ^= (~((hash << 11 ) ^ (*str++) ^ (hash >>  5 )));
            }
        }
    
        return  (hash &  0x7FFFFFFF );
    }
    
    // 由伟大的Knuth在《编程的艺术 第三卷》的第六章排序和搜索中给出。
    unsigned int DEKHash(const char *str)
    {
          int len=strlen(str);
          unsigned int hash = len;
          for(int i = 0; i < len; i++)
          {
             hash = ((hash << 5) ^ (hash >> 27)) ^ str[i];
          }
          return hash;
    }

    转载于:https://www.cnblogs.com/goodness/archive/2012/08/02/2619347.html

    展开全文
  • 局部敏感哈希算法代码
  • 1.常见的数据查找算法:众所周知,顺序查找是最简单的查找方式,但要将所有数据遍历一遍所以效率相对较低,对大数据量的査找问题显然不行。...哈希算法也是一种查找算法,可以说哈希算法是最快的查找算法...

    1.常见的数据查找算法:

    众所周知,顺序查找是最简单的查找方式,但要将所有数据遍历一遍所以效率相对较低,对大数据量的査找问题显然不行。二分查找的查找效率虽然非常高但是数据必须有序,而对数据排序通常需要更多的时间,因此只适用于在排好序的数据中找。而深度优先搜索算法、广度优先搜索算法 ,是一种暴力査找法优化算法,同样对大数据量的查找问题效率也不高。哈希算法也是一种查找算法,可以说哈希算法是最快的查找算法。对于查找问题,哈希算法一直是首选算法。

    2.算法原理及特点:

    1> 简单来说,就是把一些复杂的数据通过某种函数映射关系映射成更加易于査找的方式。每个数据都会映射为独一无二的地址,数据存储时它会存储于这个地址取数据时还会在这个地址取。哈希算法就像一本字典,当需要査词的时候通过目录找到页码,再到对应页码就能找到所需要的内容了。

    用书面语解释就是:根据总体数据量预先设置一个数组,使用一个哈希函数并以数据的关键字作为自变量得到唯一的返回值。这样就可以利用哈希函数将数据元素映射到数组的某位置并把数据存放在对应位置上。在查找时,通过哈希函数计算该数据应该存储在哪里再到相应的存储位置取出查找的数据。

    2> 哈希算法的查找速度与数据多少无关,在没有发生”碰撞”或“溢出”的情况下,只需一次读取。同时该算法的保密性特别好,如果事先不知道哈希函数就无法进行查找从而获得数据。(注意:设计一个好的哈希函数是重中之重,好的哈希函数应该使每个关键字都尽可能地散列到每一个位置中去。面对的第一个问题就是如何设计一个易于计算并且均匀分布所有的键的哈希函数。)

    2.常见算法:(除法哈希算法、乘法哈希算法、平方取中法、随机数哈希算法等。)

    除法哈希算法:用每一个关键字去除以一个特定的质数,所得的余数就是该关键字的哈希值。通过 x 除以 m 的余数将关键字映射到数组的 m 个位置中。

    除哈希函数公式为  :                h(x) = x mod m

    举个例子,设计一个程序,以除留余数法的哈希算法取得索引值,再用线性探测法来储存数据。(线性探测法是用于处理当数据发生碰撞时,若该索引对应的储存位置已有数据,则会以线性的方式依次往后寻找空的存储位置且此时该方法将存储的位置视为一个环形结构,如果后面的位置被填满而前面还有位置时数据还可以放在前面。但线性探测法也有缺点,相似的键值对经常会汇聚在一起,因此平方探测法(或称为二次探测法)也经常被使用,只不过此处并不讨论。)

    import random

    INDEXBOX=10 #哈希表最大元素

    MAXNUM=7 #最大数据个数

    def print_data(data,max_number): #打印数组子程序

    print('\t',end='')

    for i in range(max_number):

    print('[%2d] ' %data[i],end='')

    print()

    #线性探测法

    def create_table(num,index): #建立哈希表子程序

    tmp=num%INDEXBOX #哈希函数 = 数据%INDEXBOX

    while True:

    if index[tmp]==-1: #如果数据对应的位置是空的

    index[tmp]=num #则直接存入数据

    break

    else:

    tmp=(tmp+1)%INDEXBOX #否则往后找位置存放

    #主程序

    index=[None]*INDEXBOX

    data=[None]*MAXNUM

    print('原始数组值:')

    for i in range(MAXNUM): #起始数据值

    data[i]=random.randint(1,20)

    for i in range(INDEXBOX): #清除哈希表

    index[i]=-1

    print_data(data,MAXNUM) #打印起始数据

    print('哈希表的内容:')

    for i in range(MAXNUM): #建立哈希表

    create_table(data[i],index)

    print(' %2d =>' %data[i],end='') #打印单个元素的哈希表位置

    print_data(index,INDEXBOX)

    print('完成的哈希表:')

    print_data(index,INDEXBOX) #打印最后完成的结果

    结果:

    乘法哈希算法:对给定的长度为 m 的数组,用关键字 x 乘以一个常数 N, N 的值为大于0 并小于 1 的一个小数,并提取出 Nx 的小数部分。之后,用 m 乘以这个小数,再向下取整哈希函数公式为:           h(x) = ⌊m(Nx mod 1)⌋

    (⌊,⌋,表示向下取整,其中 Nx mod 1 的意思就是 x 的小数部分。相对于除法哈希算法,乘法哈希算法对于数组的长度 m 没有过多的要求。研究表明N 的值为 0.618 较好。)

    例:关键字 8 需要存储,哈希函数为 h(x) = ⌊10 × (0.618x mod 1)⌋,

    计算过程如下:h(8) = ⌊10 × (0.618 × 8 mod 1)⌋ = ⌊10 × (4.944 mod 1)⌋ = ⌊10 × 0.944⌋ = ⌊9.44⌋ = 9

    那么利用哈希函数存储的数据如图所示,注意数组下标从 0 开始。

    平方取中法:首先计算出关键字的平方值,然后取平方值中间几位作为哈希地址。哈希函数公式为:

    h(x) = mid(x · x,n)      (其中 mid 的意思就是选取中间 n 位的函数。)

    例:关键字的集合为 [123,234,245], 它们对应的平方值为[15129,54756,60025],如果我们选择平方值的千位和百位作为哈希值,则它们的哈希值为 [51,47,0]。

    例如,关键字 245 需要存储,哈希函数为 h(x) = mid(x·x,2),计算过程如下:

    h(245) = mid(245 × 245,2) = mid(60025,2) = 0

    那么利用哈希函数存储的数据如图所示,注意数组下标从 0 开始。

    展开全文
  • 今天我想先给大家科普下一致性哈希算法这块,因为我下一篇文章关于缓存的高可用需要用到这个,但是又不能直接在里面写太多的代码以及关于一致性hash原理的解读,这样会失去对于缓存高可用的理解而且会造成文章很长,...

    8e96b130f704c7425c37eaf72b5f826d.png

    今天我想先给大家科普下一致性哈希算法这块,因为我下一篇文章关于缓存的高可用需要用到这个,但是又不能直接在里面写太多的代码以及关于一致性hash原理的解读,这样会失去对于缓存高可用的理解而且会造成文章很长,有担心有些朋友还没接触过一致性哈希算法,所以,我就将它单独拎出来讲一下。

    什么是一致性哈希

    一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系 。一致性哈希解决了简单哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的动态伸缩等问题。

    一致性哈希算法一般用来干什么

    一般我们在项目的负载均衡上要求资源被均匀的分配到所有的服务器节点上,同时,还需要对资源的请求能迅速的路由到具体的节点,例如:

    1. 我们在做RPC服务的时候,会经常部署多台服务器,然而有时有这样的需求就是,我们希望将同一类型的请求路由到同一台机器上,这个时候就可以用一致性hash算法来实现。
    2. MemCache集群,要求存储数据均匀的放到集群中的各个节点上,访问这些数据时能快速的路由到集群中对应存放该数据的节点上;并且要求增删节点对整个集群的影响很小,不至于有大的动荡造成整体负载的不稳定,这个时候也是可以用一致性hash算法。

    一致性哈希算法原理解析

    一致性哈希算法核心思想就是,先维护出一个2的32次方整数环【0,2^32-1】,然后将每个节点的计算hash值放到环上。下面通过一个例子来看看 ;

    现在有三个节点分别是Node0、Node1、Node3,我们要将多个资源尽可能均匀的分配到这三个节点中,该怎么做呢?

    依据一致性hash算法思想,我们需要将资源key进行hash运算,得到的hash值在环上顺时针查找,找到离它最近的节点也就是第一个大于或等于它的节点,这样资源就和节点建立了映射关系。

    1c8636bcc05d0c5637b1f55c34b148f2.png

    为何用环来存储节点,还有顺时针查找?

    我们要向分配节点第一想到的办法就是取余算法。即现在有3个节点,资源key=7,7%3=1,则选择Node1,key=5,5%3= 2,则选择Node2,key=3,3%3=0,则选择Node0。虽然简单,但有个缺点,如果节点数增加或减少,就会有大量的key不命中,造成请求压力转移,可能对系统整体有很大的影响,甚至发生宕机危险。

    而一致性哈希算法增加或减少节点,只会引起很少部分的key不会命中,如下图,增加一个Node4节点,则只会将部分的key值从Node1移到Node4,对集群影响很小。

    982c0ee0c70a872dc3aed1f59001ab87.png

    代码如何实现?

    如上,我们已经知道了一致性哈希的原理了也知道它的作用了,那我们该怎么去写代码实现呢?下面我们以java为例写一个一致性哈希实现算法。

    1. 首先我们得怎么构造这个2的32次方的hash环,当然方法有很多,我这里就直接推荐使用TreeMap这个数据结构,因为TreeMap底层是使用了红黑树结构来存储实体对象的,时间复杂度在O(logN),效率较高。
    2. 我们在选择Hash算法上也需要选好,要尽可能的打散开,如果考虑简单的String.HashCode()方法,这个算法的缺点是,相似的字符串如N1(10.0.0.0:91001),N2(10.0.0.0:91002),N3(10.0.0.0:91003),哈希值也很相近,造成的结果是节点在Hash环上分布很紧密,导致大部分Key值落到了N0上,节点资源分布不均。一般我们采用FNV1_32_HASH、KETAMA_HASH等算法,KETAMA_HASH是MemCache集群默认的实现方法,这些算法效果要好得多,会使N0,N1,N2的Hash值更均匀的分布在环上。

    那我们先来看看KETAMA_HASH算法实现一致性哈希算法的代码:

    import java.io.UnsupportedEncodingException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Arrays;
    import java.util.Map;
    import java.util.TreeMap;
    
    public class ConsistentHashLoadBalance1 {
    
       private TreeMap<Long, String> realNodes = new TreeMap();
       private String[] nodes;
    
       public ConsistentHashLoadBalance1(String[] nodes){
       this.nodes = Arrays.copyOf(nodes, nodes.length);
       initalization();
       }
    
       /**
       * 初始化哈希环
       * 循环计算每个node名称的哈希值,将其放入treeMap
       */
       private void initalization(){
       for (String nodeName: nodes) {
       realNodes.put(hash(nodeName, 0), nodeName);
       }
       }
    
       /**
       * 根据资源key选择返回相应的节点名称
       * @param key
       * @return 节点名称
       */
       public String selectNode(String key){
       Long hashOfKey = hash(key, 0);
       if (! realNodes.containsKey(hashOfKey)) {
       //ceilingEntry()的作用是得到比hashOfKey大的第一个Entry
       Map.Entry<Long, String> entry = realNodes.ceilingEntry(hashOfKey);
       if (entry != null)
       return entry.getValue();
       else
       return nodes[0];
       }else
       return realNodes.get(hashOfKey);
       }
    
       private Long hash(String nodeName, int number) {
       byte[] digest = md5(nodeName);
       return (((long) (digest[3 + number * 4] & 0xFF) << 24)
       | ((long) (digest[2 + number * 4] & 0xFF) << 16)
       | ((long) (digest[1 + number * 4] & 0xFF) << 8)
       | (digest[number * 4] & 0xFF))
       & 0xFFFFFFFFL;
       }
    
       /**
       * md5加密
       *
       * @param str
       * @return
       */
       public byte[] md5(String str) {
       try {
       MessageDigest md = MessageDigest.getInstance("MD5");
       md.reset();
       md.update(str.getBytes("UTF-8"));
       return md.digest();
       } catch (NoSuchAlgorithmException e) {
       e.printStackTrace();
       return null;
       } catch (UnsupportedEncodingException e) {
       e.printStackTrace();
       return null;
       }
       }
    
       private void printTreeNode(){
       if (realNodes != null && ! realNodes.isEmpty()){
       realNodes.forEach((hashKey, node) ->
       System.out.println(
       new StringBuffer(node)
       .append(" ==> ")
       .append(hashKey)
       )
       );
       }else
       System.out.println("Cycle is Empty");
       }
    
       public static void main(String[] args){
       String[] nodes = new String[]{"192.168.13.1:8080", "192.168.13.2:8080", "192.168.13.3:8080", "192.168.13.4:8080"};
       ConsistentHashLoadBalanceNoVirtualNode consistentHash = new ConsistentHashLoadBalanceNoVirtualNode(nodes);
       consistentHash.printTreeNode();
       }
    }

    我们来看看输出结果,可以看出,hash结果值还是很开阔的。

    192.168.13.2:8080 ==> 596465258

    192.168.13.4:8080 ==> 1785851105

    192.168.13.1:8080 ==> 2249838119

    192.168.13.3:8080 ==> 3292932255

    现在我们使用KETAMA_HASH哈希算法,帮我们解决了hash值分布不均匀的问题,但是,目前我们还有个问题,如下图,在Node3节点尚未加入集群之前,数据是均匀分布在{Node0,Node1,Node2}三个节点上的,现在增加了Node3节点后,Node1到Node3节点中间的所有资源从Node2迁移到了Node3上。这样,Node0,Node1存储的资源多,Node2,Node3存储的资源少,资源分布就不均了。

    那我们该怎么解决这种问题呢?这里我们就要引入一个叫虚拟节点的概念,其实很简单,就是比方说我现在将真实的节点Node0映射成100个虚拟节点放在环上,同这100个虚拟节点根据KETAMA_HASH哈希环匹配的资源都存到真实节点Node0上,当集群增加节点Node3时,在Hash环上增加Node3拆分的100个虚拟节点,这新增的100个虚拟节点更均匀的分布在了哈希环上,可能承担了{Node0,Node1,Node2}每个节点的部分资源,资源分布仍然保持均匀。

    81d49f7c7d0b37e52f54fbe0885fa187.png

    每个真实节点应该拆分成多少个虚拟节点?数量要合适才能保证负载分布的均匀,有一个大致的规律,如下图所示,Y轴表示真实节点的数目,X轴表示需拆分的虚拟节点数目:

    951ad8390b318ada4dd1072dcfb3efb0.png

    真实节点越少,所需阐发的虚拟节点越多,比如有10个真实节点,每个节点所需拆分的虚拟节点个数可能是100~200个,才能达到真正的负载均衡。

    下面,我们的代码就需要改造了,需要加入虚拟节点来映射:

    import java.io.UnsupportedEncodingException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.LinkedList;
    import java.util.Map;
    import java.util.TreeMap;
    
    
    public class ConsistentHashLoadBalance {
    
       private TreeMap<Long, String> virtualNodes = new TreeMap<>();
       private LinkedList<String> nodes;
       //每个真实节点对应的虚拟节点数
       private final int replicCnt;
    
       public ConsistentHashLoadBalance(LinkedList<String> nodes, int replicCnt){
       this.nodes = nodes;
       this.replicCnt = replicCnt;
       initalization();
       }
    
       /**
       * 初始化哈希环
       * 循环计算每个node名称的哈希值,将其放入treeMap
       */
       private void initalization(){
       for (String nodeName: nodes) {
       for (int i = 0; i < replicCnt/4; i++) {
       String virtualNodeName = getNodeNameByIndex(nodeName, i);
       for (int j = 0; j < 4; j++) {
       virtualNodes.put(hash(virtualNodeName, j), nodeName);
       }
       }
       }
       }
    
       private String getNodeNameByIndex(String nodeName, int index){
       return new StringBuffer(nodeName)
       .append("&&")
       .append(index)
       .toString();
       }
    
       /**
       * 根据资源key选择返回相应的节点名称
       * @param key
       * @return 节点名称
       */
       public String selectNode(String key){
       Long hashOfKey = hash(key, 0);
       if (! virtualNodes.containsKey(hashOfKey)) {
       Map.Entry<Long, String> entry = virtualNodes.ceilingEntry(hashOfKey);
       if (entry != null)
       return entry.getValue();
       else
       return nodes.getFirst();
       }else
       return virtualNodes.get(hashOfKey);
       }
    
       private Long hash(String nodeName, int number) {
       byte[] digest = md5(nodeName);
       return (((long) (digest[3 + number * 4] & 0xFF) << 24)
       | ((long) (digest[2 + number * 4] & 0xFF) << 16)
       | ((long) (digest[1 + number * 4] & 0xFF) << 8)
       | (digest[number * 4] & 0xFF))
       & 0xFFFFFFFFL;
       }
    
       /**
       * md5加密
       *
       * @param str
       * @return
       */
       public byte[] md5(String str) {
       try {
       MessageDigest md = MessageDigest.getInstance("MD5");
       md.reset();
       md.update(str.getBytes("UTF-8"));
       return md.digest();
       } catch (NoSuchAlgorithmException e) {
       e.printStackTrace();
       return null;
       } catch (UnsupportedEncodingException e) {
       e.printStackTrace();
       return null;
       }
       }
    
       public void addNode(String node){
       nodes.add(node);
       String virtualNodeName = getNodeNameByIndex(node, 0);
       for (int i = 0; i < replicCnt/4; i++) {
       for (int j = 0; j < 4; j++) {
       virtualNodes.put(hash(virtualNodeName, j), node);
       }
       }
       }
    
       public void removeNode(String node){
       nodes.remove(node);
       String virtualNodeName = getNodeNameByIndex(node, 0);
       for (int i = 0; i < replicCnt/4; i++) {
       for (int j = 0; j < 4; j++) {
       virtualNodes.remove(hash(virtualNodeName, j), node);
       }
       }
       }
    
       private void printTreeNode(){
       if (virtualNodes != null && ! virtualNodes.isEmpty()){
       virtualNodes.forEach((hashKey, node) ->
       System.out.println(
       new StringBuffer(node)
       .append(" ==> ")
       .append(hashKey)
       )
       );
       }else
       System.out.println("Cycle is Empty");
       }
    
       public static void main(String[] args){
       LinkedList<String> nodes = new LinkedList<>();
       nodes.add("192.168.13.1:8080");
       nodes.add("192.168.13.2:8080");
       nodes.add("192.168.13.3:8080");
       nodes.add("192.168.13.4:8080");
       ConsistentHashLoadBalance consistentHash = new ConsistentHashLoadBalance(nodes, 160);
       consistentHash.printTreeNode();
       }
    }

    看看输出结果(后面还有):

    192.168.13.3:8080 ==> 9681570

    192.168.13.1:8080 ==> 9770234

    192.168.13.3:8080 ==> 10655171

    192.168.13.1:8080 ==> 29484412

    192.168.13.1:8080 ==> 32476931

    192.168.13.1:8080 ==> 41184104

    192.168.13.4:8080 ==> 56379665

    192.168.13.2:8080 ==> 58341869

    192.168.13.4:8080 ==> 60613368

    。。。。

    总结,今天我们将如何进行资源均摊引入了一致性哈希算法,并且分享了其原理以及作用,同时,针对增加或减少节点的情况下,会造成资源不均匀且容易发生雪崩的情况,特此在一致性哈希算法中加入了虚拟节点进行了改造,最后通过真实代码的方式展示了我们的一致性hash算法该怎么写。相信这样下一篇文章就很容易了哈。希望对大家有帮助,这样我们下一篇的缓存高可用我觉得大家就好理解了。

    如果大家喜欢,或是对大家有所帮助就关注我,我会一直分享业界流行技术方案,让我们共同学习共同进步。

    下一篇预告:聊聊我们缓存中的高可用话题

    往期精选

    你一定要掌握这种缓存读写策略,开发必备

    消息中间件能干什么?RabbitMQ、Kafka、RocketMQ正确选型姿势

    NoSql数据库,是怎么解决我们高并发场景下MySql表现的不足

    数据库分库分表,手把手教你怎么去动态扩容索容

    每天百万交易的支付系统,生产环境该怎么设置JVM堆内存大小

    你的成神之路我已替你铺好,没铺你来捶我

    展开全文
  • 一、一致性哈希算法

    2020-07-05 10:57:53
    4.3 一致性哈希算法代码实现 4.4 一致性哈希算法优化(虚拟节点) 1 一致性哈希算法用途 一致性哈希是解决上线、下线后相同的请求尽可能的命中原来服务器的问题。 假如我们自己设计了一个高可用缓存系统,可以集群...
  • 今天我想先给大家科普下一致性哈希算法这块,因为我下一篇文章关于缓存的高可用需要用到这个,但是又不能直接在里面写太多的代码以及关于一致性hash原理的解读,这样会失去对于缓存高可用的理解而且会造成文章很长,...
  • 感知哈希算法(pHash算法+python代码实现) pHash算法是计算图片相似度算法的一种,可以用在以图搜图上面,原理也很简单,下面简单罗列一下算法过程: 缩放图片尺寸:缩放到8*8的大小,这里是为了去除图片的细节,...
  • 复制代码 代码如下:APR_DECLARE_NONSTD(unsigned int) apr_hashfunc_default(const char *char_key, apr_ssize_t *klen){ unsigned int hash = 0; const unsigned char *key = (const unsigned char *)char_key;...
  • 在浏览器的图片搜索中,用户可以上传一张图片,浏览器显示因特网中与此图片相同或者相似的图,实现这种功能的关键技术叫做"感知哈希算法"(Perceptual Hash Algorithm), 意思是为图片生成一个指纹(字符串格式), 两张...
  • 哈希算法与二叉树

    2020-04-10 10:52:24
    哈希算法 一. 基本含义: 哈希算法的主要作用 1:独一无二的 2:数据是完整的 哈希算法的分类 1:普通哈希。 2:加密哈希:。 二叉树 啥也不说了,直接上代码: public class TreeNode { // 左节点(儿子) private...
  • 1,对于待存储的海量数据,如何将它们分配到各个机器中去?---数据分片与路由当数据量很大时,通过改善单机硬件资源的纵向扩充方式来存储数据变得越来越不适用,而通过增加机器数目...2,衡量一致性哈希算法好处的四...
  • 哈希算法

    2011-07-26 18:02:43
    我们可以利用哈希算法根据id将学生姓名存入,再根据id检索。 学生ID相当于KEY ,名字相当于VALUE 代码如下: package com.algorithm.hash; public class hash { //哈希函数 public static int Has...
  • 大家都用google或baidu的识图功能,上面就是我搜索一幅图片的结果,该引擎实现相似图片搜素的关键技术叫做“感知哈希算法”(Perceptualhashalgorithm),它的作用是对每张图片生成一个“指纹”(fingerprint)字符...
  • 【本文转载自一致性哈希算法学习及JAVA代码实现分析】 1,对于待存储的海量数据,如何将它们分配到各个机器中去?---数据分片与路由 当数据量很大时,通过改善单机硬件资源的纵向扩充方式来存储数据变得...
  • 1 <?php 2 /** 3 * Flexihash - A simple consistent hashing implementation for PHP. 4 * 5 * The MIT License 6 * 7 * Copyright (c) 2008 Paul Annesley 8 * 9 *...
  • 今天我想先给大家科普下一致性哈希算法这块,因为我下一篇文章关于缓存的高可用需要用到这个,但是又不能直接在里面写太多的代码以及关于一致性hash原理的解读,这样会失去对于缓存高可用的理解而且会造成文章很长,...
  • 一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简单哈希算法带来的问题,使得DHT...
  • 该压缩包包含编译方式,示例代码,只需拍两张图片即可比较,比较打印输出值小于10,即为相似图片。使用改代码的用户linux系统必须先安装opencv环境.
  • delphi下面开发的国产哈希算法SM3可以直接调用接口 里面的代码注释写的很明白 我自己做项目测试了可以使用 没得问题
  • 哈希算法理解

    2020-01-14 15:18:39
    哈希函数基本概念功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表举例说明设定内容居中、居左、居右SmartyPants创建一个自定义列表如何...
  • 哈希算法实现代码

    2017-03-15 10:35:23
    说明: 本程序建立的哈希表示意图: 哈希函数为对哈希表长取余 /********************************************************************* * 哈希算法实现 * (c)copyrig
  • 7.1.5代码实现 7.2一致性hash 7.3局部敏感哈希(LSH) 7.3.1为什么要有局部敏感哈希? 7.3.2文档相似度计算 7.3.3文档shingling 7.3.4保持相似度矩阵表示 7.4.5最小哈希 参考文档: 7.1哈希表(散列表) 7....
  • 一致性哈希算法在分布式系统中应用广泛,可用于网关负载均衡、数据库分库分表、分布式缓存。使用一致性哈希算法可以尽可能的将同一资源请求路由到同一台服务器上。 本文代码中仅实现顺时针方式查找 核心方法: ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,003
精华内容 801
关键字:

哈希算法代码