一文了散列解一致

  
  

本文首发于体内互联网技术微信公众号
链接:https://mp.weixin.qq.com/s/LGLqEOlGExKob8xEXXWckQ
钱幸川

     

在分布式环境下面,我们经常会通过一定的规则来进行数据分布的定义,本文描述的取模算法和一致性散列(一致性哈希)是通过一定规则产生一个键,对这个关键进行一定规则的运算,得出这个数据该去哪儿。

  

本文使用软件环境:Java 8

  

一、数据分布接口定义

  

<>强概述

  

在分布式环境下面,我们经常会通过一定的规则来进行数据分布的定义,比如用户1的数据存储到数据库1,用户2的数据存储到数据库2…

  

一般来说,有这么几种常用的方式:

  
      <李>   

    有一个分布式环境中唯一的中心分发节点,每次在数据存储的时候,都会询问中心节点这个数据该去哪儿,这个分发节点明确告诉这个数据该去哪儿。

      李   <李>通过一定规则产生一个键,对这个关键进行一定规则的运算,得出这个数据该去哪儿。本文描述的取模算法和一致性散列,就是这样一种方式。   
  

<>强接口定义

  
 <代码>/* *
  *数据分布哈希算法接口定义
  * @author xingchuan.qxc
  *
  */公共接口HashNodeService {/* *
  *集群增加一个数据存储节点
  * @param节点
  */公共空间addNode(节点);/* *
  *数据存储时查找具体使用哪个节点来存储
  * @param关键
  * @return
  */公共节点lookupNode (String键);/* *
  *哈希的算法
  * @param关键
  * @return
  */公共长哈希(String键);/* *
  *模拟意外情况断掉一个节点,用于测试缓存命中率
  * @param节点
  */公共空间removeNodeUnexpected(节点);
  } 
  

二、数据分布算法实现,取模算法

  

<>强概述

  

取模算法的应用场景描述如下:

  

需要在集群中实现一个用户数据存储的负载均衡,集群中有n个存储节点,如何均匀的把各个数据分布到这n个节点呢?

  

实现步骤大概分成两步:

  
      <李>   

    通过用户的关键来取一个哈希值

      李   <李>   

    通过这个哈希值来对存储节点数n进行取模,得出一个指数

      李   <李>上面这就个指数是待存储的节点标识李   
  

注意:本文例子我生成散列值的方式,我采用CRC32的方式。

  

<>强代码实现:

  
 <代码>/* *
  *取模数据分布算法实现
  * @author xingchuan.qxc
  *
  */公共类NormalHashNodeServiceImpl实现HashNodeService {/* *
  *存储节点列的表
  */私人List节点=new ArrayList<在();
  
  @Override
  公共空间addNode(节点节点){
  this.nodes.add(节点);
  }
  @Override
  公共节点lookupNode (String键){
  长k=散列(关键);
  int指数=(int) (k % nodes.size ());
  返回nodes.get(指数);
  }
  @Override
  公共长哈希(String键){
  CRC32 CRC32=new CRC32 ();
  crc32.update (key.getBytes ());
  返回crc32.getValue ();
  }
  @Override
  公共空间removeNodeUnexpected(节点节点){
  nodes.remove(节点);
  }
  } 
  

通过上述例子我们可以看的到,lookupNode的时候,是要先去取这个关键的CRC32的值,然后对集群中节点数进行取模得到r,最后返回下标为r的节点。

  

测试代码如下:

  
 <代码> HashNodeService nodeService=new NormalHashNodeServiceImpl ();
  节点addNode1=新节点(“xingchuan。node1”、“192.168.0.11”);
  节点addNode2=新节点(“xingchuan。node2”、“192.168.0.12”);
  节点addNode3=新节点(“xingchuan。node3”、“192.168.0.13”);
  节点addNode4=新节点(“xingchuan。node4”、“192.168.0.14”);
  节点addNode5=新节点(“xingchuan。node5”、“192.168.0.15”);
  节点addNode6=新节点(“xingchuan。node6”、“192.168.0.16”);
  节点addNode7=新节点(“xingchuan。node7”、“192.168.0.17”);
  节点addNode8=新节点(“xingchuan。node8”、“192.168.0.18”);
  nodeService.addNode (addNode1);
  nodeService.addNode (addNode2);
  nodeService.addNode (addNode3);
  nodeService.addNode (addNode4);
  nodeService.addNode (addNode5);
  nodeService.addNode (addNode6);
  nodeService.addNode (addNode7);
  nodeService.addNode (addNode8);//用于检查数据分布情况
  Integer> Map<字符串;,countmap=new HashMap<的在();
  节点的节点=零;
  for (int i=1;我& lt;=100000;我+ +){
  字符串键=String.valueOf(我);
  节点=nodeService.lookupNode(关键);
  节点。cacheString(键,“TEST_VALUE”);
  字符串k=node.getIp ();
  整型数=countmap.get (k);
  如果(count==null) {
  数=1;
  countmap。把(k,数);
  其他}{
  数+ +;
  countmap。把(k,数);
  }
  
  }
  system . out。println(“初始化数据分布情况:”+ countmap); 

一文了散列解一致