第七章Redis Cluster 核心技术
第七章· Redis Cluster 核心技术
一、Redis Cluster 分布式集群
1.什么是Redis Cluster
1)Redis集群是一个可以在多个Redis节点之间进行数据共享的设施(installation)。
2)Redis集群不支持那些需要同时处理多个键的Redis命令,因为执行这些命令需要在多个Redis节点之间移动数据,并且在高负载的情况下,这些命令将降低Redis集群的性能,并导致不可预测的行为。
3)Redis集群通过分区(partition)来提供一定程度的可用性(availability):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。
4)Redis集群有将数据自动切分(split)到多个节点的能力。
2.Redis Cluster的特点
高性能
1.在多酚片节点中,将16384个槽位,均匀分布到多个分片节点中
2.存数据时,将key做crc16(key),然后和16384进行取模,得出槽位值(0-16384之间)
3.根据计算得出的槽位值,找到相对应的分片节点的主节点,存储到相应槽位上
4.如果客户端当时连接的节点不是将来要存储的分片节点,分片集群会将客户端连接切换至真正存储节点进行数据存储
高可用
在搭建集群时,会为每一个分片的主节点,对应一个从节点,实现slaveof功能,同时当主节点down,实现类似于sentinel的自动failover的功能。
3.Redis Cluster客户端连接任意节点
如图所示,当我们用客户端连接A分片时,如果按照数据的取模,我们想要访问的数据,不在A分片中,那么集群会自动将请求进行转发。
4.redis集群数据共享(设计理念)
Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot), 数据库中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。
1.节点 A 负责处理 0 号至 5500 号哈希槽。
2.节点 B 负责处理 5501 号至 11000 号哈希槽。
3.节点 C 负责处理 11001 号至 16384 号哈希槽。
5.Redis Cluster运行机制
所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
节点的fail是通过集群中超过半数的master节点检测失效时才生效.
客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key
6.Redis Cluster如何做集群复制
为了使得集群在一部分节点下线或者无法与集群的大多数(majority)节点进行通讯的情况下, 仍然可以正常运作, Redis 集群对节点使用了主从复制功能: 集群中的每个节点都有 1 个至 N 个复制品(replica), 其中一个复制品为主节点(master), 而其余的 N-1 个复制品为从节点(slave)。
在之前列举的节点 A 、B 、C 的例子中, 如果节点 B 下线了, 那么集群将无法正常运行, 因为集群找不到节点来处理 5501 号至 11000 号的哈希槽。
假如在创建集群的时候(或者至少在节点 B 下线之前), 我们为主节点 B 添加了从节点 B1 , 那么当主节点 B 下线的时候, 集群就会将 B1 设置为新的主节点, 并让它代替下线的主节点 B , 继续处理 5501 号至 11000 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了。
不过如果节点 B 和 B1 都下线的话, Redis 集群还是会停止运作。
集群的复制特性重用了 SLAVEOF 命令的代码,所以集群节点的复制行为和 SLAVEOF 命令的复制行为完全相同。
7.Redis Cluster故障转移
1)在集群里面,节点会对其他节点进行下线检测。
2)当一个主节点下线时,集群里面的其他主节点负责对下线主节点进行故障移。
3)换句话说,集群的节点集成了下线检测和故障转移等类似 Sentinel 的功能。
4)因为 Sentinel 是一个独立运行的监控程序,而集群的下线检测和故障转移等功能是集成在节点里面的,它们的运行模式非常地不同,所以尽管这两者的功能很相似,但集群的实现没有重用 Sentinel 的代码。
8.Redis Cluster中执行命令的两种情况
1)命令发送到了正确的节点:命令要处理的键所在的槽正好是由接收命令的节点负责,那么该节点执行命令,就像单机 Redis 服务器一样。
2)命令发送到了错误的节点:接收到命令的节点并非处理键所在槽的节点,那么节点将向客户端返回一个转向(redirection)错误,告知客户端应该到哪个节点去执行这个命令,客户端会根据错误提示的信息,重新向正确的节点发送命令。
二、Redis Cluster 安装部署
1.部署Redis Cluster
6个redis实例,一般会放到3台硬件服务器
注:在企业规划中,一个分片的两个分到不同的物理机,防止硬件主机宕机造成的整个分片数据丢失。
环境规划
外网IP | 内网IP | 端口 | 安装包 |
---|---|---|---|
10.0.0.51 | 172.16.1.51 | 7000,7001 | redis-3.2.12.tar.gz |
10.0.0.52 | 172.16.1.52 | 7002,7003 | redis-3.2.12.tar.gz |
10.0.0.53 | 172.16.1.53 | 7004,7005 | redis-3.2.12.tar.gz |
安装集群插件
#EPEL源安装ruby支持
[root@db01 ~]# yum install ruby rubygems -y
#查看gem源
[root@db01 ~]# gem sources -l
*** CURRENT SOURCES ***
http://rubygems.org/
#添加阿里云的gem源
[root@db01 ~]# gem sources -a http://mirrors.aliyun.com/rubygems/
http://mirrors.aliyun.com/rubygems/ added to sources
#删除国外gem源
[root@db01 ~]# gem sources --remove https://rubygems.org/
http://rubygems.org/ removed from sources
#再次查看gem源
[root@db01 ~]# gem sources -l
#使用gem安装redis的ruby插件
[root@db01 ~]# gem install redis -v 3.3.3
Successfully installed redis-3.3.3
1 gem installed
Installing ri documentation for redis-3.3.3...
Installing RDoc documentation for redis-3.3.3...
准备6个实例
#下载
[root@db01 ~]# wget http://download.redis.io/releases/redis-3.2.12.tar.gz
#解压
[root@db01 ~]# tar xf redis-3.2.12.tar.gz
#移动到指定目录
[root@db01 ~]# mv redis-3.2.12 /application/
#做软链接
[root@db01 ~]# ln -s /application/redis-3.2.12 /application/redis
#进入redis目录
[root@db01 ~]# cd /application/redis
#编译
[root@db01 redis]# make
#添加环境变量
[root@db01 redis]# vim /etc/profile.d/redis.sh
export PATH="/application/redis/src:$PATH"
#启动redis
[root@db01 redis]# src/redis-server &
配置多实例
#创建多实例目录
[root@db01 ~]# mkdir -p /data/700{0..5}
#编辑多实例配置文件
[root@db01 ~]# vim /data/7000/redis.conf
port 7000
daemonize yes
pidfile /data/7000/redis.pid
loglevel notice
logfile "/data/7000/redis.log"
dbfilename dump.rdb
dir /data/7000
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
[root@db01 ~]# vim /data/7001/redis.conf
port 7001
daemonize yes
pidfile /data/7001/redis.pid
loglevel notice
logfile "/data/7001/redis.log"
dbfilename dump.rdb
dir /data/7001
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
[root@db01 ~]# vim /data/7002/redis.conf
port 7002
daemonize yes
pidfile /data/7002/redis.pid
loglevel notice
logfile "/data/7002/redis.log"
dbfilename dump.rdb
dir /data/7002
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
[root@db01 ~]# vim /data/7003/redis.conf
port 7003
daemonize yes
pidfile /data/7003/redis.pid
loglevel notice
logfile "/data/7003/redis.log"
dbfilename dump.rdb
dir /data/7003
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
[root@db01 ~]# vim /data/7004/redis.conf
port 7004
daemonize yes
pidfile /data/7004/redis.pid
loglevel notice
logfile "/data/7004/redis.log"
dbfilename dump.rdb
dir /data/7004
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
[root@db01 ~]# vim /data/7005/redis.conf
port 7005
daemonize yes
pidfile /data/7005/redis.pid
loglevel notice
logfile "/data/7005/redis.log"
dbfilename dump.rdb
dir /data/7005
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
#启动节点
[root@db01 ~]# redis-server /data/7000/redis.conf
[root@db01 ~]# redis-server /data/7001/redis.conf
[root@db01 ~]# redis-server /data/7002/redis.conf
[root@db01 ~]# redis-server /data/7003/redis.conf
[root@db01 ~]# redis-server /data/7004/redis.conf
[root@db01 ~]# redis-server /data/7005/redis.conf
#检查端口
[root@db01 ~]# netstat -lntup|grep 700*
tcp 0 0 0.0.0.0:17003 0.0.0.0:* LISTEN 7433/redis-server *
tcp 0 0 0.0.0.0:17004 0.0.0.0:* LISTEN 7437/redis-server *
tcp 0 0 0.0.0.0:17005 0.0.0.0:* LISTEN 7443/redis-server *
tcp 0 0 0.0.0.0:7000 0.0.0.0:* LISTEN 7423/redis-server *
tcp 0 0 0.0.0.0:7001 0.0.0.0:* LISTEN 7425/redis-server *
tcp 0 0 0.0.0.0:7002 0.0.0.0:* LISTEN 7429/redis-server *
tcp 0 0 0.0.0.0:7003 0.0.0.0:* LISTEN 7433/redis-server *
tcp 0 0 0.0.0.0:7004 0.0.0.0:* LISTEN 7437/redis-server *
tcp 0 0 0.0.0.0:7005 0.0.0.0:* LISTEN 7443/redis-server *
tcp 0 0 0.0.0.0:17000 0.0.0.0:* LISTEN 7423/redis-server *
tcp 0 0 0.0.0.0:17001 0.0.0.0:* LISTEN 7425/redis-server *
tcp 0 0 0.0.0.0:17002 0.0.0.0:* LISTEN 7429/redis-server *
tcp 0 0 :::17003 :::* LISTEN 7433/redis-server *
tcp 0 0 :::17004 :::* LISTEN 7437/redis-server *
tcp 0 0 :::17005 :::* LISTEN 7443/redis-server *
tcp 0 0 :::7000 :::* LISTEN 7423/redis-server *
tcp 0 0 :::7001 :::* LISTEN 7425/redis-server *
tcp 0 0 :::7002 :::* LISTEN 7429/redis-server *
tcp 0 0 :::7003 :::* LISTEN 7433/redis-server *
tcp 0 0 :::7004 :::* LISTEN 7437/redis-server *
tcp 0 0 :::7005 :::* LISTEN 7443/redis-server *
tcp 0 0 :::17000 :::* LISTEN 7423/redis-server *
tcp 0 0 :::17001 :::* LISTEN 7425/redis-server *
tcp 0 0 :::17002 :::* LISTEN 7429/redis-server *
#检查进程
[root@db01 ~]# ps -ef|grep redis
root