你可能从未使用过Redis的高可用方案

Redis 高可用方案: 主从复制(读写分离)和主备切换(哨兵模式)的服务端部署与客户端使用

介绍: 哨兵(sentinel)是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的Master,并将所有Slave 连接到新的Master。所以整个运行哨兵的集群的数量不得少于3个节点。 核心: 在主从复制的基础上,哨兵引入了主节点的自动故障转移。 作用:

  • 监控:哨兵会不断地检查主节点和从节点是否运作正常。
  • 自动故障转移:当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
  • 通知:哨兵可以将故障转移的结果发送给客户端。

与其他文章比对优势

  1. 编写时时候最新的Redis版本, 并且经本人部署和使用验证
  2. 使用简单, 只需要执行脚本即可完成
  3. 包含服务端部署和Golang客户端的使用, 形成闭环
  4. 以开发者视角去编写, 示例均为最小的可重现步骤

概念

  • 哨兵模式: Sentinel mode
  • 主从复制, 也叫读写分离. 主节点负责写,从节点负责读, 从节点可以有多个, 从节点可以有从节点, 但是不能循环, 从节点可以有主节点, 但是不能循环 主节点会将数据同步到从节点, 从节点会定时向主节点发送心跳, 如果主节点没有响应, 从节点会自动切换为主节点, 从节点可以配置为只读, 也可以配置为可写
  • 主备切换,也叫哨兵模式. 主节点宕机, 从节点会自动切换为主节点, 但是会丢失数据, 所以需要配置主备切换, 从节点会将数据同步到备节点, 备节点会定时向从节点发送心跳, 如果从节点没有响应, 备节点会自动切换为主节点, 从节点可以配置为只读, 也可以配置为可写

使用

本库分为两部分, 一部分是服务端, 一部分是客户端, 服务端是使用源码编译方式进行部署, 客户端是使用Golang的go-redis库对Redis Server进行读写操作

服务端

参考Github仓库server目录

概念

  • master: 主节点, 用于写入数据
  • slave: 从节点, 用于读取数据

环境

IP Linux发行版 角色 端口
192.168.2.152 Ubuntu 22.04 主节点/哨兵 6379/26379
192.168.2.155 Ubuntu 22.04 从节点/哨兵 6379/26379
192.168.2.158 Ubuntu 22.04 从节点/哨兵 6379/26379

部署

二进制安装的注意项 如果需要设置为自启动后台运行需要编写service配置文件, 需要修改redis.conf文件, 配置以下参数:

  • daemonize 改为daemonize yes
  • pidfile 改为pidfile $REDIS_HOME/redis.pid
  • supervised 值为systemd, upstart, auto, 选择当前系统管理的软件包

service配置文件需要配置以下参数:

  • Service.ExecStart=redis-server $REDIS_HOME/conf/redis.conf: 启动redis服务
  • Service.ExecStop=redis-cli -p $PORT shutdown: 退出之前使用 SHUTDOWN 命令将数据保存在磁盘上

/etc/systemd/system/redis.service示例:

ini 复制代码
[Unit]
# 简单描述服务
Description=Redis Status
# 描述服务类别,表示本服务需要在network服务启动后在启动
After=network.target

[Service]
# 设置服务的启动方式
Type=notify

# 指定服务的工作目录
WorkingDirector=/usr/local/bin/

# 杀死进程的方式
KillMode=control-group

# 启动服务的命令
ExecStart=redis-server $REDIS_HOME/conf/redis.conf

# 服务启动后的执行命令, 该命令会在ExecStart命令执行后执行
ExecStartPost=/bin/sh -c "echo $MAINPID > /var/run/redis_6379.pid"

# PID文件的位置
PIDFile=/var/run/redis_6379.pid

# 服务停止的命令: 通过redis-cli工具连接到redis服务并执行shutdown命令
ExecStop=redis-cli -p $PORT shutdown

# 服务退出后的重启策略, on-abnormal表示非正常退出时重启,on-failure表示失败时重启
Restart=on-failure

[Install]
WantedBy=multi-user.target

源码安装

运行install.sh, 该shell只适用与apt包管理器, 本shell需要安装一个pkgconf依赖包, 如果是yum包管理器, 需要自己安装相关依赖包

apt:

shell 复制代码
apt install pkgconf -y

然后运行

shell 复制代码
chmod +x install.sh
./install.sh

主从复制(读写分离)配置

完整的redis配置在conf目录中的rediis.default.conf, 取自官网, 根据你实际的需求进行修改, 本文档使用推荐的配置

主节点配置

定义REDIS_HOME变量为你自己的redis安装目录,该目录必须提前创建. 后续安装和配置都在此目录下执行 定义REDIS_PASSWORD变量为你自己的redis的密码,生产环境中, 推荐设置为高强调密码, 降低弱密码风险 定义REDIS_PORT变量为你自己的redis的端口, 生产环境中, 推荐设置为非默认端口, 降低直接扫描到该默认端口的风险

shell 复制代码
export REDIS_HOME="/home/redis"
export REDIS_PASSWORD="123456"
export REDIS_PORT="6379"

从节点配置

定义MASTER_IP变量为master节点ip和端口 定义REDIS_PASSWORD变量为你自己的redis的密码,生产环境中, 推荐设置为高强调密码, 降低弱密码风险 定义REDIS_PORT变量为你自己的redis的端口, 生产环境中, 推荐设置为非默认端口, 降低直接扫描到该默认端口的风险

shell 复制代码
export MASTER_IP="192.168.2.152 6379"
export REDIS_PASSWORD="123456"
export REDIS_PORT="6379"

验证

验证配置

全部节点都配置完成后, 需要验证是否配置成功, 需要在每个节点上执行以下命令:

redis-cli -h <HOST> -p <PORT> -a <PASSWORD> 连接redis, 例如:

shell 复制代码
redis-cli -p $REDIS_PORT -a $REDIS_PASSWORD PING

如果返回PONG表示连接成功

验证主从复制
  1. 在主节点上执行redis-cli info replication命令, 查看主节点信息, 例如:

    shell 复制代码
    redis-cli -p 6379 -a $REDIS_PASSWORD info replication
  2. 在主节点进行写操作, 例如:

    shell 复制代码
    redis-cli -p 6379 -a $REDIS_PASSWORD set name "zhangsan"
  3. 在从节点上验证是否同步成功, 例如:

    shell 复制代码
    redis-cli -p 6379 -a $REDIS_PASSWORD get name

哨兵模式

完整的redis配置在conf目录中的sentinel_default.conf, 取自官网, 根据你实际的需求进行修改, 本文档只使用了最小的可执行的的配置

修改 Redis 哨兵模式的配置文件

shell 复制代码
cd /home/redis/
cp /home/redis/redis-stable/sentinel.conf conf/

主节点配置

定义环境变量:

  1. REDIS_HOME: redis目录
  2. NODE_NAME: 节点的名称
  3. REDIS_PASSWORD: redis的密码
  4. REDIS_PORT: redis的端口, 默认6379
  5. SENTINEL_PORT: 哨兵的端口, 默认26379
  6. MASTER_IP: master节点的ip和端口
  7. SLAVE_QUORUM: 已部署的从节点的数量, 本文档中为2个从节点, 所以为2
  8. MASTER_HOST: master节点的ip和端口

注意, MASTER_NAME的值必须与其他节点不同,为了区别不同的节点

示例:

shell 复制代码
export REDIS_HOME="/home/redis"
export NODE_NAME="master1" 
export REDIS_PASSWORD="263393"
export REDIS_PORT="6379"
export SENTINEL_PORT="26379"
export MASTER_IP="192.168.2.152"
export MASTER_HOST="$MASTER_IP $REDIS_PORT"
export SLAVE_QUORUM="2"
从节点配置
  1. REDIS_HOME: redis目录
  2. NODE_NAME: 节点的名称
  3. REDIS_PASSWORD: redis的密码
  4. REDIS_PORT: redis的端口, 默认6379
  5. SENTINEL_PORT: 哨兵的端口, 默认26379
  6. MASTER_IP: master节点的ip和端口
  7. MASTER_HOST: master节点的ip和端口
  8. SLAVE_QUORUM: 已部署的从节点的数量, 本文档中为2个从节点, 所以为2

注意, NODE_NAME的值必须与其他节点不同, 为了与其他节点区分

shell 复制代码
export REDIS_HOME="/home/redis"
export NODE_NAME="master1" 
export REDIS_PASSWORD="263393"
export REDIS_PORT="6379"
export SENTINEL_PORT="26379"
export MASTER_IP="192.168.2.152"
export MASTER_HOST="$MASTER_IP $REDIS_PORT"
export SLAVE_QUORUM="2"

常用命令

redis-cli -h <HOST> -p <PORT> -a <PASSWORD> 连接redis, 例如:

shell 复制代码
redis-cli -p 6379 -a 263393 PING

lsof -i:<PORT> 查看端口占用情况和PID, 例如:

shell 复制代码
lsof -i: 6379

kill -9 <PID> 杀死进程对应的PID, 例如:

shell 复制代码
kill -9 12336379

systemctl命令:

shell 复制代码
systemctl start redis # 启动服务
systemctl stop redis # 停止服务
systemctl restart redis # 重启服务
systemctl status redis # 查看服务状态

service的Restart参数有:

  • no:服务意外终止时不会自动重启。
  • on-success:只有在服务正常退出(退出码为0)的情况下才会自动重启。
  • on-failure:只有在服务非正常退出(退出码不为0)的情况下才会自动重启。
  • on-abnormal:只有在服务以异常的方式终止时才会自动重启。
  • always:无论服务以何种方式终止,systemd 都会尝试自动重新启动服务。

安全性

ACL

解析: redis-cli

perl 复制代码
> ACL LIST
1) "user default on nopass ~* &* +@all"

每行中的前两个单词是"user",后跟用户名。接下来的词是描述不同事物的 ACL 规则。 默认用户配置为活动 (on)、不需要密码 (nopass)、访问每个可能的密钥 ( ~* ) 和 Pub/Sub 通道 ( &* ),并能够调用所有可能的命令 ( +@all )。

创建用户的语法:

  1. ACL SETUSER 关键字
  2. 用户名
  3. on | off 启用或禁用用户
  4. 用户密码
  5. nopass :删除用户的所有设置密码,并将用户标记为不需要密码:这意味着每个密码都将针对此用户。如果此指令用于默认用户,则每个新连接都将立即使用默认用户进行身份验证,而无需任何显式 AUTH 命令。请注意,resetpass 指令将清除此条件
  6. ><password> :将此密码添加到用户的有效密码列表中。例如 >mypass ,将"mypass"添加到有效密码列表中。此指令清除 nopass 标志(请参阅后面)。每个用户都可以拥有任意数量的密码
  7. <<password> :从有效密码列表中删除此密码。如果您尝试删除的密码实际上未设置,则会发出错误
  8. :将此 SHA-256 哈希值添加到用户的有效密码列表中。此哈希值将与为 ACL 用户输入的密码哈希值进行比较。这允许用户在文件中存储哈希值, acl.conf 而不是存储明文密码。仅接受 SHA-256 哈希值,因为密码哈希必须为 64 个字符,并且仅包含小写的十六进制字符

  9. ! :从有效密码列表中删除此哈希值。当您不知道哈希值指定的密码,但想要从用户中删除密码时,这很有用
  10. resetpass: 刷新允许的密码列表并删除 nopass 状态。resetpass 后,用户没有关联的密码,如果不添加一些密码(或稍后将其设置为 nopass),就无法进行身份验证
  11. 允许和禁止的命令:
    1. +@module 允许模块
    2. -@module 禁止模块
    3. ~command 允许命令
    4. +command 允许命令, 例如+config|get
    5. -command 禁止命令, 将命令删除到用户可以调用的命令列表中。从 Redis 7.0 开始,它可以与阻塞子命令一起使用 | (例如"-config|set")
    6. +@: 添加该类别中要由用户调用的所有命令,有效类别为@admin、@set、@sortedset、...依此类推,通过调用命令 ACL CAT 查看完整列表。特殊类别 @all 表示所有命令,包括当前存在于服务器中的命令,以及将来将通过模块加载的命令
    7. -@ :喜欢 +@ ,但从客户端可以调用的命令列表中删除命令
    8. allcommands :+@all 的别名。请注意,这意味着能够执行通过模块系统加载的所有未来命令
    9. nocommands :-@all 的别名。
  12. 允许和禁止某些密钥和密钥权限
    1. ~ :添加可作为命令的一部分提及的键模式。例如 ~* ,允许所有密钥。该模式是 glob 样式的模式,类似于 KEYS 的模式。可以指定多个模式
    2. %R~ :(在 Redis 7.0 及更高版本中可用)添加指定的读取键模式。这的行为类似于常规密钥模式,但仅授予从与给定模式匹配的密钥中读取的权限。有关详细信息,请参阅密钥权限。
    3. %W~ :(在 Redis 7.0 及更高版本中可用)添加指定的写入密钥模式。这的行为类似于常规密钥模式,但仅授予写入与给定模式匹配的密钥的权限。有关详细信息,请参阅密钥权限
    4. %RW~ :(在 Redis 7.0 及更高版本中可用)的 ~ 别名。
    5. allkeys :的别名 ~*
    6. resetkeys :刷新允许的键模式列表。例如 ~foo:* ~bar:* resetkeys ~objects:* ,ACL 将只允许客户端访问与模式 objects:* 匹配的密钥
  13. 允许和禁止发布/订阅频道
    1. & :(在 Redis 6.2 及更高版本中可用)添加用户可以访问的 Pub/Sub 频道的 glob 样式模式。可以指定多个通道模式。请注意,模式匹配仅针对 PUBLISH 和 SUBSCRIBE 提到的通道进行,而 PSUBSCRIBE 要求其通道模式与用户允许的通道模式之间的文字匹配
    2. allchannels :&* 的别名 允许用户访问所有 Pub/Sub 频道的别名。
    3. resetchannels :刷新允许的通道模式列表,如果用户的 Pub/Sub 客户端不再能够访问其各自的通道和/或通道模式,则断开这些客户端的连接
shell 复制代码
ACL SETUSER <用户名> [on | off] [nopass | resetpass] [~pattern [~pattern ...]] [+@module [+@module ...]] [-@module [-@module ...]] [~command [~command ...]] [+command [+command ...]] [-command [-command ...]]

配置账号密码:

bash 复制代码
sentinel sentinel-user $NODE_NAME
sentinel sentinel-pass $REDIS_PASSWORD

创建一个账号, 用于哨兵模式

shell 复制代码
redis-cli -h 192.168.2.152 -a "$REDIS_PASSWORD" -p "$SENTINEL_PORT"

以下操作都是在redis-cli中执行

示例1: 账号是master1,密码为263393, 规则是allchannels +@all

shell 复制代码
ACL SETUSER master1 ON >263393 allchannels +@all

示例2: 创建一个名为 "master1" 的用户,并启用该用户,密码为 "263393"。然后,该用户被允许执行所有命令(+@all),但被禁止执行属于危险分类(@dangerous)的命令(-@dangerous)

shell 复制代码
ACL SETUSER master1 on >263393 +@all -CONFIG -FLUSHDB -FLUSHALL

示例3: 创建一个名为 "master2" 的用户,并启用该用户,密码为 "263393"。然后,该用户被允许执行所有命令(+@all),但被禁止执行CONFIG -FLUSHDB -FLUSHALL命令

shell 复制代码
ACL SETUSER master2 on >263393 +@all -CONFIG -FLUSHDB -FLUSHALL

验证账号

shell 复制代码
auth master1 263393

关闭默认的账号

shell 复制代码
ACL SETUSER default off 

删除账号:

shell 复制代码
ACL DELUSER <username>

排错

启动redis服务

shell 复制代码
/usr/local/bin/redis-server $REDIS_HOME/conf/redis.conf

查看日志

shell 复制代码
tail -f $REDIS_HOME/logs/redis.log

使用Golang的go-redis库对Redis Server进行操作

使用

参考Github仓库client目录

  1. 安装依赖

    shell 复制代码
    go mod tidy
  2. 运行

    shell 复制代码
    go run main.go

参考

  1. Github源码
  2. 源码安装
  3. redis-cli
  4. 主从, 哨兵
  5. Linux systemd 配置文件
相关推荐
zhuyasen2 小时前
Go 分布式任务和定时任务太难?sasynq 让异步任务从未如此简单
后端·go
半新半旧4 小时前
python 整合使用 Redis
redis·python·bootstrap
daixin88486 小时前
什么是缓存雪崩?缓存击穿?缓存穿透?分别如何解决?什么是缓存预热?
java·开发语言·redis·缓存
daixin88488 小时前
Redis过期数据的删除策略是什么?有哪些?
数据库·redis·缓存
同志们8 小时前
LiteLLM Go: 多平台LLM客户端统一接口实现
llm·go
用户89535603282209 小时前
LaPluma : 一个轻盈的 Go 数据流处理库
go
vv安的浅唱9 小时前
Golang基础笔记七之指针,值类型和引用类型
后端·go
猫头虎11 小时前
2025年02月11日 Go生态洞察:Go 1.24 发布亮点全面剖析
开发语言·后端·python·golang·go·beego·go1.19
幻灭行度11 小时前
通过redis_exporter监控redis cluster
数据库·redis·缓存
冷崖15 小时前
Redis缓存策略以及bigkey的学习(九)
redis·学习·缓存