Redis 内容及相关实验

Redis 内容及相关实验

Redis 就像一个请了个「24 小时不睡觉、记忆力还超群」的数据管家:你把数据丢给它,它直接放在内存里,随取随用,快得离谱。


目录

  1. [Redis 简介](#Redis 简介)
  2. [Redis 安装部署](#Redis 安装部署)
  3. [Redis 主从复制](#Redis 主从复制)
  4. [Redis 哨兵模式 Sentinel](#Redis 哨兵模式 Sentinel)
  5. [Redis Cluster 集群](#Redis Cluster 集群)
  6. 三种高可用方案对比小结
  7. 总结

一、Redis 简介

1.1 Redis 是什么

Redis(Remote Dictionary Server) 是一个开源的、基于内存 的键值对(Key-Value)数据库。它把所有数据放在内存里,因此读写速度能达到 10 万+ QPS;同时通过 RDB / AOF 把数据落地到磁盘,宕机后也能恢复,所以它既快又不怕丢。

它和 MySQL 这种"把数据放硬盘、用的时候再读"的传统关系型数据库不一样:MySQL 是"仓库",规整但取货慢;Redis 是"手边的保险柜",随手就能拿。

典型使用场景:

场景 说明
缓存(Cache) 把热点数据放 Redis,挡在数据库前面,扛住高并发读
数据库(DB) 直接当主存储,配合持久化保证数据不丢
消息队列 / 发布订阅 用 List、Stream 做轻量队列、用 Pub/Sub 做消息广播
排行榜 / 计数器 用 ZSet、incr 做实时排名、访问计数
分布式锁 SET key value NX 实现跨进程互斥

1.2 为什么这么快

  • 数据在内存:没有磁盘 IO 瓶颈;
  • 单线程模型:避免了多线程上下文切换和锁竞争(6.0 后引入多线程 IO,但命令执行仍是单线程);
  • IO 多路复用(epoll):一个线程就能同时hold住海量连接;
  • 高效的数据结构:SDS、跳表、哈希表等底层结构都为性能量身设计。

1.3 数据类型

Redis 的 key 都是字符串,value 支持多种结构。记住"五大基础类型 + 扩展类型"就够了:

  • String(字符串) :最常用,可存文本、数字、序列化对象,支持 incr 自增;
  • List(列表):双向链表,可做队列 / 栈;
  • Hash(哈希):键值对集合,适合存对象属性(如用户资料);
  • Set(集合):无序去重,支持交集/并集,做共同好友、抽奖;
  • ZSet(有序集合):带分数的有序集合,做排行榜神器;
  • 扩展类型:Bitmaps(位图,在线状态)、HyperLogLog(UV 统计)、Geospatial(地理附近的人)、Streams(消息流)。

1.4 持久化:RDB 与 AOF

内存数据断电即失,所以 Redis 提供两种持久化方式,生产环境建议两个都开

  • RDB(快照) :定时把内存全量数据 dump 成 .rdb 二进制文件。文件小、恢复快,适合备份;缺点是可能丢最后一次快照之后的数据。
  • AOF(日志) :把每一条写命令追加到 .aof 文件。数据更安全(可配置每秒/每次刷盘),文件大、恢复稍慢。
  • 重启时 Redis 优先用 AOF 恢复(数据更全),RDB 主要用来做快速备份和主从全量同步。

二、Redis 安装部署(实验)

实验环境:3 台机器 redis-node1/2/3(IP 分别为 172.25.254.10/20/30),系统已配置好主机名解析。以下以 node1 为例,其余节点同样操作。

2.1 安装依赖

bash 复制代码
[root@redis-node1 ~]# dnf install make gcc initscripts -y

2.2 源码编译安装

bash 复制代码
[root@redis-node1 ~]# wget https://download.redis.io/releases/redis-7.4.8.tar.gz
[root@redis-node1 ~]# tar zxf redis-7.4.8.tar.gz
[root@redis-node1 ~]# cd redis-7.4.8/
[root@redis-node1 redis-7.4.8]# make && make install

2.3 用脚本生成服务(install_server.sh)

Redis 自带 utils/install_server.sh,可以一键生成 systemd 可管理的服务。systemd 环境下脚本默认会退出,需要先把它的 systemd 检测注释掉:

bash 复制代码
[root@redis-node1 redis-7.4.8]# cd utils/
[root@redis-node1 utils]# vim install_server.sh
# 把下面这段 systemd 检测注释掉(否则脚本直接 exit)
#_pid_1_exe="$(readlink -f /proc/1/exe)"
#if [ "${_pid_1_exe##*/}" = systemd ]
#then
#       echo "This systems seems to use systemd."
#       ...
#fi

[root@redis-node1 utils]# ./install_server.sh

交互提示一路回车用默认值,关键配置如下:

复制代码
Please select the redis port for this instance: [6379]
Please select the redis config file name [/etc/redis/6379.conf] /etc/redis/redis.conf
Please select the redis log file name [/var/log/redis_6379.log]
Please select the data directory for this instance [/var/lib/redis/6379]
Please select the redis executable path [/usr/local/bin/redis-server]
...
Installation successful!

2.4 放开监听并启动

编辑配置文件,关闭保护模式、允许所有网卡监听:

bash 复制代码
[root@redis-node1 utils]# vim /etc/redis/redis.conf
# 约 89 行:允许所有 IP 监听
bind * -::*
# 约 113 行:关闭保护模式(实验环境,生产请配合密码/防火墙)
protected-mode no

[root@redis-node1 utils]# systemctl daemon-reload
[root@redis-node1 utils]# systemctl start redis_6379.service
[root@redis-node1 utils]# systemctl status redis_6379.service

2.5 验证端口监听

bash 复制代码
[root@redis-node1 ~]# netstat -antlpe | grep redis
tcp  0  0 127.0.0.1:6379    0.0.0.0:*  LISTEN  ...  redis-server
tcp  0  0 ::1:6379          :::*       LISTEN  ...  redis-server

看到 6379 端口处于 LISTEN,说明 Redis 已经跑起来了。node2node3 用同样的步骤安装即可。


三、Redis 主从复制

3.1为什么需要主从复制

单节点 Redis 有两个痛点:单点故障 (挂了就全完)和读压力集中。主从复制让一个 Master 把数据同步给多个 Slave:

  • 读写分离:Master 负责写,Slave 负责读,分摊压力;
  • 数据冗余:Slave 是 Master 的备份;
  • 复制方式:首次是全量复制(RDB 快照),之后是增量复制(命令流)。

注意:默认 Slave 是只读的,不能在从节点上写数据。

3.2 实验:搭建一主两从

① 配置主节点(node1)

bash 复制代码
[root@redis-node1 ~]# vim /etc/redis/redis.conf
#bind 127.0.0.1 -::1
bind * -::*
protected-mode no
[root@redis-node1 ~]# systemctl restart redis_6379.service

② 配置两个从节点(node2、node3)

bash 复制代码
# 在 redis-node2 节点
[root@redis-node2 ~]# vim /etc/redis/redis.conf
#bind 127.0.0.1 -::1
bind * -::*
protected-mode no
replicaof 172.25.254.10 6379      # 指向主节点 IP + 端口
[root@redis-node2 ~]# systemctl restart redis_6379.service

# 在 redis-node3 节点
[root@redis-node3 ~]# vim /etc/redis/redis.conf
#bind 127.0.0.1 -::1
bind * -::*
protected-mode no
replicaof 172.25.254.10 6379
[root@redis-node3 ~]# systemctl restart redis_6379.service

3.3 验证复制状态

主节点查看(node1)

bash 复制代码
[root@redis-node1 ~]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.25.254.20,port=6379,state=online,offset=391,lag=0
slave1:ip=172.25.254.30,port=6379,state=online,offset=391,lag=1
master_replid:e5f5cddc017ab0d5223213592d0482b832d3af77
master_repl_offset:391

看到 role:masterconnected_slaves:2,两个 slave 都是 online,说明主从建立成功。

从节点查看(node2)

bash 复制代码
[root@redis-node2 ~]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:172.25.254.10
master_port:6379
master_link_status:up        # 与主节点连接正常
slave_read_only:1            # 从节点只读

3.4 测试数据同步 & 从节点只读

在主节点写数据,从节点立刻能读到:

bash 复制代码
# 主节点 node1 写入
[root@redis-node1 ~]# redis-cli
127.0.0.1:6379> set name lee
OK
127.0.0.1:6379> get name
"lee"

# 从节点 node2 / node3 读取
[root@redis-node2 ~]# redis-cli
127.0.0.1:6379> get name
"lee"

尝试在从节点写入,会被拒绝:

bash 复制代码
[root@redis-node3 ~]# redis-cli
127.0.0.1:6379> get name
"lee"
127.0.0.1:6379> set test 123
(error) READONLY You can't write against a read only replica.

✅ 主从复制 + 读写分离验证通过。


四、Redis 哨兵模式 Sentinel

4.1主从的短板靠哨兵补

主从复制解决了"读压力"和"数据备份",但 Master 挂了没人自动顶上 。哨兵(Sentinel)就是来干这活的------一组哨兵进程专门盯着 Master,发现它真挂了,自动把一个 Slave 提升为新 Master,并让其他节点改认新主。

几个关键概念:

  • 监控(Monitoring):哨兵持续 ping 主从节点;
  • 主观下线(sdown):某个哨兵自己觉得节点连不上了;
  • 客观下线(odown) :达到 quorum 个哨兵都认为下线,才确认真挂了;
  • 故障转移(failover):选举领头哨兵 → 选一个 Slave 提升 → 通知其余节点;
  • quorum :认定主节点下线的票数(实验中设为 2,即至少 2 个哨兵同意)。

4.2 实验:搭建哨兵

① 主节点复制并编辑哨兵配置

bash 复制代码
[root@redis-node1 ~]# cd redis-7.4.8/
[root@redis-node1 redis-7.4.8]# cp -p sentinel.conf /etc/redis/
[root@redis-node1 ~]# vim /etc/redis/sentinel.conf
protected-mode no                            # 关闭保护模式
port 26379                                   # 哨兵监听端口
daemonize no                                 # 前台运行(方便看日志)
pidfile /var/run/redis-sentinel.pid
loglevel notice
sentinel monitor mymaster 172.25.254.10 6379 2   # 监控 mymaster,quorum=2
sentinel down-after-milliseconds mymaster 10000  # 10 秒连不上视为下线
sentinel parallel-syncs mymaster 1           # 故障转移后同时同步新主的 slave 数
sentinel failover-timeout mymaster 180000    # 故障切换超时 3 分钟

⚠️ 原参考文档此处写的是 172.25.254.100,应为实际 master 的 172.25.254.10,本文已修正,否则哨兵会监控一个不存在的地址。

② 从节点也关闭保护模式

bash 复制代码
[root@redis-node2 ~]# vim /etc/redis/redis.conf
protected-mode no
[root@redis-node2 ~]# systemctl restart redis_6379.service

[root@redis-node3 ~]# vim /etc/redis/redis.conf
protected-mode no
[root@redis-node3 ~]# systemctl restart redis_6379.service

③ 把哨兵配置发给两个从节点,三台一起启动

bash 复制代码
[root@redis-node1 ~]# scp /etc/redis/sentinel.conf root@172.25.254.20:/etc/redis/
[root@redis-node1 ~]# scp /etc/redis/sentinel.conf root@172.25.254.30:/etc/redis/

# 三台节点都执行:
[root@redis-node1 ~]# redis-sentinel /etc/redis/sentinel.conf

启动后日志里能看到哨兵发现了 master 和两个 slave,以及彼此:

bash 复制代码
# +monitor master mymaster 172.25.254.10 6379 quorum 2
* +slave slave 172.25.254.20:6379 ... @ mymaster 172.25.254.10 6379
* +slave slave 172.25.254.30:6379 ... @ mymaster 172.25.254.10 6379
* +sentinel sentinel 28f2f3da... 172.25.254.20 26379 @ mymaster ...
* +sentinel sentinel 89568283... 172.25.254.30 26379 @ mymaster ...

4.3 实验:测试故障切换

① 干掉主节点

bash 复制代码
[root@redis-node1 ~]# redis-cli
127.0.0.1:6379> SHUTDOWN
not connected>

② 观察哨兵日志(故障转移过程)

bash 复制代码
# +sdown master mymaster 172.25.254.10 6379          # 主观下线
# +odown master mymaster 172.25.254.10 6379 #quorum 2/2   # 客观下线
# +try-failover master mymaster ...
# +vote-for-leader d0780e7f... 1                      # 投票选领头哨兵
# +selected-slave slave 172.25.254.20:6379 ...        # 选中 .20 提升
# +promoted-slave slave 172.25.254.20:6379 ...        # 提升为 master
# +failover-end master mymaster 172.25.254.10 6379
# +switch-master mymaster 172.25.254.10 6379 172.25.254.20 6379  # 主切换到 .20

③ 在 node3 上确认已认新主

bash 复制代码
[root@redis-node3 ~]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:172.25.254.20      # 已经指向新主 .20
master_port:6379
master_link_status:up

④ 恢复原主节点(node1)

bash 复制代码
[root@redis-node1 ~]# /etc/init.d/redis_6379 start

原主重启后变成新主的从节点,在 node2 上能看到:

bash 复制代码
[root@redis-node2 ~]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.25.254.30,port=6379,state=online,...
slave1:ip=172.25.254.10,port=6379,state=online,...   # 原主 .10 已成为从

✅ 哨兵自动故障转移验证通过。


五、Redis Cluster 集群

5.1 理论:集群解决了什么

哨兵解决了"主挂了自动切换",但它只有一个 Master 写 ,写能力和存储容量都有上限。Redis Cluster 是分布式方案

  • 数据分片 :把数据按 slot = CRC16(key) % 16384 分到 16384 个哈希槽,槽平均分配到多个 Master;
  • 无中心化 :客户端连任意节点,节点算槽后命中自己就处理,否则返回 MOVED 重定向;
  • 内置高可用 :每个 Master 配 Slave,Master 宕机其 Slave 自动接管槽,不需要哨兵
  • 在线扩缩容:槽可以在节点间迁移,集群不中断。

5.2 实验环境

6 台机器:172.25.254.10 ~ 60,其中 .10/.20/.30 为 Master,.40/.50/.60 为对应 Slave。

5.3 配置集群节点

6 台节点都执行以下配置(先设主从认证、开启 cluster):

bash 复制代码
[root@redis-node1 ~]# vim /etc/redis/6379.conf
masterauth "123456"                  # 集群主从认证密码
cluster-enabled yes                  # 开启 cluster 功能
cluster-config-file nodes-6379.conf # 集群配置文件
cluster-node-timeout 15000           # 节点超时(ms)

[root@redis-node1 ~]# /etc/init.d/redis_6379 stop
[root@redis-node1 ~]# /etc/init.d/redis_6379 start

# 首次搭建先清掉旧数据(已有数据时必须)
[root@redis-node1 ~]# redis-cli
127.0.0.1:6379> flushall
127.0.0.1:6379> CLUSTER RESET HARD

5.4 创建集群

一条命令拉起 3 主 3 从(--cluster-replicas 1 表示每个 Master 配 1 个 Slave):

bash 复制代码
[root@redis-node1 ~]# redis-cli --cluster create \
  172.25.254.10:6379 172.25.254.20:6379 172.25.254.30:6379 \
  172.25.254.40:6379 172.25.254.50:6379 172.25.254.60:6379 \
  --cluster-replicas 1

输出关键片段(自动分配槽位和主从):

复制代码
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.25.254.50:6379 to 172.25.254.10:6379
Adding replica 172.25.254.60:6379 to 172.25.254.20:6379
Adding replica 172.25.254.40:6379 to 172.25.254.30:6379
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
[OK] All nodes agree about slots configuration.

5.5 验证集群状态

bash 复制代码
# 集群信息总览
[root@redis-node1 ~]# redis-cli --cluster info 172.25.254.10:6379
172.25.254.10:6379 -> 0 keys | 5461 slots | 1 slaves.
172.25.254.30:6379 -> 0 keys | 5461 slots | 1 slaves.
172.25.254.20:6379 -> 0 keys | 5462 slots | 1 slaves.
[OK] 0 keys in 3 masters.

# 集群自身状态
[root@redis-node1 ~]# redis-cli cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_known_nodes:6
cluster_size:3

# 健康检查
[root@redis-node1 ~]# redis-cli --cluster check 172.25.254.10:6379
[OK] All 16384 slots covered.

cluster_state:okAll 16384 slots covered 说明集群健康。拓扑如下:

5.6集群扩容(加一主一从)

业务增长要加机器,集群支持在线扩容

① 加入新主节点 .70

bash 复制代码
[root@redis-node1 ~]# redis-cli --cluster add-node 172.25.254.70:6379 172.25.254.10:6379
[root@redis-node1 ~]# redis-cli --cluster check 172.25.254.10:6379
172.25.254.70:6379 -> 0 keys | 0 slots | 0 slaves.   # 新主还没槽

② 迁移槽给新主(reshard 4096 个)

bash 复制代码
[root@redis-node1 ~]# redis-cli --cluster reshard 172.25.254.10:6379
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? dfabfe07170ac9b5d20a5a7a70c836877bd64504   # .70 的 ID
Please enter all the source node IDs.
Source node #1: all     # 从所有现有 master 取槽
Source node #2: done
Ready to move 4096 slots.

迁移后 .70 分到 4096 个槽(从三个老 master 各取一部分):

复制代码
M: dfabfe07170ac9b5d20a5a7a70c836877bd64504 172.25.254.70:6379
   slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master

③ 给新主挂从节点 .80

bash 复制代码
[root@redis-node1 ~]# redis-cli --cluster add-node 172.25.254.80:6379 172.25.254.10:6379 \
  --cluster-slave --cluster-master-id dfabfe07170ac9b5d20a5a7a70c836877bd64504

扩容后变成 4 主 4 从,槽自动均摊到每主 4096 个。

5.7集群缩容(删一主一从)

① 把 .70 的槽迁回 .10

bash 复制代码
[root@redis-node1 ~]# redis-cli --cluster reshard 172.25.254.10:6379
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? 8db833f3c3bc6b8f93e87111f13f56d366f833a0   # .10 的 ID
Source node #1: dfabfe07170ac9b5d20a5a7a70c836877bd64504   # .70 的 ID
Source node #2: done

② 删除节点(先删从 .80,再删主 .70)

bash 复制代码
[root@redis-node1 ~]# redis-cli --cluster del-node 172.25.254.10:6379 1176ee294e6b5071ca57e93374d04ac22028daed
>>> Sending CLUSTER FORGET messages to the cluster...
[root@redis-node1 ~]# redis-cli --cluster del-node 172.25.254.10:6379 dfabfe07170ac9b5d20a5a7a70c836877bd64504

[root@redis-node1 ~]# redis-cli --cluster check 172.25.254.10:6379
[OK] All 16384 slots covered.

缩容完成,恢复为 3 主 3 从。⚠️ 删除主节点前必须先把它的槽全部迁走,否则会丢数据。


六、三种高可用方案对比小结

方案 写能力 存储上限 自动故障转移 是否需要哨兵 适用场景
主从复制 单 Master 单节点 ❌ 手动 读多写少、要备份
哨兵 Sentinel 单 Master 单节点 ✅ 自动 高可用、写量不大
Cluster 集群 多 Master 横向扩展 ✅ 自动 否(内置) 大数据量、高并发写

七、总结

  • Redis 是什么:基于内存的 KV 数据库,快、支持持久化、数据类型丰富;
  • 主从复制:一主多从做读写分离和数据备份,但 Master 挂了要人手动顶;
  • 哨兵模式:哨兵自动监控 + 故障转移,解决主从的"单点"问题,但仍只有一个 Master 写;
  • Cluster 集群:数据分 16384 槽、多 Master 分片,既能横向扩容又能自动故障转移,是大规模场景的终极方案;
  • 持久化:RDB + AOF 都开,重启优先 AOF,RDB 做备份。
相关推荐
大模型码小白1 小时前
Spring AI Tool 实现自然语言操作 MySQL 数据库详解
服务器·开发语言·数据库·人工智能·python·mysql·spring
DBA大董3 小时前
TDengine3.0 DBA常用的运维命令和SQL2
运维·数据库·时序数据库·dba·tdengine
ManageEngineITSM4 小时前
什么是CMDB?配置管理数据库的定义、作用与建设方法一文讲清
大数据·数据库·人工智能·资产管理·变更管理
IvorySQL4 小时前
PostgreSQL 日报|PG19 外键快速路径隐患已修复(8 月 23 日)
数据库·postgresql
Elastic 中国社区官方博客4 小时前
OpenTelemetry Java 扩展:无需分叉 agent 即可自定义追踪
java·大数据·运维·开发语言·数据库·人工智能·elasticsearch
只爱喝胡辣汤4 小时前
Redis Intset(整数集合)技术文档
redis
01传说5 小时前
redis开机自启脚本
数据库·redis·缓存
这个DBA有点耶5 小时前
数据库运维的“自动驾驶”:KES-Operator如何把DBA经验编码为软件
数据库·dba·自动化运维