普通Hash与一致性Hash

本文介绍了Hash算法的基础知识,包括两种常见的存储方式:除留余数法和开放寻址法。接着探讨了普通Hash在负载均衡中的问题,如服务器宕机导致的用户登录失效。为了解决这些问题,文章引入了一致性Hash的概念,解释了其工作原理和优势,同时指出了一致性Hash存在的数据倾斜问题,并通过增加虚拟节点来缓解该问题。最后,文章简要提到了手写Hash的三个部分:普通Hash、一致性Hash不带虚拟节点和一致性Hash带虚拟节点。
摘要由CSDN通过智能技术生成

1.Hash的介绍

  Hash算法应用很广泛,比如MD5,SHA加密算法,数据存储和数据查找方面。
  Hash算法最主要的应用场景还是在数据存储数据查找方面。而设计得好的Hash算法,在数据查找方面可以时间复杂度可以达到O(1)。

1.1 常用2种Hash存储的方式介绍

  • 除留余数法
    定义一个固定大小的数组长度,把需要存储的数值%数组长度得到的数值,存储到数组的下标位置,这种方式就叫除留余数法。这种方法的缺点就是,容易产生Hash冲突,比如数组长度为5,需要存储的数值有1,2,3,4,6,那么在存储1和6的时候,就会产生冲突,因为1和6对5取余,长度都为1。所以在此基础上,引进了开放寻址法拉链存储法
  • 开放寻址法
    这种方式,在除留余数法的基础上,产生冲突时,把冲突的值放到被冲突的值前面或者后面的空闲位置。
  • 拉链存储法
    这种方式,在除留余数法的基础上,产生冲突时,把冲突的值用链表的形式存储到被冲突的值的上面,及被冲突的值会产生一个链表,这个链表存储所有跟改值产生冲突的值。

2. Hash的应用场景

  一般来说,我们如果不做hash算法研究,我们平时在工作当中,只需要使用已有的Hash算法就可以了。
  那么Hash的应用场景有哪些了?主要的应用场景有请求负载均衡分布式存储

  • 请求负载均衡
    在使用nginx进行负载均衡时, 就有一个ip_hash策略可以选择。那么使用ip_hash有什么好处了?它可以实现会话沾滞,从而避免处理session共享问题。因为同一个ip的请求会被映射到同一条服务器,从而使得session一直有效。而不是这次请求是这条服务器,服务器存储了session,下一次请求请求的是另外一台服务器导致session失效的。
    在这里提一下,nginx的ip_hash策略默认使用的是普通Hash,并且在进行hash处理的时候,同一个网段的请求会落在同一条服务器,因为nginx处理ip_hash的代码中,只处理了客户端ip的前三段。如果想使用一致性Hash,需要自行下载模块,并进行编译安装。
  • 分布式存储
    在分布式的环境下,如果有多台mysql数据库或者多台redis,那么客户端需要存储到某条记录时,就可以使用hash(key) = index,来实现数据存储到某个服务器的功能了。

2.普通Hash

  普通hash会不会存在什么问题了?答案肯定是有的
  举个例子,以nginx的ip_hash为例,如果后台服务器有5台,如果此时有一台服务器宕机了,那么大部分的客户端的hash得重新计算了, 因为之前是hash(key%5)= index, 现在变成了hash(key%4)=index。当用户很多并且是使用的session会话沾滞的情况下,这种就会造成大量的用户登录失效从而导致用户体验很差。

3.一致性Hash

  一致性Hash是为了解决普通Hash的, 但是也只能说更大的程度的去优化普通Hash算法,从而减少客户端变更目标主机的解决方案。而不能完全百分之百解决所有用户都不替换目标主机。
  一致性Hash思路为,定义一条线, 线的两端分别为02的32次方-1(这个为int的最大值),然后把这条线的收尾两端相连形成一个环,我们称为Hash环。然后把服务器端的ipHash值落到这个环上,客户端的iphash值也落在这个环上,客户端产生的iphash以顺时针的方向查找服务器端生成的Hash值,离哪个最近,就访问哪台主机 。
  那么这种方案有没有什么缺点了?答案是有的,比如服务端机器刚开始的节点只有5台,而这个环总共有2的32次数-1个点,那么很容易造成大量客户端都落在一台服务端机器上,这种也被成为数据倾斜
  而为了解决数据倾斜的问题,又提出了一种解决方案,可以给每一个服务端主机都虚拟一些节点出来落在这个环上,这样就可以极大程度的避免了数据倾斜的问题。

4.手写Hash

4.1 普通Hash

	public static void main(String[] args) {
   
		// 定义模拟后台服务端机器数量为3
        int serverSize = 3;

		// 定义客户端请求ip
        String[] clientArr = new String[]{
   "192.168.10.1", "192.168.10.2", "1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值