您的位置:首页 > 数据库 > Redis

Redis 为什么能够快存快取, 一致性hash 算法和map 中的hash 算法有何不同

2018-08-25 17:09 691 查看

首先我们先分析一下list 和hashmap 想取某个值的时间复杂度

list (LinkedList 或者我们取ArrayList但是我们不知道下标)我们需要从头遍历到尾巴。可能第一次取到,也可能第二次取到即1
+2+3+4+。。。+n  和为 n*(n+1)/2。一共找了n 次。所以再除以n 就是时间复杂度,即O(n+1)/2

  1. hashmap 中的hash 算法

再来看看hashmap 中的hash 算法。首先hashmap 是由数组加链表组成的。存放的规则是 key.hashcode()/array.length 。这个值等于存放的数组下标。如下图所示,长方形代表的数组,圆形代表的链表。当有几个key 的hashcode 算法得到的数组下标是一样的时候。就会将最先放入的值敲到每个数组下标 对应的链表的最下面去。从图上看就是从上到下O(1)。因为时间复杂度低,当然取值快啊,再者redis是内存数据库,使用的时候不需要再去磁盘上读取。当数组使用的比例达到0.75 (扩容因子)的时候,数组会扩展长度,以便获得更多的空间存储。那么问题来了,本来某个key 对应的数组下标是0, 当数组扩容的时候根据 key.hashcode()/array.length这个公式计算 很可能对应的下标到了4.那么4里面是没有这个key对应的value。

所以当数组进行扩容的时候hashmap 会进行重新排序(rehash)。所以有时候map.put()方法调用的时候,会很慢。后台在重新计算。

  2. 一致性hash算法

在redis3.0 之后集群的概念才很明显。 它先将hashcode 在 0 到2^32之间的值做成了一个环形的结构,直接上图。他将redis的ip 和需要存放的key 一并的放2这个环中。并且按顺时针最近原则选择存放的redis。图上所示object1-4都会存入到对应下标的redis 中。那么object5 会存在哪个redis 呢?,按照顺时针最近原则存的是存到redis1中

 

这样做的好处是什么呢?当有新的节点进来的时候或者有一台机器down 掉的时候, 我们只需rehash 部分的key 而不是全部rehash。如下图所示, 青色线包含了红色线的范围。当redis5 进入集群,我们只要把原来青色线中的红线部分rehash 到redis5中就行,而不是rehash 全部。

 

 

 3.为了平衡性

上图中。放入redis2中值的比例远远小于放入redis4中的比例。为了解决这个问题,redis 的作者增加了许多虚拟ip,使得值分散的更均匀,集群中每个redis的资源使用率更平均。比如redis1有两个虚拟ip.redis#1和redis#2.那么图中粉色线的部分的hashcode对应的值都会存入redis1中,虚拟ip 只是和redis1有映射关系并不存储值。

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: