redis/redis集群技术.md
2025-03-15 10:55:58 +08:00

537 lines
17 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<h2><center>Redis 集群技术</center></h2>
## 一Python 连接 Redis
### 1. 安装包
```bash
[root@python ~]# yum -y install python3-pip.noarch
[root@python ~]# pip3 install ipython
[root@python ~]# pip3 install redis
```
### 2. 连接
```python
[root@python ~]# ipython
In [1]: import redis
In [2]: r = redis.Redis(host='192.168.159.131',port=6379)
In [3]: r.set("test1","111")
Out[3]: True
In [4]: r.get("test1")
Out[4]: b'111'
In [5]: ret = r.get("test1")
In [6]: ret.decode()
Out[6]: '111'
```
注意:
关闭redis的保护模式protected-mode no
### 3. 连接池
redis-py使用connection pool来管理对一个redis server的所有连接避免每次建立、释放连接的开销
默认每个Redis实例都会维护一个自己的连接池
可以直接建立一个连接池然后作为参数传给Redis这样就可以实现多个 Redis 实例共享一个连接池
```python
[root@python ~]# ipython
In [1]: import redis
In [2]: pool = redis.ConnectionPool(host='192.168.159.131',port=
...: 6379)
In [3]: rs = redis.Redis(connection_pool=pool)
In [4]: rs.set("foo","bar")
Out[4]: True
In [5]: rs.get("foo")
Out[5]: b'bar'
```
## 二Redis 主从复制集群
### 1. Redis 复制特性
- 使用异步复制
- 一个主服务器可以有多个从服务器
- 从服务器也可以有自己的从服务器
- 复制功能不会阻塞主服务器
- 可以通过复制功能来让主服务器免于执行持久化操作,由从服务器去执行持久化操作即可
- 关闭主服务器持久化时,复制功能的数据是安全的
当配置Redis复制功能时强烈建议打开主服务器的持久化功能。否则的话由于延迟等问题应该要避免部署的服务自动拉起
### 2. Redis 主从复制原理
redis 主从同步有两种方式(或者所两个阶段):全同步和部分同步
从刚刚连接的时候进行全同步全同步结束后进行部分同步。当然如果有需要slave 在任何时候都可以发起全同步
主从同步的机制:
![](http://182.92.143.66:40072/directlink/img/redis/image-202503140006.png)
- 从服务器向主服务器发送 SYNC 命令
- 接到 SYNC 命令的主服务器会调用BGSAVE 命令,创建一个 RDB 文件,并使用缓冲区记录接下来执行的所有写命令
- 当主服务器执行完 BGSAVE 命令时,它会向从服务器发送 RDB 文件,而从服务器则会接收并载入这个文件
- 主服务器将缓冲区储存的所有写命令发送给从服务器执行
### 3. Redis 命令传播
在主从服务器完成同步之后,主服务器每执行一个写命令,会将被执行的写命令发送给从服务器执行,这个操作被称为“命令传播”
命令传播是一个持续的过程:只要复制仍在继续,命令传播就会一直进行,使得主从服务器的状态可以一直保持一致
![](http://182.92.143.66:40072/directlink/img/redis/image-202503140007.png)
### 4. Redis 复制一致性问题
![](http://182.92.143.66:40072/directlink/img/redis/image-202503140008.png)
在读写分离环境下,客户端向主服务器发送写命令 SET n 10086主服务器在执行这个写命令之后向客户端返回回复并将这个写命令传播给从服务器
接到回复的客户端继续向从服务器发送读命令 GET n ,并且因为网络状态的原因,客户端的 GET命令比主服务器传播的SET 命令更快到达了从服务器
因为从服务器键 n 的值还未被更新,所以客户端在从服务器读取到的将是一个错误(过期)的 n值
### 5. Redis 复制安全性提升
主服务器只在有至少 N 个从服务器的情况下,才执行写操作从 Redis 2.8 开始, 为了保证数据的安全性, 可以通过配置, 让主服务器只在有至少 N 个当前已连接从服务器的情况下, 才执行写命令
不过, 因为 Redis 使用异步复制, 所以主服务器发送的写数据并不一定会被从服务器接收到, 因此, 数据丢失的可能性仍然是存在的
通过以下两个参数保证数据的安全:
```shell
min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>
```
要求至少有1个slave数据复制和同步的延迟不能超过10秒如果说一旦所有的slave数据复制和同步的延迟都超过了10秒钟那么这个时候master就不会再接收任何请求了
减少异步复制的数据丢失:
有了min-slaves-max-lag这个配置就可以确保说一旦slave复制数据和ack延时太长就认为可能master宕机后损失的数据太多了那么就拒绝写请求这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内
减少脑裂的数据丢失:
如果一个master出现了脑裂跟其他slave丢了连接那么上面两个配置可以确保说如果不能继续给指定数量的slave发送数据而且slave超过10秒没有给自己ack消息那么就直接拒绝客户端的写请求这样脑裂后的旧master就不会接受client的新数据也就避免了数据丢失
总结:
上面的配置就确保了如果跟任何一个slave丢了连接在10秒后发现没有slave给自己ack那么就拒绝新的写请求。因此在脑裂场景下最多就丢失10秒的数据
### 6. 主从复制实战
实验环境
三台服务器,一台master,两台slave
部署
```bash
[root@redis-master ~]# yum -y install redis
[root@redis-slave1 ~]# yum -y install redis
[root@redis-slave2 ~]# yum -y install redis
```
修改配置文件
```bash
主配置:
[root@redis-master ~]# vim /etc/redis.conf
bind 0.0.0.0
protected-mode no
requirepass master@123456
slave1配置文件
[root@redis-slave1 ~]# vim /etc/redis.conf
bind 0.0.0.0
# 关闭保护模式
protected-mode no
# 设置为从节点指向主节点IP和端口
slaveof 192.168.159.131 6379
# 主节点密码(如果主节点设置了密码)
masterauth master@123456
slave2配置文件
[root@redis-slave2 ~]# vim /etc/redis.conf
bind 0.0.0.0
# 关闭保护模式
protected-mode no
# 设置为从节点指向主节点IP和端口
slaveof 192.168.159.131 6379
# 主节点密码(如果主节点设置了密码)
masterauth master@123456
```
注意:
配置文件参数地址https://xingdian-file.oss-cn-hangzhou.aliyuncs.com/redis-config.txt
启动服务
```bash
[root@redis-master ~]# systemctl restart redis
[root@redis-slave1 ~]# systemctl restart redis
[root@redis-slave2 ~]# systemctl restart redis
```
验证服务
```bash
[root@redis-master ~]# redis-cli -h 192.168.159.131 -a "master@123456" info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.159.133,port=6379,state=online,offset=309,lag=1
slave1:ip=192.168.159.132,port=6379,state=online,offset=309,lag=1
master_repl_offset:309
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:308
[root@redis-master ~]# redis-cli -a "master@123456"
127.0.0.1:6379> set test1 111
OK
127.0.0.1:6379> get test1
"111"
[root@redis-slave1 ~]# redis-cli
127.0.0.1:6379> get test1
"111"
[root@redis-slave2 ~]# redis-cli
127.0.0.1:6379> get test1
"111"
```
## 三Redis HA Sentinel 集群
Redis-Sentinel 是 Redis 官方推荐的高可用性(HA)解决方案当用Redis做Master-slave的高可用方案时假如master宕机了Redis本身(包括它的很多客户端)都没有实现自动进行主备切换而Redis-sentinel本身也是一个独立运行的进程它能监控多个master-slave集群发现master宕机后能进行自动切换
Sentinel 是一个监视器,它可以根据被监视实例的身份和状态来判断应该执行何种动作
![](http://182.92.143.66:40072/directlink/img/redis/image-202503140009.png)
### 1. Redis Sentinel 更能
Sentinel的主要功能包括主节点存活检测、主从运行情况检测、自动故障转移failover、主从切换。Redis的Sentinel最小配置是一主一从Redis的Sentinel系统可以用来管理多个Redis服务器
监控
Sentinel会不断的检查主服务器和从服务器是否正常运行
通知
当被监控的某个Redis服务器出现问题Sentinel通过API脚本向管理员或者其他的应用程序发送通知
自动故障转移
当主节点不能正常工作时Sentinel会开始一次自动的故障转移操作它会将与失效主节点是主从关系的其中一个从节点升级为新的主节点 并且将其他的从节点指向新的主节点
配置提供者
在Redis Sentinel模式下客户端应用在初始化时连接的是Sentinel节点集合从中获取主节点的信息
### 2. Redis Sentinel 工作流程
由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器以及所有从服务器并在被监视的主服务器进入下线状态时自动将下线主服务器属下的某个从服务器升级为新的主服务器然后由新的主服务器代替已下线的主服务器继续处理命令请求
![](http://182.92.143.66:40072/directlink/img/redis/image-202503140010.png)
Sentinel负责监控集群中的所有主、从Redis当发现主故障时Sentinel会在所有的从中选一个成为新的主。并且会把其余的从变为新主的从。同时那台有问题的旧主也会变为新主的从也就是说当旧的主即使恢复时并不会恢复原来的主身份而是作为新主的一个从
在Redis高可用架构中Sentinel往往不是只有一个而是有3个或者以上。目的是为了让其更加可靠毕竟主和从切换角色这个过程还是蛮复杂的
### 3. Redis Sentinel 服务器连接
**发现并连接主服务器**
Sentinel 通过用户给定的配置文件来发现主服务器
![](http://182.92.143.66:40072/directlink/img/redis/image-202503140011.png)
Sentinel 会与被监视的主服务器创建两个网络连接
- 命令连接用于向主服务器发送命令
- 订阅连接用于订阅指定的频道,从而发现监视同一主服务器的其他 Sentinel
**发现并连接从服务器**
Sentinel 通过向主服务器发送 INFO 命令来自动获得所有从服务器的地址
跟主服务器一样Sentinel 会与每个被发现的从服务器创建命令连接和订阅连接
### 4. Redis Sentinel 命令操作
| **命令** | **描述** |
| ---------------------------------------------- | ------------------------------------------------------------ |
| PING | 返回 PONG |
| SENTINEL masters | 列出所有被监视的主服务器 |
| SENTINEL slaves <master name> | 列出所有被监视的从服务器 |
| SENTINEL get-master-addr-by-name <master name> | 返回给定名字的主服务器的 IP 地址和端口号。 |
| SENTINEL reset <pattern> | 重置所有名字和给定模式 pattern 相匹配的主服务器 |
| SENTINEL failover <master name> | 当主服务器失效时, 在不询问其他 Sentinel 意见的情况下,强制开始一次自动故障迁移。 |
### 5. Redis Sentinel (哨兵)
**环境说明**
| **主机名称** | **IP地址** | **redis版本和角色说明** |
| ------------- | --------------------- | ----------------------- |
| redis-master | 192.168.152.133:6379 | redis 6.0.5(主) |
| redis-slave01 | 192.168.152.134:6379 | redis 6.0.5(从) |
| redis-slave02 | 192.168.152.135:6379 | redis 6.0.5(从) |
| redis-master | 192.168.152.133:26379 | Sentinel01 |
| redis-slave01 | 192.168.152.134:26379 | Sentinel02 |
| redis-slave02 | 192.168.152.135:26379 | Sentinel03 |
**安装(所有节点安装)**
```bash
[root@redis-master ~]# yum -y install redis
[root@redis-slave1 ~]# yum -y install redis
[root@redis-slave2 ~]# yum -y install redis
```
**部署主从(略)**
**部署Sentinel**
```bash
[root@redis-master ~]# vim /etc/redis-sentinel.conf
protected-mode no
daemonize yes
sentinel auth-pass mymaster master@123456
sentinel monitor mymaster 192.168.159.131 6379 2
[root@redis-slave1 ~]# vim /etc/redis-sentinel.conf
protected-mode no
daemonize yes
sentinel auth-pass mymaster master@123456
sentinel monitor mymaster 192.168.159.132 6379 2
[root@redis-slave2 ~]# vim /etc/redis-sentinel.conf
protected-mode no
daemonize yes
sentinel auth-pass mymaster master@123456
sentinel monitor mymaster 192.168.159.133 6379 2
```
启动哨兵服务:
```bash
[root@redis-master ~]# redis-sentinel /etc/redis-sentinel.conf
[root@redis-slave1 ~]# redis-sentinel /etc/redis-sentinel.conf
[root@redis-slave2 ~]# redis-sentinel /etc/redis-sentinel.conf
```
验证哨兵状态:
```bash
[root@redis-master ~]# redis-cli -p 26379
127.0.0.1:26379> sentinel master mymaster # 查看监控的主节点信息
1) "name"
2) "mymaster"
3) "ip"
4) "192.168.159.131"
5) "port"
6) "6379"
7) "runid"
8) "ccbbb31aef496bcd64f9b3f7ee40aac9fd1e6075"
9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "890"
19) "last-ping-reply"
20) "890"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "10047"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "30126"
29) "config-epoch"
30) "0"
31) "num-slaves"
32) "2"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "180000"
39) "parallel-syncs"
40) "1"
127.0.0.1:26379> sentinel slaves mymaster # 查看从节点信息
1) 1) "name"
2) "192.168.159.133:6379"
3) "ip"
4) "192.168.159.133"
5) "port"
6) "6379"
7) "runid"
8) "0ddbb5f35e94425d2a5d32371d123fe9509e9fe4"
9) "flags"
10) "slave"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "153"
19) "last-ping-reply"
20) "153"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "3575"
25) "role-reported"
26) "slave"
27) "role-reported-time"
28) "43904"
29) "master-link-down-time"
30) "0"
31) "master-link-status"
32) "ok"
33) "master-host"
34) "192.168.159.131"
35) "master-port"
36) "6379"
37) "slave-priority"
38) "100"
39) "slave-repl-offset"
40) "3521"
2) 1) "name"
2) "192.168.159.132:6379"
3) "ip"
4) "192.168.159.132"
5) "port"
6) "6379"
7) "runid"
8) "43767026feff948fa4f3cca0e92fbc07f8f590a9"
9) "flags"
10) "slave"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "154"
19) "last-ping-reply"
20) "154"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "3576"
25) "role-reported"
26) "slave"
27) "role-reported-time"
28) "43905"
29) "master-link-down-time"
30) "0"
31) "master-link-status"
32) "ok"
33) "master-host"
34) "192.168.159.131"
35) "master-port"
36) "6379"
37) "slave-priority"
38) "100"
39) "slave-repl-offset"
40) "3521"
127.0.0.1:26379> sentinel sentinels mymaster # 查看哨兵节点信息
1) 1) "name"
2) "4bcba2dee21e44ef9dce0f175ee8ddc43780df78"
3) "ip"
4) "192.168.159.132"
5) "port"
6) "26379"
7) "runid"
8) "4bcba2dee21e44ef9dce0f175ee8ddc43780df78"
9) "flags"
10) "sentinel"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "352"
19) "last-ping-reply"
20) "352"
21) "down-after-milliseconds"
22) "30000"
23) "last-hello-message"
24) "810"
25) "voted-leader"
26) "?"
27) "voted-leader-epoch"
28) "0"
2) 1) "name"
2) "28c3b1bead760b3e0dca0cb1f2d223eb16081af5"
3) "ip"
4) "192.168.159.133"
5) "port"
6) "26379"
7) "runid"
8) "28c3b1bead760b3e0dca0cb1f2d223eb16081af5"
9) "flags"
10) "sentinel"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "844"
19) "last-ping-reply"
20) "844"
21) "down-after-milliseconds"
22) "30000"
23) "last-hello-message"
24) "1045"
25) "voted-leader"
26) "?"
27) "voted-leader-epoch"
28) "0"
127.0.0.1:26379>
```
注意:
如果旧主重新加入后数据不同步解决方案
可能之前是主节点,没有配置从节点的连接信息 如masterauth 连接密码当master转变为slave后由于他没有密码所以他不能从新的master同步数据随之导致 info replication 的时候,同步状态为 down ,所以只需要修改 redis.conf 中的 masterauth 为 对应的密码