Bootstrap

【Redis】集群

一个小型项目使用一台 Redis 服务器已经非常足够了,然而现实中的项目通常需要若干台Redis服务器的支持:

  • 从结构上,单个 Redis服务器会发生单点故障,同时一台服务器需要承受所有的请求负载。这就需要为数据生成多个副本并分配在不同的服务器上;
  • 从容量上,单个 Redis服务器的内存非常容易成为存储瓶颈,所以需要进行数据分片。

1、集群模式

1.1 概述

Redis 集群采用P2P模式,是完全去中心化的,不存在中心节点或者代理节点。

Redis 集群是没有统一的入口的,客户端(client)连接集群的时候连接集群中的任意节点(node)即可,集群内部的节点是相互通信的(PING-PONG机制),每个节点都是一个redis实例。

Redis 把所有的 Key 分成了 16384 个 slot,每个 Redis 实例负责其中一部分 slot 。集群中的所有信息(节点、端口、slot等),都通过节点之间定期的数据交换而更新。

1.2 部署单机伪集群

Redis集群至少需要3个节点,因为投票容错机制要求超过半数节点认为某个节点挂了该节点才是挂了,所以2个节点无法构成集群。要保证集群的高可用,需要每个节点都有从节点,也就是备份节点,所以Redis集群至少需要6台服务器。

没有那么多服务器与虚拟机时,搭建伪分布式集群,即一台服务器虚拟运行6个redis实例,修改端口号为(7001-7006)

当然,部署在多台机器上操作是一致的。

👉 第一步:创建六个Redis实例

# 下载解压:https://blog.csdn.net/weixin_42364929/article/details/143316994

# 拷贝配置文件
[appuser&localhost ~]$ cd /app/redis/conf
[appuser&localhost conf]$ cp redis.conf 7001.conf

# 修改配置文件部分参数,其他参数不变
[appuser&localhost conf]$ vim 7001.conf
# 节点端口号
port 7001  
# 绑定当前机器 IP
bind 127.0.0.1  
# Redis后台运行
daemonize yes  
# 数据文件存放位置
dir /app/redis-cluster/data   
# pid 7001和port要对应
# pidfile:包含进程标识号(pid)的文件,该文件存储在文件系统定义明确的位置,因此允许其他程序找出正在运行的脚本的pid。
pidfile /var/run/redis_7001.pid  
# 日志文件
logfile "/app/redis-cluster/logs/7001.log"  
#  启动集群模式	
cluster-enabled yes
# 集群的配置  配置文件首次启动自动生成 7000,7001,7002
cluster-config-file  nodes_7001.conf  
# 请求超时  默认15秒,可自行设置
cluster-node-timeout 15000
# 是否需要每个节点都可用,集群才算可用,关闭
cluster-require-full-coverage no
# aof日志开启  有需要就开启,它会每次写操作都记录一条日志 
appendonly yes
# 密码详解:https://blog.csdn.net/damanchen/article/details/100584275
masterauth 123456@rds
requirepass 123456@rds


# 再拷贝五份配置文件
[appuser&localhost conf]$ echo "7002.conf 7003.conf 7004.conf 7005.conf 7006.conf" | xargs -n 1 cp 7001.conf

#用vim编辑器的全局替换命令(:%s/7001/7002/g)来替换节点信息
[appuser&localhost conf]$ vim 7002.conf


# 写个启动脚本用来启动Redis实例:
[appuser@localhost conf]$ cd ..
[appuser@localhost redis]$ vim start-cluster.sh
# 删除 data文件夹下的 appendonly.aof dump.rdb nodes-7005.conf
rm -rf /app/redis/data/*
# 启动服务
cd /app/redis/bin
./redis-server /app/redis/conf/7001.conf
./redis-server /app/redis/conf/7002.conf
./redis-server /app/redis/conf/7003.conf
./redis-server /app/redis/conf/7004.conf
./redis-server /app/redis/conf/7005.conf
./redis-server /app/redis/conf/7006.conf


# 写个关闭脚本用来关闭Redis实例:
[appuser@localhost redis]$ vim stop-cluster.sh
cd /app/redis/bin
./redis-cli -p 7001 SHUTDOWN
./redis-cli -p 7002 SHUTDOWN
./redis-cli -p 7003 SHUTDOWN
./redis-cli -p 7004 SHUTDOWN
./redis-cli -p 7005 SHUTDOWN
./redis-cli -p 7006 SHUTDOWN

# 修改脚本权限
[appuser@localhost redis]$ chmod 764 start-cluster.sh
[appuser@localhost redis]$ chmod 764 stop-cluster.sh

# 启动Redis实例
[appuser@localhost redis]$ ./start-cluster.sh


# 查看Redis服务
[appuser@localhost script]$ ps -ef |grep redis
appuser   42398      1  0 15:19 ?        00:00:00 ./redis-server 127.0.0.1:7001 [cluster]
appuser   42400      1  0 15:19 ?        00:00:00 ./redis-server 127.0.0.1:7002 [cluster]
appuser   42402      1  0 15:19 ?        00:00:00 ./redis-server 127.0.0.1:7003 [cluster]
appuser   42412      1  0 15:19 ?        00:00:00 ./redis-server 127.0.0.1:7004 [cluster]
appuser   42414      1  0 15:19 ?        00:00:00 ./redis-server 127.0.0.1:7005 [cluster]
appuser   42416      1  0 15:19 ?        00:00:00 ./redis-server 127.0.0.1:7006 [cluster]
appuser   42441  38082  0 15:19 pts/1    00:00:00 grep --color=auto redis

# 查看集群信息(此时集群处于失败状态,各节点互相直接发现不了,而且还没有可存储的位置,即slot(槽)没有分配)
[appuser@localhost scripts]$ ../bin/redis-cli -h 127.0.0.1 -p 7001 cluster info
127.0.0.1:7001> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:0
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0
localhost:7001> keys *
(empty array)
localhost:7001> set name m
(error) CLUSTERDOWN Hash slot not served

👉 第二步:创建集群

创建Redis集群的方式有两种:redis-cli方式、redis-trib.rb工具

  • redis-cli 方式(推荐):
# 启动集群,前三台为主节点,后三台为从节点,1 表示我们希望为集群中的每个主节点创建一个从节点(可以将命令放在上边的启动脚本里边):
[appuser@localhost bin]$ ./redis-cli --cluster create --cluster-replicas 1 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 
...
Can I set the above configuration? (type 'yes' to accept): 

# 输入 yes 回车 
yes

[WARNING] Some slaves are in the same host as their master --> 主从同一个机器,因为部署的伪集群在同一机器上,不必管

Can I set the above configuration? (type ‘yes’ to accept) --> 提示你是否接受上述的配置,填入yes

此时节点已经添加,并且槽位已经分配好了,集群也处于可用的状态,查看集群状态:

[appuser@localhost bin]$ ./redis-cli -p 7001 cluster info
  • redis-trib.rb工具

Ruby工具安装:https://blog.csdn.net/weixin_42364929/article/details/120576194?spm=1001.2014.3001.5501

redis-trib.rb脚本下载:https://blog.csdn.net/weixin_42364929/article/details/120578068?spm=1001.2014.3001.5502

[appuser@localhost ~]$ mv /app/redis/src/redis-trib.rb /app/redis-cluster/bin
[appuser@localhost bin]$ ./redis-trib.rb create --replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 

2、主从模式

2.1 概述

通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据。但是由于数据是存储在一台服务器上的,如果这台服务器出现硬盘故障等问题,也会导致数据丢失。为了避免单点故障,通常的做法是将数据库复制多个副本以部署在不同的服务器上,这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务。为此,Redis提供了复制(replication)功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上。

Redis主从同步策略:主从数据库刚刚连接的时候,采用全量同步来初始化slave节点。salve正常工作时,采用增量同步来将主服务器发生的写操作同步到从服务器。无论如何,redis首先会尝试进行增量同步,如不成功,要求从数据库进行全量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。

全量同步:当一个从数据库启动后,会向主数据库发送SYNC命令。主数据库接收到SYNC命令后会开始在后台保存快照(即RDB持久化的过程),并将保存快照期间接收到的命令缓存起来。当快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库。从数据库收到后,会载入快照文件并执行收到的缓存的命令。

增量复制:从数据库发送 PSYNC命令,格式为PSYNC 主数据库的运行ID 断开前最新的命令偏移量。主数据库收到PSYNC命令后,首先会判断从数据库传送来的运行ID是否和自己的运行ID相同(确保从数据库之前确实是和自己同步的,以免从数据库拿到错误的数据),然后判断从数据库最后同步成功的命令偏移量是否在积压队列中。两个条件都满足的话就可以执行增量复制,并将积压队列中相应的命令发送给从数据库。如果此次重连不满足增量复制的条件,主数据库会进行一次全量同步。

2.2 部署配置

主数据库不需要配置,从数据库的配置文件(redis.conf)中加入slaveof 数据库地址 主数据库端口 即可

2.3 未完-待补充

  • 数据库分类、图结构
  • 乐观复制
  • 读写分离一致性
  • 从数据库持久化
  • 无硬盘复制
  • 缺点

3、哨兵模式

3.1 概述

哨兵的作用是监控Redis系统的运行状态,在主数据库故障时自动将从数据库转换为主数据库。

工作机制:

  • 每个sentinel 以每秒钟一次的频率向它所知的master,slave 以及其他sentinel 实例发送一个 PING 命令,如果一个实例距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被sentinel标记为主观下线。
  • 如果一个master被标记为主观下线,则正在监视这个master的所有sentinel 要以每秒一次的频率确认master的确进入了主观下线状态,当有足够数量的sentinel(大于等于配置文件指定的值)在指定的时间范围内确认master的确进入了主观下线状态, 则master会被标记为客观下线
  • 当master被sentinel标记为客观下线时,sentinel向下线的master的所有slave发送 INFO 命令的频率会从 10 秒一次改为 1 秒一次
    若没有足够数量的sentinel同意master已经下线,master的客观下线状态就会被移除;若master重新向sentinel的 PING 命令返回有效回复,master的主观下线状态就会被移除

使用sentinel模式的时候,客户端就不要直接连接Redis,而是连接sentinel的ip和port,由sentinel来提供具体的可提供服务的Redis实现,这样当master节点挂掉以后,sentinel就会感知并将新的master节点提供给使用者。

3.2 部署配置

创建一个哨兵配置文件sentinel.conf,内容:

sentinel monitor 主数据库名称 主数据库ip 主数据库port 执行故障恢复操作需要同意的哨兵个数

执行Sentinel进程:

[appuser&localhost bin]$ ./redis-sentinel ../conf/sentinel  

配置哨兵监控一个系统时,只需要配置其监控主数据库即可,哨兵会自动发现所有复制该数据库的从数据库

3.3 未完、待补充

  • 监控提醒
  • 投票选举
  • 自动故障迁移
  • 事件
  • 特点
  • 缺点
;