一 前言

redis群集有三种模式,分别是主从同步复制、哨兵模式、Cluster

① 主从复制

主从复制是高可用Redis的基础,哨兵和cluster都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。

  缺陷:故障恢复无法自动化,写操作无法负载均衡,存储能力受到单机的限制。

② 哨兵

  在主从复制的基础上,哨兵实现了自动化的故障恢复

  缺陷:写操作无法负载均衡,存储能力受到单机的限制。

③ 集群(cluster - 官方推荐6台) 通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案

二、Redis主从复制

Redis的三种模式 (主从,哨兵,集群)_redis

通过持久化功能,redis保证了即使在服务器重启的情况下也不会丢失(或少量丢失)数据,因为持久化会把内存中的数据保存到硬盘上,重启会从硬盘上加载数据,但是由于数据是存儲在一台服务器上的,如果这台服务器出现硬盘故障等问题,也会导致数据丢失。

  为了避免单点故障,通常的做法是将数据库复制多个副本以部署在不同的服务器上,这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务,为此, redis提供了复制(replication)功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上。

  在复制的概念中,数据库分为两类,一类是主数据库(master) ,另一类是从数据(slave) 。主数据可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库,而从数据库一般是只读的,并接受主数据同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。

1、主从复制流程

Redis的三种模式 (主从,哨兵,集群)_redis_02

①Slave从节点服务启动并连接到Master之后,它将主动发送一个SYNC同步命令。

Master服务主节点收到同步命令开始执行BGSAVE命令生成RDB文件。同时使用缓冲区记录此后执行的所有写命令。

主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令

从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;

主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;

从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;(从服务器初始化完成)

主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令 (从服务器初始化完成后的操作)

 

2、主从复制的优缺点

 

优点:

支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成

Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。

Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。

Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据

 

缺点:

Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。

主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。

Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

Redis的三种模式 (主从,哨兵,集群)_数据库_03

3,实验--搭建Redis主从复制

节点名 IP地址
master 192.168.126.10
slave1 192.168.126.40
slave2 192.168.126.80
三台均已安装redis

修改Redis配置文件
Master节点
vim /etc/redis/6379.conf

bind 0.0.0.0
#70行,修改监听地址为 0.0.0.0
daemonize yes
#137行,开启守护进程
logfile var1ogredis_6379.1og
#172行,指定日志文件目录
dir varlibredis6379
#264行,指定工作目录
appendonly yes
#700行,开启 AOF 持久化功能

/etc/init.d/redis_6379 restart
#重启服务使配置生效

Redis的三种模式 (主从,哨兵,集群)_redis_04

Redis的三种模式 (主从,哨兵,集群)_redis_05

Redis的三种模式 (主从,哨兵,集群)_redis_06

Redis的三种模式 (主从,哨兵,集群)_服务器_07

Redis的三种模式 (主从,哨兵,集群)_数据库_08

Redis的三种模式 (主从,哨兵,集群)_数据库_09

Slave节点 (两个同步操作)
vim /etc/redis/6379.conf

bind 0.0.0.0
#70行,修改监听地址为 0.0.0.0
daemonize yes
#137行,开启守护进程
logfile /var/log/redis_6379.log
#172行,指定日志文件目录
dir /var/lib/redis/6379
#264行,指定工作目录
replicaof 192.168.126.10 6379
#288行,指定要同步的 Master 节点 IP 和端口
appendonly yes
#700行,开启 AOF 持久化功能

/etc/init.d/redis_6379 restart
#重启服务使配置生效

验证主从效果
主节点输入
tail -f var/log/redis_6379.log

Redis的三种模式 (主从,哨兵,集群)_redis_10

redis-cli info replication(可另开一个终端)

# Replication

rolemaster

connected_slaves2

slave0ip=192.168.126.40,port=6379,state=online,offset=238,lag=0

slave1ip=192.168.126.80,port=6379,state=online,offset=238,lag=0

#master启动时生成的40位16进制的随机字符串,用来标识master节点

master_replid0a1c276e72f872fc6db0e2d9171d874014a7000d

#切换主从的时候master节点标识会有更改

master_replid20000000000000000000000000000000000000000

#复制流中的一个偏移量,master处理完写入命令后,会把命令的字节长度做累加记录,统计在该字段。该字段也是实现部分复制的关键字段。

master_repl_offset42

#无论主从,都表示自己上次主实例repid1和复制偏移量;用于兄弟实例或级联复制,主库故障切换psync

second_repl_offset-1

repl_backlog_active1

repl_backlog_size1048576

repl_backlog_first_byte_offset1

repl_backlog_histlen42

Redis的三种模式 (主从,哨兵,集群)_服务器_11

在主上面写入数据  在从上面查询

Redis的三种模式 (主从,哨兵,集群)_数据库_12

Redis的三种模式 (主从,哨兵,集群)_redis_13

问题排查

报错排查

① WARNING The TCP backlog setting of 511 cannot be enforced because procsysnetcoresomaxconn is set to the lower value of 128

当前每一个端口最大的监听队列的长度不满足这个高负载环境,需要调整

 

解决办法

echo 2048  procsysnetcoresomaxconn

 

② WARNING overcommit_memory is set to 0! Background save may fail under low memory condition

内存超额警告,当前内存设置为0会导致后台保存失败

 

解决办法

echo vm.overcommit_memory=1  etcsysctl.conf

#刷新配置文件保其生效

sysctl vm.overcommit_memory=1

 

③ WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis

内核中启用了透明大页面(THP)支持会将导致Redis的延迟和内存使用问题

 

解决

echo never  syskernelmmtransparent_hugepageenabled

 

④ Error condition on socket for SYNC Connection reset by peer

连接被拒绝,因为主服务器可能绑定了自身IP地址

 

解决办法

主节点配置文件

bind 0.0.0.0

 

 

二、Redis哨兵

1、哨兵模式集群架构

· 哨兵是Redis集群架构中非常重要的一个组件,哨兵模式是基于主从模式实现的,也就是说同样可以实现主从分离,同样集群分为master和slave节点,哨兵的出现主要是解决了主从复制出现故障时需要人为干预的问题,(解决故障恢复无法自动化问题)

2、哨兵模式主要功能

【1】集群监控:负责监控 Redis master 和 slave 进程是否正常工作

【2】消息通知:如果某个 Redis 实例出现故障,那么哨兵负责发送消息作为报警通知给管理员

【3】故障转移:如果 master node 挂掉了,会自动转移到 slave node 上

【4】配置中心:如果故障转移发生了,通知 client 客户端习新的 master 地址

3、 哨兵模式原理

每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。

如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)

如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态

当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)

此时就会进行哨兵选举,选出一个领头的哨兵对主从数据库发起故障的修复(就是选一个从数据库作为新的Master)

在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。

当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。

若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。

命令解释:

INFO命令可以让哨兵获取到当前数据库的信息,比如运行id,复制信息等等,从而实现新节点的自动发现,从数据库的信息正是从info命令中获取的,获取从数据库信息后,就会和从数据库建立两条链接,和主数据库建立的链接是完全一样的,之后就会每10s向主从数据库发送info命令,当有新的从数据库加入时,就会从info命令中发现了,从而将这个新的slave加入自己的监控列表中。当然如果有新的哨兵加入到了监控中,其他哨兵也是从这个info命令中获取的。

Ping命令其实就是监控节点是否正常运行

 

4、哨兵选举过程:

1.第一个发现该master挂了的哨兵,向每个哨兵发送命令,让对方选举自己成为领头哨兵

2.其他哨兵如果没有选举过他人,就会将这一票投给第一个发现该master挂了的哨兵

3.第一个发现该master挂了的哨兵如果发现由超过一半哨兵投给自己,并且其数量也超过了设定的quoram参数,那么该哨兵就成了领头哨兵

4.如果多个哨兵同时参与这个选举,那么就会重复该过程,直到选出一个领头哨兵

选出领头哨兵后,就开始了故障修复,会从选出一个从数据库作为新的master

5、Master选举过程:

1.从所有在线的从数据库中,选择优先级最高的从数据库

2.如果有多个优先级高的从数据库,那么就会判断其偏移量,选择偏移量最小的从数据库,这里的偏移量就是增量复制的

3.如果还是有相同条件的从数据库,就会选择运行id较小的从数据库升级为master

 

6、哨兵模式的优缺点

优点:

高可用

哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。
主从可以自动切换,系统更健壮,可用性更高。

缺点:

Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂

Redis的三种模式 (主从,哨兵,集群)_redis_14

7、流程:

 

① 首先主节点的信息是配置在哨兵(Sentinel)的配置文件中

② 哨兵节点会和配置的主节点建立起两条连接,分别为:命令连接和订阅连接

Redis发布订阅(pubsub)是一种消息通信模式发送者(pub)发送消息,订阅者 (sub) 接收消息。

③ 哨兵会通过命令连接每10s发送一次INFO命令,通过INFO命令,主节点会返回自己的run_id和自己的从节点信息

④ 哨兵会对这些从节点也建立两条连接命令连接和订阅连接

⑤ 哨兵通过命令连接向从节点发送INFO命令,获取到他的一些信息

run id(redis服务器id)

role(职能)

从服务器的复制偏移量offset

其他

------------------以上完成了哨兵监控redis集群的目的----------------------

 

------以下部分,完成的是哨兵之间的监控,以及哨兵集群的(分布式特点-数据共享)-----

⑥ 通过命令连接向服务器的sentinel hello频道发送一条消息,内容包括自己的ip端口、run id、配置(后续投票的时候会用到)等

⑦ 通过订阅连接对服务器的sentinel hello频道做了监听,所以所有的向该频道发送的哨兵的消息都能被接受到

⑧ 解析监听到的消息,进行分析提取,就可以知道还有那些别的哨兵服务节点也在监听这些主从节点了,更新结构体将这些哨兵节点记录下来

⑨ 向观察到的其他的哨兵节点建立命令连接----没有订阅连接

 

补充:

专业名词:

   1)命令连接:建立一个连接,用来发送一条命令

           目的:为了与对方服务器建立连接和发送请求

   2)订阅连接:为了和对方服务器 保持一个持续性的请求和相应的关系

           目的:类似于listen监听,一旦有数据,则会提取到本地服务器

   3)订阅者:  发送订阅连接的服务器服务

           解释:对一个服务服务器进行持续性绑定,用于以后的获取数据的服务身份

   4)发送者:  响应进行“订阅”的服务器,反馈自身数据

           解释:向绑定的对象,提供数据的一方

   5)INFO命令: 一条命令连接,用来请求调用被订阅端的本身数据

           目的:“提醒”被订阅端 发送数据

   6)offset:  段偏移量,和mysql中postion类似,主要用于记录每条数据保存在内存持久化文件中的位置

       解释:就是redis 数据库在持久化后保存在文件中的位置保存在内存中的位置,类似position

   7)sentinelhello频道:哨兵集群中,共享数据、获取数据的一个内存中的信号

           目的:让哨兵集群 各个节点之间数据共享,相互发现

 

 流程宏观维度:

  1、哨兵向redis master节点获取状态、信息数据,并且知晓从节点位置

 2、哨兵向从节点获取状态、信息数据,哨兵对redis 集群进行监控

 3、哨兵集群之间 向hello频道(哨兵之间共享数据的位置)发送自己获取的数据

 4、哨兵从hello节点获取到其他哨兵节点的位置

 5、哨兵之间进行数据共享、及彼此监控

 

故障迁移

【1】在从节点中挑选出新的从节点

通讯正常

优先级排序

优先级相同时选择offset最大的

【2】将该节点设置成新的主节点 slaveof no one ,并确保在后续的 INGO 命令时,该节点返回状态为 master

【3】将其他的从节点设置成从新的主节点服务, slaveof 命令

【4】将旧的主节点变成新的主节点的从节点

8、实验  搭建哨兵模式

节点名 IP地址

master 192.168.126.10

slave1 192.168.126.40

slave2 192.168.126.80

主从复制已搭建完成

Redis的三种模式 (主从,哨兵,集群)_redis_15

Redis的三种模式 (主从,哨兵,集群)_redis_16

修改哨兵配置文件[所有节点皆需]
vim /opt/redis-5.0.7/sentinel.conf

#17行,关闭保护模式
protected-mode no
#21行,Redis哨 兵默认的监听端口
port 26379
#26行 开启守护进程
daemonize yes
#36行,指定日志存放路径
logfile /var/log/sentinel.log
#65行,指定数据库存放路径
dir /var/lib/redis/6379
#84行,指定哨兵节点
#2表示,至少需要 2 个哨兵节点同意,才能判定主节点故障并进行故障转移
sentinel monitor mymaster 192.168.126.10 6379 2
#113行,判定服务器down掉的时间周期,默认30000毫秒 (30秒 )
sentinel down-after-milliseconds mymaster 3000
#146行,故障节点的最大超时时间为180000 (180秒)
sentinel failover-timeout mymaster 180000

Redis的三种模式 (主从,哨兵,集群)_redis_17

Redis的三种模式 (主从,哨兵,集群)_服务器_18

Redis的三种模式 (主从,哨兵,集群)_redis_19

Redis的三种模式 (主从,哨兵,集群)_数据库_20

Redis的三种模式 (主从,哨兵,集群)_服务器_21

启动哨兵模式

先启动主节点在启动从节点(如果后台启动失败,或者启动后自动退出,请仔细检查配置文件)

cd /opt/redis-5.0.7

redis-sentinel sentinel.conf &

Redis的三种模式 (主从,哨兵,集群)_redis_22

Redis的三种模式 (主从,哨兵,集群)_服务器_23

查看哨兵信息

[root@master redis-5.0.7]# redis-cli -p 26379 info sentinel

# Sentinel

sentinel_masters1

sentinel_tilt0

sentinel_running_scripts0

sentinel_scripts_queue_length0

sentinel_simulate_failure_flags0

master0name=mymaster,status=ok,address=192.168.226.1286379,slaves=2,sentinels=1

Redis的三种模式 (主从,哨兵,集群)_redis_24

模拟故障(rm -rf /var/run/redis_6379.pid)
ps -ef | grep redis
#查看 redis-server 的进程号

kill -9 17489
#杀死 Master 节点上的 redis-server 的进程号
查看哨兵信息
[root@master redis-5.0.7]# redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters1
sentinel_tilt0
sentinel_running_scripts0
sentinel_scripts_queue_length0
sentinel_simulate_failure_flags0
master0name=mymaster,status=odown,address=192.168.226.1286379,slaves=2,sentinels=3

status=odown
o即objectively ,客观

#查看master哨兵日志
验证结果
tail -f /var/log/sentinel.log
redis-cli -p 26379 info sentinel

Redis的三种模式 (主从,哨兵,集群)_redis_25

Redis的三种模式 (主从,哨兵,集群)_redis_26

四、Redis集群cluster

 redis是一个开源的kev-value存储系统,受到了广大互联网公司的青睐。redis3.0版本之前只支持单例模式,在3.0版本及以后才支持集群 redis集群采用P2P模式,是完全去中心化的,不存在中心节点或者代理节点;

为了实现集群的高可用,即判新节点是否健康(能否正常使用), redis-cluster有一个投票容错机制

如果集群中超过半数的节点投票认为某个节点挂了,那么这个节点就挂了(fail)。这是判断节点是否挂了的方法

判新集群是否正常

如果集群中任意一个节点挂了,而且该节点没有从节点(备份节点),那么这个集群就挂了。这是判断集群是否挂了的方法

那么为什么任意一个节点挂了(没有从节点)这个集群就挂了

因为集群内置了16384个slot(哈希槽),并且把所有的物理节点映射到了这16384[0-16383]个slot上,或者说把这些slot均等的分配给了各个节点。

当需要在Redis集群存放一个数据(key-value)时,redis会先对这个key进行crc16算法,然后得到一个结果再把这个结果对16384进行求余,这个余数会对应[0-16383]其中一个槽,进而决定key-value存储到哪个节点中。所以一旦某个节点挂了,该节点对应的slot就无法使用,那么就会导致集群无法正常工作。

示例(三个节点) :

节点A覆盖0-5460;

节点B覆盖5461-10922;

节点C覆盖10923-16383

即每个节点有5460个哈希槽

新增一个节点

节占A覆盖1365-5460

节占B覆盖6827-10922

节点C覆盖12288-16383

节点D覆盖0-1364.5461-6826.10923-12287

即每个节点有4095个哈希槽

综上所述,每个Redis集群理论上最多可以有16384个节点。

 

 

【1】在 redis-Cluster 群集中,可以给每个主节点添加从节点,主节点和从节点直接遵循主从模型的特性,当用户需要处理更多读请求的时候,添加从节点可以扩展系统的读性能

【2】redis-Cluster 的故障转移:redis群集的主节点内置了类似 redis sentinel 的节点故障检测和自动故障转移功能,当群集中的某个主节点下线时,群集中的其他在线主节点会注意到这点,并且对已经下线的主节点进行故障转移

【3】群集进行故障转移的方法和 redis sentinel 进行故障转移的方法基本一样,不同的是,在集群里面,故障转移是由集群中其他在线的主节点复制进行的,所以群集不必另外使用 redis sentinel

 

 redis的哨兵模式基本已经可以实现高可用、读写分离,但是在这种模式,每台redis服务器都存储相同的数据,很浪费内存资源,所以加入了 Cluster 群集模式,实现了redis的分布式存储,也就是说,每台redis节点存储着不同的内容

 群集部署建议至少3台以上的master节点,建议使用3主3从六个节点的模式

 Cluster 群集由多个redis服务器组成的分布式网络服务群集,群集中有多个master主节点,每个主节点都可读可写,节点之间会互相通信,两两相连,redis群集无中心节点

 

Cluster集群

主节点负责读写请求和集群信息的维护,从节点只进行主节点数据和状态信息的复制

作用

(1) 数据分区

数据分区(或称数据分片)是集群最核心的功能(分布式)

集群将数据分散到多个节点,一方面突破了 Redis 单机内存大小的限制,存储容量大大增加,另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力

Redis 单机内存大小受限问题,例如,如果单机内存太大,bgsave 和 bgrewriteaof 的 fork 操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务,全量复制阶段主节点的复制缓冲区可能溢出

(2) 高可用

集群支持主从复制(模式)和主节点的自动故障转移(与哨兵类似),当任意节点发送故障时,集群仍然可以对外提供服务

(3) 数据分片

Redis 集群引入了哈希槽的概念,有 16384 个哈希槽(编号 0~16383)

集群的每个节点负责一部分哈希槽,每个 Key 通过 CRC16 校验后对 16384 取余来决定放置哪个哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作

 2、实验搭建Cluster集群

准备环境:master1 192.168.126.10
Master2 192.168.126.40
Master3 192.168.126.60
Slave1 192.168.126.70
Slave2 192.168.126.80
Slave3 192.168.126.90
均已安装redis,关闭防火墙和增强功能,开启redis

vim /etc/redis/6379.conf
bind 127.0.0.1
#69行,注释掉bind项或不修改,默认监听所有网卡
protected-mode no
#88行,修改,关闭保护模式
port 6001
#92行,修改,redis监听端口,
daemonize yes
#136行,开启守护进程,以独立进程启动
cluster-enabled yes
#832行,取消注释,开启群集功能
cluster-config-file nodes-6001.conf
#840行,取消注释,群集名称文件设置
cluster-node-timeout 15000
#846行,取消注释群集超时时间设置
appendonly yes
#700行,修改,开启AOF持久化



启动服务
/etc/init.d/redis_6379 restart

Redis的三种模式 (主从,哨兵,集群)_数据库_27

#加入集群

redis-cli --cluster create 192.168.126.10:7001 192.168.126.40:7002 192.168.126.60:7003 192.168.126.70:7004 192.168.126.80:7005 192.168.126.90:7006 --cluster-replicas 1

#六个实例分为三组,每组一主一从,前面的做主节点,后面的做从节点

#下面交互的时候需要输入 yes 才可以创建

#-replicas 1 表示每个主节点有一个从节点

Redis的三种模式 (主从,哨兵,集群)_服务器_28Redis的三种模式 (主从,哨兵,集群)_redis_29

测试群集

redis-cli -p 6001 -c         #加-c参数,节点之,间就可以互相跳转

127.0.0.1:7001> cluster slots    #查看节点的哈希槽编号范围

Redis的三种模式 (主从,哨兵,集群)_服务器_30

Redis的三种模式 (主从,哨兵,集群)_redis_31

5798哈希槽在192.168.126.40节点的范围内,所以数据写在了40的节点上

cluster keyslot name查看name键的槽位号

Redis的三种模式 (主从,哨兵,集群)_服务器_32