Redis哨兵模式与分区详细分析

一、Redis-Sentinel(哨兵)

1、介绍

Redis-Sentinel是redis官方推荐的高可用性解决方案,
当用redis作master-slave的高可用时,如果master本身宕机,redis本身或者客户端都没有实现主从切换的功能。

而redis-sentinel就是一个独立运行的进程,用于监控多个master-slave集群, 自动发现master宕机,进行自动切换slave > master。

sentinel主要功能如下:

  1. 不时的监控redis是否良好运行,如果节点不可达就会对节点进行下线标识   2. 如果被标识的是主节点,sentinel就会和其他的sentinel节点“协商”,如果其他节点也认为主节点不可达,    就会选举一个sentinel节点来完成自动故障转移   3. 在master-slave进行切换后,masterredis.conf、slaveredis.conf和sentinel.conf的内容都会发生改变,    即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换

2、工作原理

每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令

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

如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。

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

在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令

当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次

若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。

若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。

主观下线和客观下线

主观下线:Subjectively Down,简称 SDOWN,指的是当前 Sentinel 实例对某个redis服务器做出的下线判断。 客观下线:Objectively Down, 简称 ODOWN,指的是多个 Sentinel 实例在对Master Server做出 SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,然后开启failover.

SDOWN适合于Master和Slave,只要一个 Sentinel 发现Master进入了ODOWN, 这个 Sentinel 就可能会被其他 Sentinel 推选出, 并对下线的主服务器执行自动故障迁移操作。

ODOWN只适用于Master,对于Slave的 Redis 实例,Sentinel 在将它们判断为下线前不需要进行协商, 所以Slave的 Sentinel 永远不会达到ODOWN。

3、master宕机处理

img

img

如果master宕机,我们应该先选一个slave出来,让他成为新的master,其他redis都修改成这个新的master的slave,但是redis本身或者客户端都没有实现主从切换的功能,当然,人为地修改配置文件,实现上图的功能也是可以的,但是如果是在深夜,所有人都睡觉了呢,谁来修改配置信息?这个时候就可以使用redis的Sentinel功能了,它就是实现了,当发现master宕机,自动帮我们去修改其他redis配置文件,选举出一个新master。

4、Sentinel功能实现图

img

img

img

5、redis一些查看命令

redis-cli info  # 查看redis数据库信息

redis-cli info replication # 查看redis的复制授权信息(主从复制)

redis-cli info sentinel   # 查看redis的哨兵信息  

6、Redis主从配置

1.准备三个redis实例,一主两从  
# redis-6379.conf配置
port 6379  
daemonize yes  
logfile "6379.log"  
dbfilename "dump-6379.rdb"  
dir "/var/redis/data/"


# redis-6380.conf配置
port 6380  
daemonize yes  
logfile "6380.log"  
dbfilename "dump-6380.rdb"  
dir "/var/redis/data/"  
slaveof 127.0.0.1 6379



# redis-6381.conf配置
port 6381  
daemonize yes  
logfile "6381.log"  
dbfilename "dump-6381.rdb"  
dir "/var/redis/data/"  
slaveof 127.0.0.1 6379


2. 准备好了三个数据库实例,启动三个数据库实例  
# 启动前记得先去创建redis数据存放的文件夹
mkdir -p /var/redis/data/

# 启动实例
redis-server  redis-6379.conf  
redis-server  redis-6380.conf  
redis-server  redis-6381.conf

# 查看redis服务是否已经启动
ps -ef | grep redis


3. 确定主从关系  
redis-cli  -p 6379 info replication  
# Replication
role:master  
connected_slaves:2  
slave0:ip=127.0.0.1,port=6380,state=online,offset=336,lag=0  
slave1:ip=127.0.0.1,port=6381,state=online,offset=336,lag=1


redis-cli  -p 6380 info replication  
# Replication
role:slave  
master_host:127.0.0.1  
master_port:6379  

7、Redis Sentinel安装配置

1. Sentinel配置解析  
port 26379  // Sentinel的端口  
dir /var/redis/data/  // Sentinel日志文件存放位置  
logfile "26379.log"  // Sentinel日志文件名字

// 当前Sentinel节点监控 127.0.0.1:6379 这个主节点
// 2代表判断主节点失败至少需要2个Sentinel节点节点同意
// mymaster是主节点的别名
sentinel monitor mymaster 127.0.0.1 6379 2

// 每个Sentinel节点都要定期PING命令来判断Redis数据节点和其余Sentinel节点是否可达
// 如果超过30000毫秒30s且没有回复,则判定不可达
sentinel down-after-milliseconds mymaster 30000

// 当Sentinel节点集合对主节点故障判定达成一致时,Sentinel领导者节点会做故障转移操作,选出新的主节点,
// 原来的从节点会向新的主节点发起复制操作,限制每次向新的主节点发起复制操作的从节点个数为1
sentinel parallel-syncs mymaster 1

//故障转移超时时间为180000毫秒
sentinel failover-timeout mymaster 180000

// 后台执行
daemonize yes 


2. 准备三个哨兵,开始监控主从架构  
# 哨兵配置文件redis-26379.conf
port 26379  
dir /var/redis/data/  
logfile "26379.log"  
sentinel monitor zbjmaster  127.0.0.1 6379 2  
sentinel down-after-milliseconds zbjmaster 30000  
sentinel parallel-syncs zbjmaster 1  
sentinel failover-timeout zbjmaster 180000  
daemonize yes 


# 哨兵配置文件redis-26380.conf
port 26380  
dir /var/redis/data/  
logfile "26380.log"  
sentinel monitor zbjmaster  127.0.0.1 6379 2  
sentinel down-after-milliseconds zbjmaster 30000  
sentinel parallel-syncs zbjmaster 1  
sentinel failover-timeout zbjmaster 180000  
daemonize yes 



# 哨兵配置文件redis-26381.conf
port 26381  
dir /var/redis/data/  
logfile "26381.log"  
sentinel monitor zbjmaster  127.0.0.1 6379 2  
sentinel down-after-milliseconds zbjmaster 30000  
sentinel parallel-syncs zbjmaster 1  
sentinel failover-timeout zbjmaster 180000  
daemonize yes 



3. 启动三个哨兵实例  
redis-sentinel redis-26379.conf  
redis-sentinel redis-26380.conf  
redis-sentinel redis-26381.conf

注意!!如果发现实验不成功,需删掉所有的哨兵配置文件,从新来过
注意!!如果发现实验不成功,需删掉所有的哨兵配置文件,从新来过
注意!!如果发现实验不成功,需删掉所有的哨兵配置文件,从新来过

# 检查哨兵状态是否正常
# 只有发现如下信息,即为正常
redis-cli -p 26379 info sentinel  
# Sentinel
sentinel_masters:1  
sentinel_tilt:0  
sentinel_running_scripts:0  
sentinel_scripts_queue_length:0  
sentinel_simulate_failure_flags:0  
# 最重要的一句
master0:name=zbjmaster,status=ok,address=127.0.0.1:6380,slaves=2,sentinels=3


4. 测试哨兵的自动主从切换  
1,干掉6379的redis数据库  
    kill -9 6379的PID

2,查看6380和6381的身份信息,是否自动的进行主从切换  
    我们设置的是30s后master没有响应,哨兵自动进行主从切换,因此30s后查看主从信息
    redis-cli -p 6380 info replication
    redis-cli -p 6381 info replication

3,手动启动6379挂掉的数据库,查看是否会被哨兵,添加进信息的主从集群  
    redis-server redis-6379.conf
    redis-cli -p 6379 info replication

二、redis分区和集群

1、什么是分区和集群

  1. 分区
    分区是分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集。 分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。 分区使Redis的计算能力通过简单地增加计算机得到成倍提升,Redis的网络带宽也会随着计算机和网卡的增加而成倍增长。

  2. 集群
    redis集群就是分区的一种的实现

2、为什么要用分区

  1. 并发问题
    官方声称 redis 每秒可以执行10万条命令 但是假如业务需要每秒100万的命令执行呢(例如新浪微博某某明星出轨、官宣之类的)

  2. 数据量
    当数据量太大的时候,一台服务器内存正常是16~256G,假如你的业务需要500G内存,怎么办?

  3. 解决方案

    1. 方案一: 配置一台超级牛逼的服务器,拥有超大内存和超强的cpu, 但是这么做的成本是非常高的,而且,万一这台机器宕掉了,那你的服务还不是全挂了。
    2. 方案二: 考虑分布式,加机器,把数据分到不同的位置,分摊集中式的压力,一堆机器做一件事。

3、分区的数据分布理论

redis是一个非关系型数据库,它的存储是key-value形式的,
redis实例集群主要思想是将redis数据的key进行散列,通过hash函数特定的key会映射到指定的redis节点上

分布式数据库首要解决把整个数据集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整个数据的一个子集。

常见的分区规则有哈希分区和顺序分区。

4、顺序分区

假设我有三个节点,100个redis的数据,按照平均值(几乎是平均的),顺序分区的规则就是: 把1-33个数据 放在 node1 把34-66个数据 放在node2 把67-100个数据 放在node3

5、哈希分区

  1. 节点取余
    例如按照节点取余的方式,分三个节点 1~100的数据对3取余,可以分为三类 余数为0 余数为1 余数为2 把余数为0的数据存到同一个节点 把余数为1的数据存到同一个节点 把余数为2的数据存到同一个节点

那么同样的分4个节点就是hash(key)%4,余数相同的存到同一个节点 节点取余的优点是简单,客户端分片直接是哈希+取余

  1. 一致性哈希
    客户端进行分片,哈希+顺时针取余
  2. 虚拟槽分区
    本文研究哈希分区之虚拟槽分区,因此下面单独来聊一聊

三、哈希分区之虚拟槽分区

1、介绍

Redis Cluster采用的就是虚拟槽分区

虚拟槽分区巧妙地使用了哈希空间,使用分散度良好的哈希函数把所有的数据映射到一个固定范围内的整数集合, 这些整数就定义为槽(slot)。

Redis Cluster槽的范围是0 ~ 16383,即一共16384个槽

槽是集群内数据管理和迁移的基本单位。采用大范围的槽的主要目的是为了方便数据的拆分和集群的扩展,

每个节点(redis实例)负责一定数量的槽。

2、虚拟槽图解

img

3、搭建redis cluster

redis支持多实例的功能,我们在单机演示集群搭建,需要6个实例,三个是主节点,三个是从节点,数量为6个节点才能保证高可用的集群。

1.准备6个节点,用于存储数据,分配槽位,每个节点的配置,如下,仅仅是端口的区别  
# redis-7000.conf配置
port 7000  
daemonize yes  
dir "/opt/redis/data"  
logfile "7000.log"  
dbfilename "dump-7000.rdb"  
cluster-enabled yes  
cluster-config-file nodes-7000.conf 

其余5个配置跟上面一模一样,仅仅是端口的区别
# redis-7001.conf配置
# redis-7002.conf配置
# redis-7003.conf配置
# redis-7004.conf配置
# redis-7005.conf配置

注意:要创建存放日志的文件夹  mkdir -p /opt/redis/data


2.启动6个数据库实例  
redis-server redis-7000.conf  
redis-server redis-7001.conf  
redis-server redis-7002.conf  
redis-server redis-7003.conf  
redis-server redis-7004.conf  
redis-server redis-7005.conf

3.开始分配redis集群状态,以及槽位分配  
Redis Cluster本身提供了自动将数据分散到Redis Cluster不同节点的能力,  
但是槽位的分配就比较麻烦了,当然了,如果你是大神,你完全可以自定义槽位的分配,
一些大神已经写好了槽位分配的工具或脚本了,例如豆瓣公司开源的codis工具,还有ruby语言的作者,写的redsi.rb,
因此我们可以使用一些工具帮我们进行redis cluster的搭建

4.通过ruby脚本,一键创建redis-cluster,进行槽位分配

5.准备ruby的编程环境  
1,下载ruby的源码包  
wget https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz

2,解压缩ruby远吗  
tar -zxvf ruby-2.3.1.tar.gz

3,开始编译安装ruby  
进入ruby源码包
./configure --prefix=/opt/ruby/

4,开始编译且编译安装  
make && make install

5,配置ruby的环境变量  
vim /etc/profile  
写入如下配置
PATH=你原本的PATH:/opt/ruby/bin

source /etc/profile


6.安装ruby操作redis的模块  
1,下载ruby操作redis的模块  
wget http://rubygems.org/downloads/redis-3.3.0.gem

2,安装  
gem install -l redis-3.3.0.gem

3,搜索创建redis集群的命令  
find /opt  -name  redis-trib.rb  
/opt/redis-4.0.10/src/redis-trib.rb

7.一键创建redis集群  
/opt/redis-4.0.10/src/redis-trib.rb create --replicas 1 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
--replicas  进行身份授权 
后面的1  代表,每个主节点,只有一个从节点
默认将 7000  7001  70002  设置为主库
将7003  7004  7005  设置为从库

8.检查集群状态  
redis-cli -p 7000 cluster info

9.测试集群节点,看是否能正常写入数据  
redis-cli -c -p 7000  
    -p  指定数据库端口
    -c  指定开启集群模式

set age 18  # 设置一个key会自动分配槽位,重定向到槽位所在的节点即代表成功

在任意一个节点都可以get age,会自动重定向到 age 所在的节点。

10.redis-cluster 会默认将不同的key,进行CRC16算法,进行分配到不同槽位

11.数据正常重定向,即redis集群ok  

参考地址

如果大家喜欢我的文章,可以关注个人订阅号。欢迎随时留言、交流。如果想加入微信群的话一起讨论的话,请加管理员简栈文化-小助手(lastpass4u),他会拉你们进群。

简栈文化服务订阅号