前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis专题(八)——Redis高可用(集群篇)

Redis专题(八)——Redis高可用(集群篇)

作者头像
用户1327360
发布2018-03-07 15:26:00
8530
发布2018-03-07 15:26:00
举报
文章被收录于专栏:决胜机器学习

Redis专题(八) ——Redis高可用(集群篇)

(原创内容,转载请注明来源,谢谢)

1、分片方式

当主从结构的每个库都存储全量数据,则导致该主从系统的最大存储量被最小存储的redis服务器限定,形成木桶效应。

因此可以对redis进行水平扩容。由于redis轻量级,因此可以预先分足够多数量的片,并在存储的时候客户端采用某一算法将数据平均分配到不同的redis中。当数据量小的时候,每个片占用的内存都不多;当数据量很大时,也只需要将部分redis迁移到其他服务器即可。

2、集群概述

分片方式维护成本高,从redis3.0开始,集群是更好的解决方案。集群拥有和单机一样的性能,网络分区后提供可访问性,提供主库故障恢复支持。

集群支持所有单机执行的命令,对于多键命令(如MGET),如果多键都在同一个集群节点则正常返回,否则报错。另外,集群只支持0号数据库,如果使用select选择数据库也会保存。

3、配置集群

1)将每个节点设置成可集群

将每个数据库配置文件的cluster-enabled开启(设置成yes)即可。每个集群至少要三个数据库才可能正常运行。

集群会将当前节点记录的集群状态持久化存储在指定文件中,默认是当前工作目录下的nodes.conf文件。但是,要求每个节点文件不同,否则会报错。因此,需要在开启节点前,设置节点的持久化路径,通过配置文件的命令cluster-config-file /路径/nodes.conf。

连接上任一集群,通过INFOcluster命令,可以判断该集群是否可用。返回值中如果cluster_enabled:1,则表示可用。

该配置生效后,表示该节点是一个独立的节点,还未加入集群。

2)redis-trib.rb

redis源码提供的一个文件,用于协助节点加入集群,由于是ruby写的,因此需要节点环境安装配置ruby,另外还需要gem包redis,通过gem install redis进行安装。

3)初始化集群

/redis-trib.rb的路径/redis-trib.rbcreate --replicas 1 ip1:port1 ip2:port2 ip3:port3 ip4:port4 ip5:port5 ip6:port6

其中--replicas1表示集群中每个主库一个从库,该命令会将ip1、2、3的库设置为主库,4、5、6设置为从库。

也可以同一个ip的不同port加入集群。

4)集群创建的详细过程

a.redis-trib.rb以客户端形式连接所有节点,发送ping命令,如果有任何节点无法正常服务,则集群建立失败。接着,发送INFO命令,确定每个节点的运行id以及是否开启集群。

b.向每个节点发送cluster meet命令,格式cluster meet ip port,告诉当前节点指定ip:port的节点也是集群的一个节点。从而使各ip归入一个集群。

c.分配主从数据库节点,原则是尽量让每个主库运行在不同ip,确保系统容灾能力。

d.为每个主库分配插槽,实质就是分配哪些键归哪些节点负责。

e.为每个将要成为从库的库,发送命令CLUSTER REPLICATE 主库运行ID,将当前节点转换成从库,并复制数据。

上述步骤后,集群创建完成,连接上任意节点,输入命令CLUSTER NODES,可以查看集群的情况,包括每个节点运行id、地址、端口、角色、状态、插槽等。

4、节点增加

向加为节点的redis(下面称为A),发送命令CLUSTERMEET ip port,其中ip和端口是目前集群中的任一节点(下面称为B)。

A接到命令后,会与B进行握手,使B认为A是集群的一员。接着,B会使用Gossip协议,将A的信息通知集群的其他节点。

5、插槽(Slot)分配

新节点可以执行clusterreplicate成为某个主节点的从节点,也可以申请一个插槽作为主节点运行。

1)键与插槽的关系

redis将每个键的键名有效部分用CRC16算法,计算散列值,再取对16384的余数。这样使每个键都可以分配到16384个插槽中。进而分配指定节点处理。因此,集群最大节点数量是16384,通常建议在1000左右。

有效键名指:

a.如果键名包含{,且后面有},且{}之间至少1个字符,则有效键名是{}之间的内容。

b.如果不满足上述条件,则键名是整个数据。

这样做的好处在于,可以把某个系统都设置成一样的,例如{order}:id,{order}:user:orderid,这两个键由于都有{},且里面的内容不止1个字符,因此有效键名都是order,则会被分配到1个节点进行存储,也就可以使用MGET等批量操作进行查询。

2)插槽分配指定节点

a.插槽没有分配过

在要分配的节点,执行命令clusteradd slot1 [slot2 slot3….]进行分配,如果某个插槽已经分配节点,会报错。

可以通过clusterslots查看当前插槽的情况。

b.分配过的插槽重新分配

可以使用redis-trib.rbreshard 待分片ip:端口,然后跟着命令提示输入迁移插槽数量、迁移至的运行id、迁移前的运行id,完成迁移。(推荐使用此方法)

也可以直接执行命令:cluster setslots 插槽号node 新的运行id。但是由于迁移不会把键也迁移过去,因此如果插槽里面有键会丢失,所以要按下列方式进行迁移。

a. 获取插槽存在的所有键:clustergetkeysinslot 插槽号要返回键的数量

b. 对每个键迁移:migrate 目标节点地址 目标节点端口 键名 数据库号码 超时时间 [copy] [replace]。[copy]则表示不删除当前键,是在新地址建立副本;[replace]表示目标地址如果有同名的键,则覆盖目标地址的同名键。

c. 重新分配插槽:clustersetslots 插槽号node 新的运行id。

3)迁移过程的数据问题

迁移过程中,如果时间较久,可能会存在数据不一致问题。redis提供解决方案,实现集群在线情况下的插槽迁移。

命令:

clustersetslot 插槽号migrating 新节点的运行id

cluster setslot 插槽号 importing新节点的运行id

如果要把0号插槽从A移到B,需要如下操作(redis-trib.rb的方案):

a. B执行 clustersetslot 0 importing A

b. A执行 clustersetslot 0 migrating B

c. 执行cluster getkeysinslot0获取0号插槽的键列表

d. 对第三步的每个键执行migrate,迁移键

e. clustersetslots 0 node B 完成迁移

即多了a、b两个步骤,执行完前两步时,客户端A请求插槽0中的键时,如果键存在(未迁移),则正常处理;如果不存在,则返回ASK跳转请求,告诉客户端键在B。客户端接到ASK后,向B发送ASKING,再发送请求数据的命令。

相反,如果客户端向B发送请求,如果有ASKING,则返回数据,否则B返回MOVED跳转,要求客户端去A请求数据。

6、获取键对应的插槽

客户端发送请求键的操作,如果某个节点有该键,则返回;否则返回重定向请求。这个重定向请求,如果开发语言已经封装,则对于开发者是透明的,相当于单机。如果没有封装,则需要手工实现重定向。

重定向的返回:MOVED 插槽号 IP:port,客户端收到重定向后,需要重定向到IP:port的地方,去进行键的相关操作。

redis-cli模式下,在对节点进行初始化连接的时候,加上-c参数,如果后续客户端发送过来该阶段不存在的键,会自动重定向。

优化:

重定向使得原本一次连接可以完成的操作,需要两次连接。反复这样会影响性能,通常需要客户端缓存插槽信息,后面就直接往相应的插槽发送数据。

7、故障恢复

集群内的每个节点,每秒都会随机选5个节点,再选这5个节点中最久没有响应的节点发送ping命令。如果一定时间内没有回复,会被认为疑似下线(PFAIL),与哨兵的主观下线相类似,如果要真正确认节点下线,还需要一定数量的节点认为该阶段疑似下线。

过程如下:

1)节点A认为节点B疑似下线,会和集群的其他节点广播。

2)当集群中的某一节点C收到集群中半数以上的节点认为B疑似下线,则确认B下线,并进行广播。

当集群中的一个主库下线,至少需要1个从库顶上,因此,集群中每个主库至少要有一个从库。

选择哪个从库作为新主库,和哨兵的方式一样,Raft算法,如下:

1)发现主库下线的从库A,向集群其他节点发送请求,要求称为主库。

2)集群的其他节点如果没有选其他的从库,则选A作为主库。

3)A发现集群半数以上节点选A做主库,则A就成为主库。

4)当多个库参选,出现没有库可以当选主库的情况,则这些库都随机等待一个时间再发送请求。

当某个从库变成主库后,会通过命令Slaveof no one将自己变成主库,并把旧主库的插槽转给自己负责。

当某个主库负责1个以上的插槽,且该主库下线,且没有可用的从库时,默认情况认为该集群已经不可用,集群下线。如果希望集群不下线继续工作,可以通过配置文件cluster-require-full-coverage no(默认是yes)。

——written by linhxx 2107.08.12

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-08-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 决胜机器学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档