【云计算】Redis重点解析
小标 2019-02-11 来源 : 阅读 961 评论 0

摘要:本文主要向大家介绍了【云计算】Redis重点解析,通过具体的内容向大家展现,希望对大家学习云计算有所帮助。

本文主要向大家介绍了【云计算】Redis重点解析,通过具体的内容向大家展现,希望对大家学习云计算有所帮助。

Redis有没有使用一致性哈希?


很多人包括之前的我在内,一直认为reids集群的数据存储用的是一致性hash算法,后来读了亚马逊的《Dynamo: Amazon’s Highly Available Key-value Store》论文,感觉Redis不至于实现的这么复杂,带着一些疑问,翻了redis官网和客户端代码,发现Redis并没有使用一致性hash算法。

Redis集群使用的是一种哈希槽(hash slot)的方式,将key通过hash后存储在16384个槽中,然后将这些槽平均分配给集群中的各个节点,举个例子,比如一个集群有4个节点,那么分配可以是这样的:


0~5000  NodeA
5001~10000 NodeB
10001 ~ 15000 NodeC
15001 ~ 16384 NodeD


这样当集群中节点的数量发生变化时,只需要调整槽的分配就可以了:

当有节点加入时,每个节点把自己的槽分一些给新节点。

当有节点退出时,将退出节点的槽分配给其他节点。

仔细想想,其实这定没有违背一致性hash定义中当有一个节点发生变化时,只影响K/N个key的缓存这个定义。

anyway,不管一致性hash也好,hash slot也好,不要执着于Redis用没用一致性hash,搞清楚每一种解决问题的算法的思想才是最重要的。


一致性hash的局限和改进:cache or storage


如果你只是用来做缓存,那自然没问题,一致性hash天生就是来做这个的。当hash环中添加或者移除节点时,平均只有K/N个key受到影响,因为是缓存系统,缓存无法命中时,再从数据源重新加载一遍就是了。

可是,如果我们要做的不仅仅是一个缓存系统呢?如果我们要做的是一个存储系统呢?K/N个key受到影响时,你本身就是数据源了,你还能从哪里加载数据呢?那大概直接就是事故了。

为了解决一致性hash的存储问题,方法大概有两种:


1. hash环上的replication


 


正如Dynamo论文图中所示,AB区间内的key,不再只由节点B存储,而是扩展到三个节点,B、C、D都存储,这样当B节点故障时,AB之间的key仍然可以从C、D节点中得到,然后把A~B区间的key再复制到E节点中一份,保证每份数据都有两个replication,所以说,大多数事情都是殊途同归的,为了解决节点故障导致的可用性问题,不管怎样,RAID也好,ZK也好,GFS也好,Mysql主从复制也好,说到底都是通过数据的冗余备份(replication)来做的,一个节点可能故障,那我就多弄几个候补的,如果遇到极端情况,所有候补节点同时挂了,那算我倒霉,我认了。毕竟再厉害的容灾,你能跨机器、跨机架、跨机房、跨城市、跨国家,可是你能夸星球吗?来个小行星撞地球,啥都没意义了,所有的东西都有个限度,都需要权衡和考虑性价比的

整个论文读完,发现Dynamo这种把replication做到hash环上的方法虽然解决了可用性的问题,考虑到虚拟节点的存在,这种方法其实是大大增加了系统的复杂度的。


2. 另一种replication


这种replication比上面那种要清晰不少,这种也是redis采用的:


如上图所示,hash环(redis使用的是hash槽)上的节点都当做是master节点,每个master节点配备若干个slave节点,当master节点故障时,其中一个slave节点会被选举为新的master节点,选举的过程是由Redis的sentinel组件(你可以认为跟zookeeper做的事情差不多)实现的。虽然多了一个额外的sentinel组件,但是整个结构上清晰了许多。而且,Redis集群采用hash槽的概念替换了一致性hash的虚拟节点,hash槽的分配可以保证每个节点的负载是均衡的。

无论哪种实现方式,slave节点都是可以提供读服务的,也就是读写分离。其实,在redis的适用场景中,大部分都是读多写少的。


Redis集群中节点变动的三种情况


1. 向集群中添加一个节点


当然这个节点还附带着它的slave节点,这里暂且略过,向集群中添加节点时,先把其他节点“管辖”的槽位都拉一部分过来到自己的节点上,使各个节点的负载接近平衡,然后更新集群上所有节点中记录的各个节点和slot的映射关系,新的请求进来后,刚才加入的节点就可以正常工作了。


2. 手动从集群中去除一个节点


当你觉得集群的利用率比较低,向去除一个节点时,redis会先把要去除的节点管辖的slot平均分配到其他节点上,分完之后,更新集群中各个节点中存储的节点和slot的映射关系,最后删除这个节点及其slave节点就可以了。


3. 集群中的一个节点因为故障宕机了


对于这种突发情况,是没有时间让我们预先将节点的slot转移到其他节点的,这种情况就靠我们上面提到的master-slave机制应对了,master挂了,slave会顶替它成为新的master,并不影响整个集群的可用性。当然,如果一个节点的master和它所有的slave同时挂了,那就只能自认倒霉了。


两种路由方式


现在思考一下,你用客户端向集群发起请求,get/set一个key的时候,整个流程是怎么样运转的呢?你是怎样找到应该存放这个key的slot的呢?又是怎样找到“管辖”这个slot的节点的呢?

下面以get为例,描述这个步骤:

 1. 将key % 16384找到slot的编号

 2. 找到管辖这个slot的节点

  这一步有两种实现方式:

  a. 客户端实现

  你的redis cluster client会缓存集群中各个节点与slot的映射关系,当因为节点变动引起映射关系的变动时,client会在发现后及时获取新的映射关系。这样客户端帮你找到“管辖”这个slot的节点后,直接向这个节点发起get请求,节点将结果返回,流程就结束了。

  b. 服务端实现

  你的redis cluster client并不会缓存任何节点和slot的映射关系,而是直接将请求发送到随便一个节点,因为每个节点中都存储着各个节点和slot的映射关系,那么接收到请求的节点会查询该slot的管辖节点是谁,如果不是自己的话,该节点会将请求转发到正确的节点上,然后该节点将数据返回给客户端。


两种方式各有利弊吧,客户端实现的方式需要客户端维护节点和slot的映射关系,服务端实现的方式需要服务端多做一次转发。redis的java客户端JedisCluster倒是两种方式都实现了,都有实现类,默认使用的是“客户端实现”的方式。

有很多地方没提到,比如redis主从复制的最终一致性,sentinel的工作流程等,redis集群中的事务以及包含多个key的请求时的问题等等,大家有兴趣可以去redis的官网看看,文档很详细。


          

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标大数据云计算大数据安全频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程