Redis三种集群模式原理与搭建配置

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,倚天版 1GB 1个月
简介: Redis三种集群模式原理与搭建配置

Redis作为我们最常用的内存数据库之一,在面对高并发环境时,也需要保持高可用性。因此,通常情况下我们需要配置Redis集群。

Redis集群,通常是在多个服务器上部署Redis服务,每个服务器作为一个节点,所有的节点之间互相联系,数据互通,这样就构成了Redis集群。

不过通常我们手上可能没有这么多服务器,不足以搭建集群,因此本文就在一台电脑上运行多个Redis进程为例,模拟集群搭建过程。

Redis集群有三种模式,下面我就来一一介绍一下它们的原理和搭建方式。

1,主从复制模式

(1) 原理与过程

主从复制模式是将多个节点中分为主节点从属节点,通常主节点只有一台,从节点有很多台,主节点提供写入读取功能,但是从属节点只提供读取功能。

网络异常,图片无法展示
|

图中master就是主节点,而slave就是从属节点,通常我们向主节点写入数据之后,主节点就会同步到从节点中去。

可见主从复制模式有以下优点:

  • 读写分离,职责明确
  • 高可用,如果从属节点挂掉一个,则整个集群仍然可用

主从复制的数据同步过程如下:

  1. 首先主节点启动,然后从属节点启动,从属节点会连接主节点并发送SYNC命令以请求同步
  2. 主节点收到SYNC命令之后,就会执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的写入命令
  3. 执行了BGSAVE之后,就向所有从属节点发送快照文件
  4. 从属节点收到快照文件之后,会丢弃自己已有的所有旧数据并把收到的快照写入数据库
  5. 之后,主节点会把缓冲区中的写命令发送给所有从节点实现从节点的增量同步

(2) 部署主从复制集群

这里我们搭建一个“一主二从”的集群,也就是一个主节点两个从属节点的集群,集群地址列表如下:

节点 地址 端口
主节点 127.0.0.1 7000
从属1 127.0.0.1 7001
从属2 127.0.0.1 7002

首先我们要安装好Redis,建议在Linux服务器上面进行搭建,确保redis-serverredis-cliredis-sentinel命令可以正常使用。这里就不讲述Redis的安装了,对于基本安装和配置不明白的可以参考我之前写的Linux上Redis安装配置的博客。

创建三个文件夹,里面分别存放我们三个节点的Redis配置文件,三个Redis节点的运行路径也对应着我们三个目录。我这里创建如下:

网络异常,图片无法展示
|

我这里创建了700070017002文件夹,每个文件夹里面都有一个redis.conf表示每个节点的配置文件。

7000里面是主节点配置,文件内容如下:

# 主节点配置
# 端口号
port 7000
# 后台运行
daemonize yes
# 密码
requirepass 12345678

可见主节点配置和平常没什么特别的地方。

70017002里面是从属节点配置,内容如下:

# 从属1配置
# 端口号
port 7001
# 后台运行
daemonize yes
# 密码
requirepass 12345678
# 指定该从属的主节点的地址和端口
replicaof 127.0.0.1 7000
# 主机密码
masterauth 12345678
# 从属2配置
# 端口号
port 7002
# 后台运行
daemonize yes
# 密码
requirepass 12345678
# 指定该从属的主节点的地址和端口
replicaof 127.0.0.1 7000
# 主机密码
masterauth 12345678

可见从属节点中,需要配置replicaof指定其对应的主节点的地址和端口号,以及masterauth指定主节点的密码,若主节点没有配置密码就可以省略此项,否则主节点配置了密码但是不写masterauth的话,就会导致从属节点同步数据失败!

我们通常最好是设定全部节点密码都一样。

然后依次使用cd命令进入三个文件夹并执行命令:

redis-server ./redis.conf

这样,三个节点就启动了!

我们可以用redis-cli命令连接一下我们任意一个节点,比如这里我连接主节点:

redis-cli -h127.0.0.1 -p7000

-h后面是地址,-p后面是端口。连上后使用auth 密码认证,然后就可以执行命令了!

先执行以下命令查看节点信息:

info replication

网络异常,图片无法展示
|

现在在主节点写一个数据试试:

set a b

然后退出连接一个从属节点:

redis-cli -h127.0.0.1 -p7001

在从属节点获取刚刚写的数据:

get a

网络异常,图片无法展示
|

这说明主节点写入数据后,成功地同步到了从属节点。

(3) 主从复制模式的问题

事实上,主从复制模式的缺陷也很明显:假设主节点挂了,我们需要手动去设置一个从属节点变为主节点并修改其它节点配置。

因此,主从复制模式目前用的不是说特别广泛。但是为什么这里还要学习主从复制模式呢?因为下面的模式很大程度上都基于主从复制模式。我们接着来看。

2,哨兵模式

(1) 原理和过程

哨兵模式事实上是上述主从复制模式的一种扩展,也就是说在主从复制模式的基础上,增加哨兵节点以监视所有节点的情况,假设主节点挂掉了,哨兵节点会从所有从属节点中选举一个节点作为新的主节点,并修改其余从属节点的配置。

网络异常,图片无法展示
|

哨兵节点自身不会提供任何数据的读写存储功能,仅仅是负责监视所有的节点。哨兵不仅会监视所有复制数据存储读写的主从节点,还会互相监视。

通常哨兵节点也会有好几个,不过当其中一个哨兵监视到主节点挂掉时,系统并不会马上进行选举,因为这仅仅是一个哨兵看到主节点挂掉,这时称之为主观下线。而当其它哨兵也发现主节点挂掉时,并且发现主节点挂掉的哨兵达到一定值时,哨兵之间才会进行选举过程,这时称之为客观下线。那要多少个哨兵发现主机挂掉才会触发选举呢?这个是可以配置的,我们下面来看。

哨兵模式工作过程:

  1. 每个哨兵进程以每秒钟一次的频率向其它所有节点发送PING命令
  2. 如果一个节点距离最后一次有效回复时间间隔超过阈值,则这个节点会被这个哨兵标记为主观下线(SDOWN),这个阈值可以通过哨兵节点配置文件中的down-after-milliseconds配置,单位ms
  3. 当主节点被任意一个哨兵标记为SDOWN,则正在监视主节点的所有哨兵会以每秒一次的频率确认主服务器的确进入了SDOWN状态
  4. 当有足够数量的哨兵在指定的时间范围内确认主节点进入了SDOWN,则主节点会被标记为客观下线(ODOWN),进入故障切换(failover)过程开始选举,哨兵节点选举出新的主节点后,会以发布订阅模式通知其余从属节点修改配置文件指向新的主节点

可见哨兵模式是一个自动化版的主从复制模式。

(2) 哨兵模式集群搭建和配置

在这里我们搭建一个“一主二从三哨兵”集群,如下:

节点 地址 端口
主节点 127.0.0.1 7000
从属1 127.0.0.1 7001
从属2 127.0.0.1 7002
哨兵1 127.0.0.1 8000
哨兵2 127.0.0.1 8001
哨兵3 127.0.0.1 8002

上述我们已经启动了“一主二从”集群,这里方便起见我们只需再创建三个文件夹存放三个哨兵的配置文件并在其中启动哨兵进程即可(哨兵模式中主从节点搭建配置和上述完全一样)。现在我这里目录如下:

网络异常,图片无法展示
|

然后我贴出上述第一个哨兵的配置:

# 哨兵1配置
# 端口
port 8000
# 被监视主机
sentinel monitor mymaster 127.0.0.1 7000 1
# 后台运行
daemonize yes
# 连接主机密码
sentinel auth-pass mymaster 12345678

这里sentinel monitor表示指定集群中主节点的地址和端口。这个配置有四个参数意义如下:

  • mymaster 自定义的主节点名称,同一个集群中所有哨兵的主节点名称应当相同
  • 127.0.0.1 主节点地址
  • 7000 主节点端口
  • 1 表示触发客观下线的哨兵节点数,这里表示只要有一个哨兵标记主节点为主观下线,就触发选举

然后sentinel auth-pass用于指定主节点密码,后面mymaster表示主节点名称,12345678就是主节点密码。

其余哨兵节点配置我不再一一列出,只需复制上述配置文件然后修改里面的端口号配置,其余不变即可。

当然注意集群中所有主从节点的密码要全部一样!否则可能出现同步和选举上的问题。

主从节点都还在运行,这时我们依次使用cd命令进入三个哨兵配置文件夹执行下面命令启动哨兵进程(平时需要先启动主节点,再启动从属节点,最后启动哨兵节点,注意这个顺序):

redis-sentinel ./sentinel.conf

可见这里哨兵进程需要用redis-sentinel命令启动,后面参数也是接的配置文件路径。

这时,整个哨兵模式集群搭建完毕!大家可以这个时候手动停掉主节点,然后依次连接从属节点执行info replication查看谁被选举成了新的主节点,这里我就不再演示了。

(3) Spring Boot配置连接Redis哨兵模式集群

我们很多时候使用spring-data-redis来连接Redis,不过这里连接哨兵集群和平时配置就有所不同了,我这里配置如下:

# 主节点名称
spring.redis.sentinel.master=mymaster
# 哨兵节点列表,用英文逗号隔开
spring.redis.sentinel.nodes=127.0.0.1:8000,127.0.0.1:8001,127.0.0.1:8002
# 主节点的密码
spring.redis.password=12345678

这里主节点名称就是上面哨兵配置中我们定义的mymaster,然后配置所有哨兵节点,格式为地址:端口,多个用英文逗号隔开,然后在配置主节点密码(注意是主节点密码)。

这里我们只需配置哨兵节点地址即可,项目启动后会自动通过哨兵节点找到主节点并连接,进而执行读写操作。

3,Cluster模式

这也是官方推荐的模式,是新版本Redis支持的一种集群模式。

(1) 原理和过程

在上述哨兵模式中,已经实现了高可用和读写分离。但是我们也可见每个节点都要储存一份完整的数据,这样很浪费内存。因此Redis官方推出了Cluster模式,这种模式下每个节点不会储存完整的内容,但是节点直接相互连通,所有节点内容加起来才是完整的内容。

网络异常,图片无法展示
|

上述每个节点可能储存一部分内容,但是不论某个内容存放在哪个节点,我们都可以通过任意一个节点访问到,因为它们之间互相连通。

那么,在整个集群中又是如何存放数据的呢?事实上,搭建集群的时候,Redis会根据节点数量先分配主从节点,然后根据主节点数量平均分配整个空间。

Redis会先把整个集群所使用的储存空间分为一定数量的等分,这个等分就叫做哈希槽(hash slot)

Redis集群中有16384个哈希槽,那么假设集群中有三个主节点分别是A、B和C,每个主节点对应一个从属节点A1、B1和C1,那么主节点会被分配槽位如下:

  • A包含从0-5460哈希槽位
  • B包含从5461-10922哈希槽位
  • C包含从10923-16383哈希槽位

那我们存放数据时,这个数据到底会放到哪个槽位中去?事实上,Redis也有这样的一个算法:存入数据时,就会对存入的键计算CRC16,然后拿计算出来的值对16384取模得到的结果,就是这个数据的槽位。

同样地,从属节点也会和上面一样同步主节点的内容。假设现在主节点B挂掉了,是不是意味着5461-10922槽位不能再储存数据了呢?当然不是。这时其对应的从属节点B1会被自动地提升为主节点。

(2) Cluster模式集群搭建和配置

为了保证高可用性,Redis要求Cluster模式至少需要3个主节点,而每个主节点至少要配备一个从属节点,因此我们至少需要6个节点才能搭建起来一个Redis的Cluster集群,所以说实际情况下对我们服务器数量有所要求。

节点如下:

节点 地址 端口
节点1 127.0.0.1 7000
节点2 127.0.0.1 7001
节点3 127.0.0.1 7002
节点4 127.0.0.1 7003
节点5 127.0.0.1 7004
节点6 127.0.0.1 7005

同样地,新建6个文件夹,里面分别存放每个节点的配置文件:

网络异常,图片无法展示
|

这里放出第一个节点配置:

# 节点1配置
# 端口号
port 7000
# 后台运行
daemonize yes
# 开启集群模式
cluster-enabled yes
# 配置当集群中有一台机器宕机时集群保持可用
cluster-require-full-coverage no
# 设置密码
requirepass 12345678
# 其它集群服务节点密码
masterauth 12345678

对于Cluster模式,我们每个节点都要配置cluster-enabled yes表示打开集群模式,然后注意配置所有节点密码一样!并配置masterauth选项表示该节点访问其余节点时的密码,否则也会导致节点之间互相连通时发生错误。

其余的节点配置也可以拷贝这个文件只修改里面的端口配置即可。

然后也是依次使用cd命令进入每个文件夹并依次执行启动命令:

redis-server ./redis.conf

启动之后,这时所有的节点仍然还是都单独运行的,我们还是需要用redis-cli命令将它们连结起来,才能完成集群搭建。

命令格式如下:

redis-cli --cluster create 节点1地址:节点1端口 节点2地址:节点2端口 ... --cluster-replicas1-a 密码

--cluster-replicas 1表示每个主节点分配1个从节点,因此6个节点会被计算为3主3从。如果集群都没有设置密码,可以省略-a参数。

我这里命令如下:

redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas1-a12345678

注意实际情况下指定节点一定要指定节点服务器的外网ip不是域名或者内网ip!否则可能会连结集群失败。

还有就是我们上述节点端口是70007001...等等,这个是我们设定的客户端访问端口,而集群中节点互相连通访问的端口不是这个,而对应的是1700017001...等等,也就是在客户端访问端口上加10000(外网访问端口和节点之间交流的端口总是相差10000),因此部署在服务器上时也要对应开放节点之间交流端口的防火墙。

然后会出现这些信息,输入yes确认:

网络异常,图片无法展示
|

出现这些信息则成功:

网络异常,图片无法展示
|

现在,我们可以用redis-cli连接集群:

redis-cli -h127.0.0.1 -p7000-c-a12345678

其中-c表示以集群模式连接,-a指定密码,这里要说明的是集群有密码并且以集群模式连接时一定要用-a指定连接密码,否则如果连接后再用auth输密码会导致重定向失败!

连接成功,写入数据试一下:

网络异常,图片无法展示
|

可见连接7000端口节点并写入数据,结果重定向到端口为7002的节点写入,这是因为通过上述算法对我们存入的键进行CRC16再取模运算之后得到结果15495,这个槽位位于第三个节点也就是7002端口节点,读取也是一样,如果你连接7000端口节点去取刚刚存入的键,那么它也会重定向到对应位置取得到这个键的值。通过这样重定向实现各个节点连通。

注意如果想重新配置集群,需要停止每个节点并把每个节点生成的这些文件删掉再执行上述步骤!

网络异常,图片无法展示
|

注意这个nodes.conf是集群节点自动生成的配置,用于记录节点之间的信息,它默认生成在当前运行目录,和数据文件dump.rdb在一起,如果你配置了dir指定了Redis的数据存放目录,则会生成到你指定的数据存放目录中去。平时不需要手动修改,这个文件的文件名默认是nodes.conf,可以通过cluster-config-file配置项自定义。

(3) Spring Boot连接Cluster模式集群

同样还是使用spring-data-redis来连接Redis,配置如下:

# 所有集群节点列表,用英文逗号隔开
spring.redis.cluster.nodes=127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005
# 主机的密码
spring.redis.password=12345678

可见这里只用配置所有节点地址端口和密码即可。

(4) Redisson连接Cluster集群踩坑

今天搭建了个外网服务器集群,并在一个Spring Boot项目中如上进行配置,这个项目使用了Redisson作为分布式锁功能。结果配置之后项目无法启动,并报错:nested exception is org.redisson.client.RedisConnectionException: Not all slots covered! Only 7647 slots are available. Set checkSlotsCoverage = false to avoid this check.

我寻思着我的集群已经正确配置了啊,并且配置过程中没有任何报错。为什么这里提示集群没有覆盖全部哈希槽呢?事实上,这是因为Redisson无法连接所有的节点导致。

上面我们知道了:Redis以集群模式启动时会生成一个nodes.conf文件记录集群信息,我打开一个节点的这个文件一看,发现问题所在:

网络异常,图片无法展示
|

搭建集群时生成的nodes.conf文件内容也很明显:用于记录其余各个节点的id和地址。但是这个里面有个包含myself的行,显然是记录该节点自己的信息的,但是自己的地址记录的是内网地址,这时导致我们项目从外网获得一个内网地址然后无法连接

解决方法很显然,就是先停止所有节点,并依次打开每个节点生成的nodes.conf,找到myself那一行,将其内网地址改为该节点服务器的外网地址,保存,重新启动节点即可。由于这里已经生成了nodes.conf文件记录了节点信息,因此再次启动所有节点它们之间就可以再次构成集群,不需要再像第一次创建集群的时候使用redis-cli命令了!

再次启动项目,就不会出错了!

整个文章参考:

  • Redis官方集群搭建文档:传送门
  • Spring Data Redis配置文档:
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1天前
|
存储 消息中间件 NoSQL
Redis命令详解以及存储原理
Redis命令详解以及存储原理
|
1天前
|
存储 NoSQL Redis
Redis存储原理与数据模型
Redis存储原理与数据模型
|
4天前
|
存储 缓存 NoSQL
Redis底层原理剖析
Redis是一个开源的使用ANSIC语言编码的、支持网络、可以基于内存的可持久化的日志型、Key-Value数据库,并且提供多种语言的API。
17 1
|
3天前
|
存储 缓存 NoSQL
Redis深度解析:部署模式、数据类型、存储模型与实战问题解决
Redis深度解析:部署模式、数据类型、存储模型与实战问题解决
|
4天前
|
存储 NoSQL Redis
Tair的发展问题之在Redis集群模式下,Lua脚本操作key面临什么问题,如何解决
Tair的发展问题之在Redis集群模式下,Lua脚本操作key面临什么问题,如何解决
|
5天前
|
NoSQL Java 调度
Lettuce的特性和内部实现问题之Redis的管道模式提升性能的问题如何解决
Lettuce的特性和内部实现问题之Redis的管道模式提升性能的问题如何解决
|
5天前
|
NoSQL 网络协议 安全
Lettuce的特性和内部实现问题之Lettuce天然地使用管道模式与Redis交互的问题如何解决
Lettuce的特性和内部实现问题之Lettuce天然地使用管道模式与Redis交互的问题如何解决
|
5天前
|
存储 NoSQL Ubuntu
在Ubuntu 16.04上安装和配置Redis的方法
在Ubuntu 16.04上安装和配置Redis的方法
6 0
|
5天前
|
缓存 NoSQL Ubuntu
如何在 Ubuntu 14.04 上配置 Redis 缓存以加速 WordPress
如何在 Ubuntu 14.04 上配置 Redis 缓存以加速 WordPress
10 0
|
7天前
|
NoSQL Redis
Redis——配置详解
Redis——配置详解
21 0