Redis集群

  • 模式类型
  • 主从复制(redis2.8版本之前的模式)
  • 哨兵模式(redis2.8及之后的模式)
  • Redis官方 Cluster集群模式(服务端sharding,redis3.0`版本之后)
  • Jedis sharding集群(客户端sharding)
  • 利用中间件代理

一.主从复制

  1. 介绍
Slave从节点服务启动并连接到Master之后,它将主动发送一个SYNC命令。Master服务主节点收到同步命令后将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave从节点服务在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master主节点继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。

 	如果Master和Slave之间的链接出现断连现象,Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。
  1. 架构图
  2. 优点
  • 同一个Master可以同步多个Slaves。
  • Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。因此我们可以将Redis的Replication架构视为图结构。
  • Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
  • Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据
    为了分载Master的读操作压力,
  • Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。即便如此,系统的伸缩性还是得到了很大的提高。
  • Master可以将数据保存操作交给Slaves完成,从而避免了在Master中要有独立的进程来完成此操作。
    支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
  1. 缺点
  • Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
  • Redis的主从复制采用全量复制,复制过程中主机会fork出一个子进程对内存做一份快照,并将子进程的内存快照保存为文件发送给从机,这一过程需要确保主机有足够多的空余内存。若快照文件较大,对集群的服务能力会产生较大的影响,而且复制过程是在从机新加入集群或者从机和主机网络断开重连时都会进行,也就是网络波动都会造成主机和从机间的一次全量的数据复制,这对实际的系统运营造成了不小的麻烦。
  • Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费
    对有密码的情况说明一下,当master节点设置密码时:
  • 客户端访问master需要密码
  • 启动slave需要密码,在配置中进行配置即可
  • 客户端访问slave不需要密码

二.哨兵(Sentinel)模式

1.介绍

该模式是从Redis的2.6版本开始提供的,但是当时这个版本的模式是不稳定的,直到Redis的2.8版本以后,这个哨兵模式才稳定下来,无论是主从模式,还是哨兵模式,这两个模式都有一个问题,不能水平扩容,并且这两个模式的高可用特性都会受到Master主节点内存的限制。

	为了解决主从模式中没有故障转移机制的问题,新增了Sentinel(哨兵)进程,在Master节点宕机后,可以实现Master和Salve的切换,从而解决高可用问题。

1.1 Sentinel进程的作用:

  • 监控(Monitoring) 不断检查Master和Salve节点是否正常工作
  • 提醒(Notification) 发现故障通知其他应用及管理员
  • 自动故障迁移(Automatic failover) 当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用现在的Master替换失效Master。Master和Slave服务器切换后,Master的redis.conf、Slave的redis.conf和sentinel.conf的配置文件的内容都会发生相应的改变,即,Master主服务器的redis.conf配置文件中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换。

1.2 Sentinel(哨兵)进程的工作方式

  1. 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
  2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)
  3. 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态
  4. 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
  5. 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
  6. 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
  7. 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。

3.优点

  • 哨兵模式是基于主从模式,主从模式的优点,哨兵模式都具备
  • 具有故障转移机制。系统具有高可用性

4.缺点

  • 配置复杂
  • 较难支持在线扩容

三.Redis 官方 Cluster集群模式

1.介绍

Redis Cluster是一种服务器Sharding(分片)技术,3.0版本开始正式提供。

多个redis节点网络互联,数据共享
所有的节点都是一主一从(可以是多个从),其中从不提供服务,仅作为备用
不支持同时处理多个键(如mset/mget),因为redis需要把键均匀分布在各个节点上,并发量很高的情况下同时创建键值会降低性能并导致不可预测的行为。
支持在线增加、删除节点
客户端可以连任何一个主节点进行读写

1.1 redis数据集群分片

在redis的每一个节点上,都有这么两个东西,一个是插槽(slot)可以理解为是一个可以存储两个数值的一个变量这个变量的取值范围是:0-16383。还有一个就是cluster我个人把这个cluster理解为是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。

1.2 故障检查

  • 每个节点都有集群中各个节点的信息
  • 通过ping-pong的方式检查故障,若超过半数的节点无法ping通一个节点,则集群认为该节点宕机。
  • 若某主节点及其从节点全部fail,则集体进入fail状态

2.目前存在问题

  • 数据存储
  • 路由重定向
  • 3.0版本后才推出的解决方案,能在大规模数据中实验的成功案例还不多

3.Cluster集群相关博客

http://doc.redisfans.com/topic/cluster-tutorial.html

四.Redis sharding集群

Redis Sharding可以说是在Redis cluster出来之前业界普遍的采用方式,其主要思想是采用hash算法将存储数据的key进行hash散列,这样特定的key会被定为到特定的节点上。

1.特点

  • 采用一致性哈希算法, 将key和节点name同时hashing,然后进行映射匹配,采用的算法是MURMUR_HASH.

五.利用中间件代理

1.介绍

  • 将需要存入redis中的数据的key通过一套算法计算得出一个值。
  • 然后根据这个值找到对应的redis节点,将这些数据存在这个redis的节点中。

2.常用中间件

  • Twemproxy
  • Codis
  • nginx

Cluster集群模式搭建集群

一,环境

  • Redis集群至少需要3个节点,因为投票容错机制要求超过半数节点认为某个节点挂了该节点才是挂了,所以2个节点无法构成集群。
  • 要保证集群的高可用(HA),要保证主备结构,因此最少需要6个节点
  • 这里用一台虚拟机的六个节点来模拟,搭建伪集群

二,搭建

1.创建六个redis节点并启动

在usr/local下创建redis-cluster目录

[root@VM_0_10_centos redis-cluster]# cd /usr/local/
[root@VM_0_10_centos local]# mkdir redis-cluster

将安装好的redis服务复制到redis-cluster文件夹中

[root@VM_0_10_centos local]# cp -r redis/ redis-cluster

删除dump.rdb文件

[root@VM_0_10_centos redis7001]# rm dump.rdb 
rm: remove regular file ‘dump.rdb’? y

修改redis.conf配置文件

以下是最小修改的配置

port 7001
cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 5000
appendonly yes

复制redis7001成六分,模拟六个节点(redis7001-redis7006),并修改配置文件

[root@VM_0_10_centos redis-cluster]# ll
total 24
drwxr-xr-x 3 root root 4096 Oct 18 15:11 redis7001
drwxr-xr-x 3 root root 4096 Oct 18 15:15 redis7002
drwxr-xr-x 3 root root 4096 Oct 18 15:15 redis7003
drwxr-xr-x 3 root root 4096 Oct 18 15:15 redis7004
drwxr-xr-x 3 root root 4096 Oct 18 15:15 redis7005
drwxr-xr-x 3 root root 4096 Oct 18 15:15 redis7006
[root@VM_0_10_centos redis-cluster]#

启动六个redis服务,一个个启动太麻烦。编写脚本start-all.sh,同时启动所有node。

cd redis7001
./bin/redis-server ./redis.conf
cd ..
cd redis7002
./bin/redis-server ./redis.conf
cd ..
cd redis7003
./bin/redis-server ./redis.conf
cd ..
cd redis7004
./bin/redis-server ./redis.conf
cd ..
cd redis7005
./bin/redis-server ./redis.conf
cd ..
cd redis7006
./bin/redis-server ./redis.conf
cd ..

启动脚本,检测所有节点均已启动

[root@VM_0_10_centos redis-cluster]# chmod +x start-all.sh    #赋予脚本权限
[root@VM_0_10_centos redis-cluster]# ./start-all.sh

2.创建集群

2.1 redis 3或4版本的集群搭建

对于Redis版本3或4,有一个以前版本的旧工具redis-trib.rb。您可以src在Redis源代码分发的目录中找到它。您需要安装redisgem才能运行redis-trib。

使用redis-trib.rb用于Redis的4或3型:

gem install redis

使用redis-trib.rb用于Redis 4或3版本的集群搭建:

./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

2.2 redis 5版本的集群搭建

如果您使用的是Redis 5,这很容易实现,因为嵌入到中的Redis Cluster命令行实用程序redis-cli将为我们提供帮助,该实用程序可用于创建新集群,检查或重新分片现有集群等。

这里作者使用redis5.0.5版本,执行以下命令即可创建集群

redis-cli --cluster create 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 127.0.0.1:7006 \
--cluster-replicas 1

运行指令

最后看到

即代表创建集群成功,这意味着至少有一个Master实例为16384个可用插槽中的每一个提供服务。

最后显示了六个节点,三个主节点(M)共同分配16384个插槽,分别映射了【0-5460】,【5461-10922】,【10923-10383】solts。

2.2.1 远程连接redis集群

若要其他服务器可以远程连接该redis集群,各redis节点则需修改如下配置

redis.conf

  • redis.conf里面的”bind IP地址“是限制访问IP的,默认情况下只能在本机下访问,需要注销
    #注释掉该配置
    #bind 127.0.0.1

若这一步还不能访问,则可以关闭redis保护模式,并通过添加密码的形式保证redis安全性

protected-mode no  #默认为yes
requirepass a1s2W3l4%G #a1s2W3l4%G为自定义密码

修改完毕后清除cluster集群中各节点数据

flushdb

并删除appendonly.aof、dump.rdb、nodes.conf配置文件

[root@VM_0_10_centos redis7001]# rm -rf!(bin|redis.conf)

重新创建集群并启动

  • 这里用公网ip创建集群
    redis-cli --cluster create 49.235.161.111:7001 49.235.161.111:7002
    49.235.161.111:7003 49.235.161.111:7004 49.235.161.111:7005 49.235.161.111:7006
    –cluster-replicas 1

2.3 连接节点

最后连接集群节点,连接任意一个即可

[root@VM_0_10_centos redis-cluster]# ./redis7001/bin/redis-cli -p 7001 -c
  • 注意:一定要加上-c,不然节点之间是无法自动跳转的!如下图可以看到,存储的数据(key-value)是均匀分配到不同的节点的:

3.集群客户端命令

$ redis-cli -h host -p port -a password #在远程服务器连接

 ./redis7001/bin/redis-cli -p 7001 -c
 #一定要加上-c,不然节点之间是无法自动跳转的!如下图可以看到,存储的数据(key-value)是均匀分配到不同的节点的

3.1 集群

cluster info  #打印集群的信息

cluster nodes #列出集群当前已知的所有节点( node),以及这些节点的相关信息。

3.2 节点(nodes)

cluster meet <ip> <port>    #将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。

cluster forget <node_id>    #从集群中移除 node_id 指定的节点。

cluster replicate <node_id> #将当前节点设置为 node_id 指定的节点的从节点。

cluster saveconfig          #将节点的配置文件保存到硬盘里面。

3.3 槽(slots)

cluster addslots <slot> [slot ...] #将一个或多个槽( slot)指派( assign)给当前节点。

cluster delslots <slot> [slot ...] #移除一个或多个槽对当前节点的指派。

cluster flushslots 	#移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。

cluster setslot <slot> node <node_id> 
#将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。

cluster setslot <slot> migrating <node_id> #将本节点的槽 slot 迁移到 node_id 指定的节点中。

cluster setslot <slot> importing <node_id> #从 node_id 指定的节点中导入槽 slot 到本节点。

cluster setslot <slot> stable #取消对槽 slot 的导入( import)或者迁移( migrate)。

3.4 键

cluster keyslot <key> #计算键 key 应该被放置在哪个槽上。

cluster countkeysinslot <slot> #返回槽 slot 目前包含的键值对数量。

cluster getkeysinslot <slot> <count> #返回 count 个 slot 槽中的键