您当前的位置:首页 > 电脑百科 > 数据库 > Redis

深度原理学习–Redis集群

时间:2019-09-23 11:29:36  来源:  作者:

前面我们介绍了国人自己开发的redis集群方案——Codis,Codis友好的管理界面以及强大的自动平衡槽位的功能深受广大开发者的喜爱。今天我们一起来聊一聊Redis作者自己提供的集群方案——Cluster。希望读完这篇文章,你能够充分了解Codis和Cluster各自的优缺点,面对不同的应用场景可以从容的做出选择。

Redis Cluster是去中心化的,这点与Codis有着本质的不同,Redis Cluster划分了16384个slots,每个节点负责其中的一部分数据。slot的信息存储在每个节点中,节点会将slot信息持久化到配置文件中,因此需要保证配置文件是可写的。当客户端连接时,会获得一份slot的信息。这样当客户端需要访问某个key时,就可以直接根据缓存在本地的slot信息来定位节点。这样就会存在客户端缓存的slot信息和服务器的slot信息不一致的问题,这个问题具体怎么解决呢?这里先卖个关子,后面会做解释。

特性

首先我们来看下官方对Redis Cluster的介绍。

  • High performance and linear scalability up to 1000 nodes. There are no proxies, asynchronous replication is used, and no merge operations are performed on values.
  • Acceptable degree of write safety: the system tries (in a best-effort way) to retAIn all the writes originating from clients connected with the majority of the master nodes. Usually there are small windows where acknowledged writes can be lost. Windows to lose acknowledged writes are larger when clients are in a minority partition.
  • Availability: Redis Cluster is able to survive partitions where the majority of the master nodes are reachable and there is at least one reachable slave for every master node that is no longer reachable. Moreover using replicas migration, masters no longer replicated by any slave will receive one from a master which is covered by multiple slaves.

是不是不(kan)想(bu)看(dong)?没关系,我来给你掰开了揉碎了解释一下。

写安全

Redis Cluster使用异步的主从同步方式,只能保证最终一致性。所以会引起一些写入数据丢失的问题,在继续阅读之前,可以先自己思考一下在什么情况下写入的数据会丢失。

先来看一种比较常见的写丢失的情况:

client向一个master发送一个写请求,master写成功并通知client。在同步到slave之前,这个master挂了,它的slave代替它成为了新的master。这时前面写入的数据就丢失了。

此外,还有一种情况。

master节点与大多数节点无法通信,一段时间后,这个master被认为已经下线,并且被它的slave顶替,又过了一段时间,原来的master节点重写恢复了连接。这时如果一个client存有过期的路由表,它就会把写请求发送的这个旧的master节点(已经变成slave了)上,从而导致写数据丢失。

不过,这种情况一般不会发生,因为当一个master失去连接足够长时间而被认为已经下线时,就会开始拒绝写请求。当它恢复之后,仍然会有一小段时间是拒绝写请求的,这段时间是为了让其他节点更新自己的路由表中的配置信息。

为了尽可能保证写安全性,Redis Cluster在发生分区时,会尽量使客户端连接到多数节点的那一部分,因为如果连接到少数部分,当master被替换时,会因为多数master不可达而拒绝所有的写请求,这样损失的数据要增大很多。

Redis Cluster维护了一个NODE_TIMEOUT变量,如果上述情况中,master在NODE_TIMEOUT时间内恢复连接,就不会有数据丢失。

可用性

如果集群的大部分master可达,并且每个不可达的master至少有一个slave,在NODE_TIMEOUT时间后,就会开始进行故障转移(一般1到2秒),故障转移完成后的集群仍然可用。

如果集群中得N个master节点都有1个slave,当有一个节点挂掉时,集群一定是可用的,如果有2个节点挂掉,那么就会有1/(N*2-1)的概率导致集群不可用。

Redis Cluster为了提高可用性,新增了一个新的feature,叫做replicas migration(副本迁移,ps:我自己翻译的),这个feature其实就是在每次故障之后,重新布局集群的slave,给没有slave的master配备上slave,以此来更好的应对下次故障。

性能

Redis Cluster不提供代理,而是让client直接重定向到正确的节点。

client中会保存一份集群状态的副本,一般情况下就会直接连接到正确的节点。

由于Redis Cluster是异步备份的,所以节点不需要等待其他节点确认写成功就可以直接返回,除非显式的使用了WAIT命令。

对于操作多个key的命令,所操作的key必须是在同一节点上的,因为数据是不会移动的。(除非是resharding)

Redis Cluster设计的主要目标是提高性能和扩展性,只提供弱的数据安全性和可用性(但是要合理)。

Key分配模型

Redis Cluster共划分为16384个槽位。这也意味着一个集群最多可以有16384个master,不过官方建议master的最大数量是1000个。

如果Cluster不处于重新配置过程,那么就会达到一种稳定状态。在稳定状态下,一个槽位只由一个master提供服务,不过一个master节点会有一个或多个slave,这些slave可以提供缓解master的读请求的压力。

Redis Cluster会对key使用CRC16算法进行hash,然后对16384取模来确定key所属的槽位(hash tag会打破这种规则)。

Keys hash tags

标签是破坏上述计算规则的实现,Hash tag是一种保证多个键被分配到同一个槽位的方法。

hash tag的计算规则是:取一对大括号{}之间的字符进行计算,如果key存在多对大括号,那么就取第一个左括号和第一个右括号之间的字符。如果大括号之前没有字符,则会对整个字符串进行计算。

说了这个多,可能你还是一头雾水。别急,我们来吃几个栗子。

  1. {Jackeyzhe}.following和{Jackeyzhe}.follower这两个key都是计算Jackey的hash值
  2. foo{{bar}}这个key就会对{bar进行hash计算
  3. follow{}{Jackey}会对整个字符串进行计算

重定向

前面聊性能的时候我们提到过,Redis Cluster为了提高性能,不会提供代理,而是使用重定向的方式让client连接到正确的节点。下面我们来详细说明一下Redis Cluster是如何进行重定向的。

MOVED重定向

Redis客户端可以向集群的任意一个节点发送查询请求,节点接收到请求后会对其进行解析,如果是操作单个key的命令或者是包含多个在相同槽位key的命令,那么该节点就会去查找这个key是属于哪个槽位的。

如果key所属的槽位由该节点提供服务,那么就直接返回结果。否则就会返回一个MOVED错误:

1GET x

2-MOVED 3999 127.0.0.1:6381

这个错误包括了对应的key属于哪个槽位(3999)以及该槽位所在的节点的IP地址和端口号。client收到这个错误信息后,就将这些信息存储起来以便可以更准确的找到正确的节点。

当客户端收到MOVED错误后,可以使用CLUSTER NODES或CLUSTER SLOTS命令来更新整个集群的信息,因为当重定向发生时,很少会是单个槽位的变更,一般都会是多个槽位一起更新。因此,在收到MOVED错误时,客户端应该尽早更新集群的分布信息。当集群达到稳定状态时,客户端保存的槽位和节点的对应信息都是正确的,cluster的性能也会达到非常高效的状态。

除了MOVED重定向之外,一个完整的集群还应该支持ASK重定向。

ASK重定向

对于Redis Cluster来讲,MOVED重定向意味着请求的slot永远由另一个node提供服务,而ASK重定向仅代表下一个请求需要发送到指定的节点。在Redis Cluster迁移的时候会用到ASK重定向,那Redis Cluster迁移的过程究竟是怎样的呢?

Redis Cluster的迁移是以槽位单位的,迁移过程总共分3步(类似于把大象装进冰箱),我们来举个栗子,看一下一个槽位从节点A迁移到节点B需要经过哪些步骤:

  1. 首先打开冰箱门,也就是从A节点获得槽位所有的key列表,再挨个key进行迁移,在这之前,A节点的该槽位被设置为migrating状态,B节点被设置为importing的槽位(都是用CLUSTER SETSLOT命令)。
  2. 第二步,就是要把大象装进去了,对于每个key来说,就是在A节点用dump命令对其进行序列化,再通过客户端在B节点执行restore命令,反序列化到B节点。
  3. 第三步呢,就需要把冰箱门关上,也就是把对应的key从A节点删除。

有同学会问了,说好的用到ASK重定向呢?上面我们所描述的只是迁移的过程,在迁移过程中,Redis还是要对外提供服务的。试想一下,如果在迁移过程中,我向A节点请求查询x的值,A说:我这没有啊,我也不知道是传到B那去了还是我一直就没有存,你还是先问问B吧。然后返回给我们一个-ASK targetNodeAddr的错误,让我们去问B。而这时如果我们直接去问B,B肯定会直接说:这个不归我管,你得去问A。(-MOVED重定向)。因为这时候迁移还没有完成,所以B也没说错,这时候x真的不归它管。但是我们不能让它俩来回踢皮球啊,所以在问B之前,我们先给B发一个asking指令,告诉B:下面我问你一个key的值,你得当成是自己的key来处理,不能说不知道。这样如果x已经迁移到B,就会直接返回结果,如果B也查不到x的下落,说明x不存在。

容错

了解了Redis Cluster的重定向操作之后,我们再来聊一聊Redis Cluster的容错机制,Redis Cluster和大多数集群一样,是通过心跳来判断一个节点是否存活的。

心跳和gossip消息

集群中的节点会不停的互相交换ping pong包,ping pong包具有相同的结构,只是类型不同,ping pong包合在一起叫做心跳包。

通常节点会发送ping包并接收接收者返回的pong包,不过这也不是绝对,节点也有可能只发送pong包,而不需要让接收者发送返回包,这种操作通常用于广播一个新的配置信息。

节点会每个几秒钟就发送一定数量的ping包。如果一个节点超过二分之一NODE_TIME时间没有收到来自某个节点ping或pong包,那么就会在NODE_TIMEOUT之前像该节点发送ping包,在NODE_TIMEOUT之前,节点会尝试TCP重连,避免由于TCP连接问题而误以为节点不可达。

心跳包内容

前面我们说了,ping和pong包的结构是相同的,下面就来具体看一下包的内容。

ping和pong包的内容可以分为header和gossip消息两部分,其中header包含以下信息:

  • NODE ID是一个160bit的伪随机字符串,它是节点在集群中的唯一标识
  • currentEpoch和configEpoch字段
  • node flag,标识节点是master还是slave,另外还有一些其他的标识位
  • 节点提供服务的hash slot的bitmap
  • 发送者的TCP端口
  • 发送者认为的集群状态(down or ok)
  • 如果是slave,则包含master的NODE ID

gossip包含了该节点认为的其他节点的状态,不过不是集群的全部节点。具体有以下信息:

  • NODE ID
  • 节点的IP和端口
  • NODE flags

gossip消息在错误检测和节点发现中起着重要的作用。

错误检测

错误检测用于识别集群中的不可达节点是否已下线,如果一个master下线,会将它的slave提升为master。如果无法提升,则集群会处于错误状态。在gossip消息中,NODE flags的值包括两种PFAIL和FAIL。

PFAIL flag

如果一个节点发现另外一个节点不可达的时间超过NODE_TIMEOUT ,则会将这个节点标记为PFAIL,也就是Possible failure(可能下线)。节点不可达是说一个节点发送了ping包,但是等待了超过NODE_TIMEOUT时间仍然没有收到回应。这也就意味着,NODE_TIMEOUT必须大于一个网络包来回的时间。

FAIL flag

PFAIL标志只是一个节点本地的信息,为了使slave提升为master,需要将PFAIL升级为FAIL。PFAIL升级为FAIL需要满足一些条件:

  • A节点将B节点标记为PFAIL
  • A节点通过gossip消息收集其他大部分master节点标识的B节点的状态
  • 大部分master节点在NODE_TIMEOUT * FAIL_REPORT_VALIDITY_MULT时间段内,标识B节点为PFAIL或FAIL

如果满足以上条件,A节点会将B节点标识为FAIL并且向所有节点发送B节点FAIL的消息。收到消息的节点也都会将B标为FAIL。

FAIL状态是单向的,只能从PFAIL升级为FAIL,而不能从FAIL降为PFAIL。不过存在一些清除FAIL状态的情况:

  • 节点重新可达,并且是slave节点
  • 节点重新可达,并且是master节点,但是不提供任何slot服务
  • 节点重新可达,并且是master节点,但是长时间没有slave被提升为master来顶替它

PFAIL提升到FAIL使用的是一种弱协议:

  • 节点收集的状态不在同一时间点,我们会丢弃时间较早的报告信息,但是也只能保证节点的状态在一段时间内大部分master达成了一致
  • 检测到一个FAIL后,需要通知所有节点,但是没有办法保证每个节点都能成功收到消息

由于是弱协议,Redis Cluster只要求所有节点对某个节点的状态最终保持一致。如果大部分master认为某个节点FAIL,那么最终所有节点都会将其标为FAIL。而如果只有一小部分master节点认为某个节点FAIL,slave并不会被提升为master,因此,FAIL状态将会被清除。

搭建

原理说了这么多,我们一定要来亲自动手搭建一个Redis Cluster,下面演示一个在一台机器上模拟搭建3主3从的Redis Cluster。当然,如果你想了解更多Redis Cluster的其他原理,可以点击阅读原文查看官网的介绍。

Redis环境

首先要搭建起我们需要的Redis环境,这里启动6个Redis实例,端口号分别是6379、6380、6479、6480、6579、6580

拷贝6份Redis配置文件并进行如下修改(以6379为例,端口号和配置文件根据需要修改):

1port 6379

2cluster-enabled yes

3cluster-config-file nodes6379.conf

4Appendonly yes

配置文件的名称也需要修改,修改完成后,分别启动6个实例(图片中有一个端口号改错了……)。

深度原理学习–Redis集群

Redis instances

创建Redis Cluster

实例启动完成后,就可以创建Redis Cluster了,如果Redis的版本是3.x或4.x,需要使用一个叫做redis-trib的工具,而对于Redis5.0之后的版本,Redis Cluster的命令已经集成到了redis-cli中了。这里我用的是Redis5,所以没有再单独安装redis-trib工具。

接下来执行命令

1redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6479 127.0.0.1:6480 127.0.0.1:6579 127.0.0.1:6580 --cluster-replicas 1

当你看到输出了

1[OK] All 16384 slots covered

就表示Redis Cluster已经创建成功了。

查看节点信息

此时我们使用cluster nodes 命令就可查看Redis Cluster的节点信息了。

深度原理学习–Redis集群

cluster nodes

可以看到,6379、6380和6479三个节点被配置为master节点。

reshard

接下来我们再来尝试一下reshard操作

深度原理学习–Redis集群

reshard_start

如图,输入命令

1redis-cli --cluster reshard 127.0.0.1:6380

Redis Cluster会问你要移动多少个槽位,这里我们移动1000个,接着会询问你要移动到哪个节点,这里我们输入6479的NODE ID

深度原理学习–Redis集群

reshard_end

reshard完成后,可以输入命令查看节点的情况

1redis-cli --cluster check 127.0.0.1:6480

可以看到6479节点已经多了1000个槽位了,分别是0-498和5461-5961。

新增master节点

深度原理学习–Redis集群

add_node我们可以使用add-node命令为Redis Cluster新增master节点,可以看到我们增加的是6679节点,新增成功后,并不会为任何slot提供服务。

新增slave节点

深度原理学习–Redis集群

add_slave

我们也可以用add-node命令新增slave节点,只不过需要加上--cluster-slave参数,并且使用--cluster-master-id指明新增的slave属于哪个master。

总结

最后来总结一下,我们介绍了

Redis Cluster的特性:写安全、可用性、性能

Key分配模型:使用CRC16算法,如果需要分配到相同的slot,可以使用tag

两种重定向:MOVED和ASK

容错机制:PFAIL和FAIL两种状态

最后又动手搭建了一个实验的Redis Cluster。



Tags:Redis集群   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Redis集群架构模式概述,引领我们穿越在数据存储的未知之旅
Redis,不仅是数据存储,更是架构的艺术。从主从到哨兵、再到Cluster,每个模式都有着独特的优势。而代理模式,则是应对大规模场景的得力助手。这是一场探险,Redis引领我们穿越在数...【详细内容】
2023-12-08  Search: Redis集群  点击:(136)  评论:(0)  加入收藏
使用Docker Compose搭建高可用Redis集群
  如今业务系统对于缓存Redis的依赖似乎是必不可少的,我们可以在各种各样的系统中看到Redis的身影。考虑到系统运行的稳定性,Redis的应用和MySQL数据库一样需要做到...【详细内容】
2023-11-13  Search: Redis集群  点击:(198)  评论:(0)  加入收藏
Redis集群的原理是什么?
Redis 集群是一种高可用性、高性能的 Redis 解决方案,可以在多个节点之间分配数据和负载,并在某些节点出现故障时保持数据的可用性。下面将介绍 Redis 集群的概念和原理。Redi...【详细内容】
2023-05-17  Search: Redis集群  点击:(292)  评论:(0)  加入收藏
Redis集群介绍及测试思路
作者:京东零售 李磊Redis集群介绍Redis集群一般有四种方式,分别为:主从复制、哨兵模式、Cluster以及各大厂的集群方案。在3.0版本之前只支持单实例模式,3.0之后支持了集群方式。...【详细内容】
2023-04-07  Search: Redis集群  点击:(114)  评论:(0)  加入收藏
Redis集群原理与容器化部署
1、集群原理简介1.1、什么是集群?什么是分区?集群简单的说就是将同一个服务部署在不同的机器上,从而提高服务的横向扩展能力。分区就是将数据分布在多个实例(服务器)上,让每一个实...【详细内容】
2022-09-15  Search: Redis集群  点击:(519)  评论:(0)  加入收藏
Redis集群的5种使用方式,及各自优缺点对比分析
本文主要针对 Redis 常见的几种使用方式及其优缺点展开分析。一、常见使用方式Redis 的几种常见使用方式包括: Redis 单副本 Redis 多副本(主从) Redis Sentinel(哨兵) Redis...【详细内容】
2021-03-19  Search: Redis集群  点击:(455)  评论:(0)  加入收藏
Redis集群做法的难点,百万并发客户端「实战」
Redis集群详解Redis有三种集群模式,分别是:* 主从模式 * Sentinel模式 * Cluster模式三种集群模式各有特点,关于Redis介绍可以参考这里:NoSQL(二)——RedisRedis官网:ht...【详细内容】
2020-10-17  Search: Redis集群  点击:(314)  评论:(0)  加入收藏
redis集群搭建
./redis-trib.rb create --replicas 1 172.20.10.8:7001 172.20.10.8:7002 172.20.10.8:7003 172.20.10.8:7004 172.20.10.8:7005 172.20.10.8:70061.安装ruby环境redis集群...【详细内容】
2020-08-11  Search: Redis集群  点击:(284)  评论:(0)  加入收藏
三分钟快速搭建分布式高可用的Redis集群
这里的Redis集群指的是Redis Cluster,它是Redis在3.0版本正式推出的专用集群方案,有效地解决了Redis分布式方面的需求。当单机内存、并发、流量等遇到瓶颈的时候,可以采用这种...【详细内容】
2020-07-16  Search: Redis集群  点击:(397)  评论:(0)  加入收藏
面试问Redis集群,被虐的不行了
【51CTO.com原创稿件】 上一篇我们讲解了 Redis 哨兵的工作原理,哨兵主要针对单节点故障无法自动恢复的解决方案,集群主要针对单节点容量、并发问题、线性可扩展性的解决方案...【详细内容】
2020-06-17  Search: Redis集群  点击:(338)  评论:(0)  加入收藏
▌简易百科推荐
兄弟,王者荣耀的段位排行榜是通过Redis实现的?
在王者荣耀中,我们会打排位赛,而且大家最关注的往往都是你的段位,还有在好友中的排名。作为程序员的你,是否思考过这个段位排行榜是怎么实现的?了解它的实现原理,会不会对上分有所...【详细内容】
2024-04-15    dbaplus社群  Tags:Redis   点击:(2)  评论:(0)  加入收藏
16个Redis常见使用场景总结
来源:blog.csdn.net/qq_39938758/article/details/105577370目录 缓存 数据共享分布式 分布式锁 全局ID 计数器 限流 位统计 购物车 用户消息时间线timeline 消息...【详细内容】
2024-04-11    书圈  Tags:Redis   点击:(6)  评论:(0)  加入收藏
Linux获取Redis 性能指标方法
一、监控指标Ø 性能指标:PerformanceØ 内存指标: MemoryØ 基本活动指标:Basic activityØ 持久性指标: PersistenceØ 错误指标:Error二、监...【详细内容】
2024-04-11  上海天正信息科技有限    Tags:Redis   点击:(9)  评论:(0)  加入收藏
Redis与缓存一致性问题
缓存一致性问题是在使用缓存系统,如Redis时经常遇到的问题。当数据在原始数据源(如数据库)中发生变化时,如何确保缓存中的数据与数据源保持一致,是开发者需要关注的关键问题。一...【详细内容】
2024-04-11  后端Q    Tags:Redis   点击:(6)  评论:(0)  加入收藏
Redis 不再 “开源”,未来采用 SSPLv1 和 RSALv2 许可证
Redis 官方于21日宣布修改开源协议 —— 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause...【详细内容】
2024-03-27  dbaplus社群    Tags:Redis   点击:(21)  评论:(0)  加入收藏
Redis“叛逃”开源,得罪了几乎所有人
内存数据库供应商Redis近日在开源界砸下了一块“巨石”。Redis即将转向双许可模式,并实施更为严格的许可条款。官方对此次变更的公告直截了当:从Redis 7.4版本开始,Redis将在Re...【详细内容】
2024-03-25    51CTO  Tags:Redis   点击:(12)  评论:(0)  加入收藏
如何使用 Redis 实现消息队列
Redis不仅是一个强大的内存数据存储系统,它还可以用作一个高效的消息队列。消息队列是应用程序间或应用程序内部进行异步通信的一种方式,它允许数据生产者将消息放入队列中,然...【详细内容】
2024-03-22  后端Q  微信公众号  Tags:Redis   点击:(20)  评论:(0)  加入收藏
Redis不再 “开源”
Redis 官方今日宣布修改开源协议 —— 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause 开...【详细内容】
2024-03-21  OSC开源社区    Tags:Redis   点击:(13)  评论:(0)  加入收藏
在Redis中如何实现分布式锁的防死锁机制?
在Redis中实现分布式锁是一个常见的需求,可以通过使用Redlock算法来防止死锁。Redlock算法是一种基于多个独立Redis实例的分布式锁实现方案,它通过协调多个Redis实例之间的锁...【详细内容】
2024-02-20  编程技术汇    Tags:Redis   点击:(50)  评论:(0)  加入收藏
手动撸一个 Redis 分布式锁
大家好呀,我是楼仔。今天第一天开工,收拾心情,又要开始好好学习,好好工作了。对于使用 Java 的小伙伴,其实我们完全不用手动撸一个分布式锁,直接使用 Redisson 就行。但是因为这些...【详细内容】
2024-02-19  楼仔  微信公众号  Tags:Redis   点击:(42)  评论:(0)  加入收藏
相关文章
    无相关信息
站内最新
站内热门
站内头条