引言
本文主要是测试 SpringBoot 2.3.3 + Redis + Sentinel, 记录一些遇到的坑.
环境配置
完成本测试需要的清单如下 :
- 开发主机, 一台
- Linux 虚拟机, 一台
- SpringBoot 2.3.3 版本
- Redis, 有 sentinel 的都可以
基本架构
Linux 服务器上运行 6 个进程, 分别是 3 个 redis-server 和 3 个 redis-sentinel. redis-sentinel 只是 redis-server 一种特殊工作模式. 如果没有找到 redis-sentinel 命令, 可以看下 redis-server --help
.
xu@xu:~$ redis-server --version
Redis server v=4.0.9 sha=00000000:0 malloc=jemalloc-3.6.0 bits=64 build=9435c3c2879311f3
xu@xu:~$ redis-server --help
Usage: ./redis-server [/path/to/redis.conf] [options]
./redis-server - (read config from stdin)
./redis-server -v or --version
./redis-server -h or --help
./redis-server --test-memory <megabytes>
Examples:
./redis-server (run the server with default conf)
./redis-server /etc/redis/6379.conf
./redis-server --port 7777
./redis-server --port 7777 --slaveof 127.0.0.1 8888
./redis-server /etc/myredis.conf --loglevel verbose
Sentinel mode:
./redis-server /etc/sentinel.conf --sentinel
如果机器资源足够的话, 可以这么部署 :
![](https://i-blog.csdnimg.cn/blog_migrate/c362ce2411552a8eebb059f707146989.png#pic_center)
每个进程在一台独立的服务器上部署, 让可靠性达到最高.
如果机器资源不够的话 (像笔者一样穷), 可以在一台 Linux 虚拟机上部署 6 个进程, 毕竟只是用于测试效果.
![](https://i-blog.csdnimg.cn/blog_migrate/ca54bdf87400b316bad7bf7f6d8e9a24.png#pic_center)
笔者的测试使用的是丐版, 没办法, 穷.
只用一台去作为 slave 感觉也可以.
需要注意下 :
每个 sentinel 在配置上只需要和最开始的 redis-master 连接, 不需要把 redis-slave 中的 IP 和 port 信息加入到 sentinel 的配置中. 因为 redis-slave 的配置中会 slaveof redis-master, 所以 sentinel 是会感知到这些 redis-slave 的配置信息.
Redis 相关配置解释
有些配置如果不理解的话很容易配错, 导致连不上, 或者只连到了从库上.
bind
在配置文件 redis.conf
中, 默认的 bind
接口是 127.0.0.1
, 也就是本地回环地址
. 这样的话, 访问 Redis 服务只能通过本机的客户端连接, 而无法通过远程连接.
如果直接以 redis-server
启动 Redis 服务, 那么用的是默认配置, 默认是绑定到 127.0.0.1
; 如果用的是自定义的配置文件, bind 没有配置任何的 ip 则都可以访问.
这样可以避免将 Redis 服务暴露于危险的网络环境中, 防止一些不安全的人随随便便通过远程
连接到 Redis 服务.
如果 bind 选项为空的话, 那会接受所有来自于可用网络接口的连接.
protected-mode
Redis 3.2 版本后新增 protected-mode
配置, 默认是 yes
, 即开启. 设置外部网络连接 Redis 服务, 设置方式如下 :
- 关闭
protected-mode
模式, 此时外部网络可以直接访问. - 开启
protected-mode
保护模式, 需配置 bind ip 或者设置访问密码.
笔者猜测 :
- 如果没有配置 protected-mode 而有没有 bind 或则设置密码, 那么外部是不能访问的.
- 如果关闭了 protected-mode, 那么外部是可以访问 Redis 服务的.
- 如果 protected-mode 没有关闭但是设置了 bind 或者密码, 外部是可以访问的.
以上还有待验证.
sentinel
sentinel monitor <master-name> <ip> <redis-port> <quorum>
告诉 sentinel 去监听地址为 ip:port
的一个 master, 这里的 master-name
可以自定义,quorum
是一个数字,指明当有多少个 sentinel 认为一个 master 失效时,master 才算真正失效。master-name
只能包含英文字母,数字,和.-_
这三个字符需要注意的是 master-ip
要写真实的 ip 地址而不要用回环地址 (127.0.0.1).
配置示例 :
sentinel monitor mymaster 192.168.0.5 6379 2
其他配置
另外的配置还有 : master 多久不可用认为是失效的, master 和 slave 的密码配置, 发生 fail-over 时的通知方式.
这里描述比较详细 : Redis配置文件Sentinel.conf参数配置详解.
Redis Server 和 Sentinel 的部署
配置文件
redis-server 的配置文件
redis-master 的配置文件 redis-6379.conf 如下 :
port 6379
# 如果 bind 127.0.0.1 就只能本地访问了
# bind 127.0.0.1
requirepass "myredis"
daemonize yes
logfile "6379.log"
dbfilename "dump-6379.rdb"
dir "/data/6379"
#如若master设置了认证密码, 那么所有redis数据节点都配置上masterauth属性
masterauth "myredis"
redis-slave1 的配置文件 redis-6380.conf 如下 :
port 6380
# 如果 bind 127.0.0.1 就只能本地访问了
# bind 127.0.0.1
requirepass "myredis"
daemonize yes
logfile "6380.log"
dbfilename "dump-6380.rdb"
dir "/data/6380"
#如若master设置了认证密码, 那么所有redis数据节点都配置上masterauth属性
masterauth "myredis"
# 多了这一句, 指定 master
slaveof 172.16.204.128 6379
redis-slave2 的配置文件 redis-6381.conf 如下 :
port 6381
# 如果 bind 127.0.0.1 就只能本地访问了
# bind 127.0.0.1
requirepass "myredis"
daemonize yes
logfile "6381.log"
dbfilename "dump-6381.rdb"
dir "/data/6381"
#如若master设置了认证密码, 那么所有redis数据节点都配置上masterauth属性
masterauth "myredis"
# 多了这一句, 指定 master
slaveof 172.16.204.128 6379
redis-sentinel 的配置文件
redis-sentinel1 的配置文件 sentinel-26379.conf 如下 :
port 26379
protected-mode no
daemonize yes
logfile "26379.log"
dir "/data/26379"
sentinel monitor mymaster 172.16.204.128 6379 2
#redis数据master节点设置了认证, 则需要如下配置
sentinel auth-pass mymaster myredis
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
redis-sentinel2 的配置文件 sentinel-26380.conf 如下 :
port 26380
protected-mode no
daemonize yes
logfile "26380.log"
dir "/data/26380"
sentinel monitor mymaster 172.16.204.128 6379 2
#redis数据master节点设置了认证, 则需要如下配置
sentinel auth-pass mymaster myredis
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
redis-sentinel3 的配置文件 sentinel-26381.conf 如下 :
port 26381
protected-mode no
daemonize yes
logfile "26381.log"
dir "/data/26381"
sentinel monitor mymaster 172.16.204.128 6379 2
#redis数据master节点设置了认证, 则需要如下配置
sentinel auth-pass mymaster myredis
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
启动 redis-server 和 sentinel 进程
将配置文件拷贝到用户目录下 :
# 创建所需的目录
sudo mkdir -p /data/6379 /data/6380 /data/6381
sudo mkdir -p /data/26379 /data/26380 /data/26381
# 启动 redis-server 进程
sudo redis-server ./redis-6379.conf
sudo redis-server ./redis-6380.conf
sudo redis-server ./redis-6381.conf
# 启动 redis-sentinel 进程
sudo redis-server ./sentinel-26379.conf --sentinel
sudo redis-server ./sentinel-26380.conf --sentinel
sudo redis-server ./sentinel-26381.conf --sentinel
执行上面的命令就可以启动所有的进程了, 如果有问题的话看一下日志.
xu@xu:~$ ps -ef | grep redis
root 4268 1 0 03:51 ? 00:00:00 redis-server *:6379
root 4274 1 0 03:51 ? 00:00:00 redis-server *:6380
root 4281 1 0 03:52 ? 00:00:00 redis-server *:6381
root 4288 1 0 03:52 ? 00:00:00 redis-server *:26379 [sentinel]
root 4294 1 0 03:52 ? 00:00:00 redis-server *:26380 [sentinel]
root 4300 1 0 03:52 ? 00:00:00 redis-server *:26381 [sentinel]
命令测试主从同步以及故障转移
这个比较简单了, 在 master 上写一个 key, 然后在 slave 上读一下这个 key, 可以测试同步.
通过 redis-cli
登陆到 redis-server
, 执行 info replication
可以查看主从信息.
将 master 进程 kill, 然后在另外两个 slave 上通过 info replication
查看新的 master, 在新的 master 上可以修改和写入 key.
info repliaction
查看当前节点的一些状态 :
xu@xu:~$ redis-cli
127.0.0.1:6379> auth myredis
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:172.16.204.128
master_port:6381
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:4423803
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:4b12249c313ac02e50b1cdc082a81bb813bd35a5
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:4423803
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:4420764
repl_backlog_histlen:3040
SpringBoot 2.3.3 测试 Sentinel
sentinel模式的配置
配置很简单 :
spring:
redis:
password: myredis
sentinel:
master: mymaster
# 将 sentinel 以 ip:port 加进来
nodes: 172.16.204.128:26379,172.16.204.128:26380,172.16.204.128:26381
笔者只集成了 Redis, Web和其他的都没有加.
在循环读写 redis 的过程中, 将 redis-master 进程杀死, 观察 SpringBoot 日志 :
![](https://i-blog.csdnimg.cn/blog_migrate/6c6c16efa289af4258860443b59faf36.png#pic_center)
单机模式的配置
挺简单的, 配置 host, port, password 等, 这里不细说了.
遇到的坑
redis 进程杀不掉
通过 ps -ef 可以看到如下的进程 :
xu@xu:~$ ps -ef | grep redis
redis 4129 1 0 03:49 ? 00:00:00 /usr/bin/redis-server 127.0.0.1:6379
xu 4137 1540 0 03:49 pts/0 00:00:00 grep --color=auto redis
原来是在 Ubuntu 虚拟机上用 sudo apt-get install redis
的时候会安装 redis.service
这个服务, 需要把它禁用掉 : sudo systemctl disable redis.service
.
Sentinel 连不上
现象: 连接单个 redis-master 是可以的, 但是 sentinel 就是连不上. 开始不知道什么原因, 后来仔细看了下日志, 其中一部分是 :
Suppressed: io.lettuce.core.RedisConnectionException:
DENIED Redis is running in protected mode because protected mode is enabled,
no bind address was specified, no authentication password is requested to clients.
In this mode connections are only accepted from the loopback interface.
If you want to connect from external computers to Redis you may adopt one of the following solutions:
1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent.
2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server.
3) If you started the server manually just for testing, restart it with the '--protected-mode no' option.
4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.
大概意思是, 你既没有关闭保护模式, 有没有使用密码, 有没有 bind, 那么 sentinel 就只能本地访问了. 这里的解决方案是直接关闭了 sentinel 的保护模式: protected-mode no
.
这是目前遇到的最大的一个坑.
docker-compose 部署的坑
起始放到这里不太合适, 最开始笔者想用 docker-compose 来部署的, 后来发现网络这块不太熟, 搞了半天也不行, 遂放弃.
总结
本文只是从部署层面体验了一下 Redis 的 sentinel 功能, 碰到了也排查了一些坑.
实际的使用还要对 redis 和 sentinel 的参数掌握得比较熟才行.