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

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

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-08-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏AILearning

Apache Spark 2.2.0 中文文档 - 概述 | ApacheCN

Spark 概述 Apache Spark 是一个快速的, 多用途的集群计算系统。 它提供了 Java, Scala, Python 和 R 的高级 API...

2149
来自专栏Linux运维学习之路

MySQL体系结构及多实例

MySQL客户端和服务器端模型 MySQL是一个典型C/S,服务器端与客户端两部分组成 服务器端程序  mysqld mysql自带的客户端(mysql mys...

34012
来自专栏开发与安全

linux系统编程之进程(二):fork函数相关总结

fork的作用是根据一个现有的进程复制出一个新进程,原来的进程称为父进程(Parent Process),新进程称为子进程(Child Process)。系统中...

2776
来自专栏加米谷大数据

Kafka日志设置和清除策略

config/log4j.properties中日志的级别设置的是TRACE,在长时间运行过程中产生的日志大小吓人,所以如果没有特殊需求,强烈建议将其更改成IN...

1442
来自专栏Hadoop实操

如何使用Cloudera Manager在线为集群减容

在Hadoop集群资源紧张的情况下可以在线扩容来提升集群的计算能力,具体参考Fayson前面的文章《如何在非Kerberos环境下对CDH进行扩容》,那么在集群...

8107
来自专栏java、Spring、技术分享

Eureka Server

从图中可以看出Eureka服务器提供服务注册与服务查找功能。多台服务器可以形成Eureka服务器集群,以提供高可用的服务。 Eureka 服务器并没有提供后台...

776
来自专栏蓝天

Linux系统命令Top/free的使用及参数详解

top [-] [d delay] [q] [c] [S] [s] [i] [n]

872
来自专栏Java帮帮-微信公众号-技术文章全总结

day07.HDFS学习【大数据教程】

分而治之:将大文件、大批量文件,分布式存放在大量服务器上,以便于采取分而治之的方式对海量数据进行运算分析;

1244
来自专栏搜云库

CentOs7.3 搭建 Redis-4.0.1 Cluster 集群服务

CentOs7.3 搭建 Redis-4.0.1 Cluster 集群服务 Redis 简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key...

51410
来自专栏皮振伟的专栏

[linux][kprobe]谁动了我的文件---使用kprobe找到目标进程

问题场景: 云计算IaaS平台上,经常使用libvirt+qemu-kvm做基础平台。libvirt会在/etc/libvirt/qemu/目录下,保存很多份q...

3374

扫码关注云+社区