Redis(Remote Dictionary Server)是一种非关系型数据库(NoSQL),以 Key-Value 模型为核心,所有数据常驻内存、单线程处理命令,因此具备极低的读写延迟与极高的并发吞吐。
它的 Key 恒为字符串类型,而 Value 则支持五种基础数据结构:String、Hash、List、Set、ZSet(Sorted Set)。正是这五种结构,让 Redis 从"一个缓存工具"演进为"一个通用内存计算引擎"。
文章目录
-
- 一、五大数据类型总览
- 二、String(字符串)
-
- [1. 命令速查](#1. 命令速查)
- [2. 创建与读取 Key](#2. 创建与读取 Key)
- [3. 读取 Key 的值](#3. 读取 Key 的值)
- [4. 删除 Key](#4. 删除 Key)
- [5. 批量设置与批量获取](#5. 批量设置与批量获取)
- [6. 追加、覆盖返回旧值、取长度](#6. 追加、覆盖返回旧值、取长度)
- [7. 过期时间:TTL / EXPIRE / PERSIST](#7. 过期时间:TTL / EXPIRE / PERSIST)
- [8. 原子计数器:INCR / DECR 家族](#8. 原子计数器:INCR / DECR 家族)
- 三、List(列表)
-
- [1. 命令速查](#1. 命令速查)
- [2. 插入语义](#2. 插入语义)
- [3. 查询与修改](#3. 查询与修改)
- [4. 删除](#4. 删除)
- 四、Set(集合)
-
- [1. 命令速查](#1. 命令速查)
- [2. 增删查](#2. 增删查)
- [3. 集合间运算](#3. 集合间运算)
- 五、ZSet(有序集合)
-
- [1. 命令速查](#1. 命令速查)
- [2. 创建与批量写入](#2. 创建与批量写入)
- [3. 排名、分数与删除](#3. 排名、分数与删除)
- 六、Hash(哈希)
-
- [1. 命令速查](#1. 命令速查)
- [2. 完整操作示例](#2. 完整操作示例)
- 七、消息队列
-
- [1. 生产者 / 消费者模式(Producer / Consumer)](#1. 生产者 / 消费者模式(Producer / Consumer))
- [2. 发布者 / 订阅者模式(Publisher / Subscriber)](#2. 发布者 / 订阅者模式(Publisher / Subscriber))
- [八、接入 Redis 的三种方式](#八、接入 Redis 的三种方式)
-
- [1. Shell 脚本访问 Redis](#1. Shell 脚本访问 Redis)
- [2. 程序连接 Redis](#2. 程序连接 Redis)
- 九、高可用演进路线
-
- [1. 主从复制(Master / Slave Replication)](#1. 主从复制(Master / Slave Replication))
- [2. 哨兵模式(Sentinel)](#2. 哨兵模式(Sentinel))
- [3. Redis Cluster(3 主 3 从)](#3. Redis Cluster(3 主 3 从))
-
- 核心概念
- 工作原理
- 使用场景
- [3 主 3 从实战](#3 主 3 从实战)
- 模拟故障:主节点宕机后会发生什么
- [十、容器化部署 Redis](#十、容器化部署 Redis)
- 十一、三种架构选型对比
- 总结
一、五大数据类型总览
| 类型 | 名称 | 核心特征 | 典型场景 |
|---|---|---|---|
| String | 字符串 | 最基本的存储单元,可存字符串、整数、浮点数 | 缓存、计数器、分布式锁 |
| Hash | 哈希 | 字段与值的映射集合,一个 Key 可挂多个 Field | 对象存储(用户信息、商品详情) |
| List | 列表 | 按插入顺序排序的字符串数组,两端可操作 | 消息队列、时间线、最新列表 |
| Set | 集合 | 无序且元素唯一,支持集合间逻辑运算 | 去重、共同好友、标签系统 |
| ZSet | 有序集合 | 每个成员关联一个 score,按分数排序 | 排行榜、延时队列、带权去重 |

二、String(字符串)
字符串是最基础的 Redis 值类型,也是使用频率最高的类型。
关键特性:
- 二进制安全:一个 Redis 字符串可以承载任意类型的数据,一张 JPEG 图片、一个序列化后的对象都可以直接存入;
- 容量上限 :单个 String 类型的 Value 最大可存储 512 MB;
- Key 恒为字符串 :Redis 中所有的 Key 都是字符串类型,且严格区分大小写。
1. 命令速查
| 命令 | 说明 |
|---|---|
| `SET key value [EX seconds] [PX milliseconds] [NX | XX]` |
GET key |
获取 key 的值 |
SETEX key seconds value |
设置值并指定过期时间(秒) |
SETNX key value |
仅当 key 不存在时设置(分布式锁基础) |
INCR key |
将 key 中的数字加 1 |
INCRBY key increment |
将 key 中的数字增加指定值 |
DECR / DECRBY |
减操作 |
MSET key1 value1 [key2 value2 ...] |
批量设置 |
MGET key1 [key2 ...] |
批量获取 |
2. 创建与读取 Key
SET 用于创建一个 Key 并赋值,语法如下(时间复杂度 O(1)):
bash
SET key value [EX seconds] [PX milliseconds] [NX|XX]
- 若 Key 已持有其他值,
SET会无条件覆写旧值,无视其类型; - 对一个带 TTL 的 Key 执行
SET后,原有的过期时间将被清除; - 自 Redis 2.6.12 起,可通过参数改变行为:
EX seconds:设置过期秒数,等价于SETEX key seconds value;PX milliseconds:设置过期毫秒数,等价于PSETEX key milliseconds value;NX:只在键不存在时才写入,等价于SETNX;XX:只在键已存在时才更新。
bash
# 不论 key 是否存在,都执行设置
127.0.0.1:6379> SET key1 value1
OK
127.0.0.1:6379> GET key1
"value1"
127.0.0.1:6379> TYPE key1
string
# EX:设置 3 秒后自动过期
127.0.0.1:6379> SET title ceo EX 3
OK
127.0.0.1:6379> GET title # 3 秒后再次查询
(nil)
# Key 严格区分大小写
127.0.0.1:6379> SET name wang
OK
127.0.0.1:6379> SET NAME li
OK
127.0.0.1:6379> GET name
"wang"
127.0.0.1:6379> GET NAME
"li"
# SETNX:仅当 Key 不存在时才赋值
127.0.0.1:6379> SETNX title coo
(integer) 1
127.0.0.1:6379> GET title
"coo"
127.0.0.1:6379> SETNX title ceo # title 已存在,写入被拒绝
(integer) 0
127.0.0.1:6379> GET title
"coo"
# XX:仅当 Key 已存在时才更新
127.0.0.1:6379> SET title ceo XX
OK
127.0.0.1:6379> GET title
"ceo"
3. 读取 Key 的值
GET 一次只能查看一个 Key 的值:
bash
127.0.0.1:6379> GET key1
"value1"
127.0.0.1:6379> GET name age
(error) ERR wrong number of arguments for 'get' command
4. 删除 Key
bash
127.0.0.1:6379> DEL key1
(integer) 1
127.0.0.1:6379> DEL key1 key2 # 返回成功删除的数量
(integer) 0
5. 批量设置与批量获取
bash
127.0.0.1:6379> MSET key1 value1 key2 value2
OK
127.0.0.1:6379> MGET key1 key2
1) "value1"
2) "value2"
127.0.0.1:6379> KEYS n*
1) "name"
127.0.0.1:6379> KEYS *
1) "name"
2) "key1"
3) "NAME"
4) "title"
5) "key2"
MSET/MGET以单次往返完成多键操作,是降低网络开销最直接的手段;KEYS会全量扫描键空间,生产环境应改用SCAN。
6. 追加、覆盖返回旧值、取长度
bash
# APPEND:向已有值尾部追加字符串,返回追加后的字节长度
127.0.0.1:6379> APPEND key1 " append new value"
(integer) 22
127.0.0.1:6379> GET key1
"value1 append new value"
# GETSET:设置新值并返回旧值(原子操作)
127.0.0.1:6379> SET name wang
OK
127.0.0.1:6379> GETSET name xiyangyang
"wang"
127.0.0.1:6379> GET name
"xiyangyang"
# STRLEN:返回 Value 的字节数(注意是字节,不是字符)
127.0.0.1:6379> SET name wang
OK
127.0.0.1:6379> STRLEN name
(integer) 4
127.0.0.1:6379> APPEND name " teng"
(integer) 9
127.0.0.1:6379> GET name
"wang teng"
127.0.0.1:6379> STRLEN name
(integer) 9
7. 过期时间:TTL / EXPIRE / PERSIST
TTL key 查看 Key 的剩余生存时间,Key 到期后会被自动删除。返回值语义固定为三种:
| 返回值 | 含义 |
|---|---|
-1 |
Key 存在但永不过期(新建 Key 的默认状态;重新赋值也会重置为永不过期) |
-2 |
Key 不存在(含已过期被回收) |
n |
Key 剩余的有效秒数 |
bash
# 重置过期时长
127.0.0.1:6379> TTL name
(integer) 97
127.0.0.1:6379> EXPIRE name 1000
(integer) 1
127.0.0.1:6379> TTL name
(integer) 996
# 取消过期设置,恢复为永不过期
127.0.0.1:6379> TTL name
(integer) 957
127.0.0.1:6379> PERSIST name
(integer) 1
127.0.0.1:6379> TTL name
(integer) -1
8. 原子计数器:INCR / DECR 家族
利用 INCR、DECR、INCRBY、DECRBY,可以把字符串当作原子计数器使用------这是 Redis 单线程命令执行模型带来的天然保证。
bash
# INCR:自增 1
127.0.0.1:6379> SET num 10
OK
127.0.0.1:6379> INCR num
(integer) 11
127.0.0.1:6379> GET num
"11"
127.0.0.1:6379> INCR num
(integer) 12
127.0.0.1:6379> GET num
"12"
# DECR:自减 1
127.0.0.1:6379> SET num 10
OK
127.0.0.1:6379> DECR num
(integer) 9
127.0.0.1:6379> GET num
"9"
INCRBY key increment 将 Key 对应的数字加上指定增量(可为负数):
- Key 不存在时,操作前会被隐式置为
0; - Value 类型错误或非数字字符串时返回错误;
- 最大支持 64 位有符号整数。
bash
127.0.0.1:6379> SET mykey 10
OK
127.0.0.1:6379> INCRBY mykey 5
(integer) 15
127.0.0.1:6379> GET mykey
"15"
127.0.0.1:6379> INCRBY mykey -10 # 增量可为负
(integer) 5
127.0.0.1:6379> GET mykey
"5"
127.0.0.1:6379> INCRBY nokey1 5 # Key 不存在,按 0 起算
(integer) 5
127.0.0.1:6379> GET nokey1
"5"
# DECRBY:同样支持负数(即反向增加)
127.0.0.1:6379> SET mykey 10
OK
127.0.0.1:6379> DECRBY mykey 8
(integer) 2
127.0.0.1:6379> DECRBY mykey -20
(integer) 22
127.0.0.1:6379> GET mykey
"22"
127.0.0.1:6379> DECRBY nokey2 3 # Key 不存在,结果为 -3
(integer) -3
127.0.0.1:6379> GET nokey2
"-3"
三、List(列表)
Redis 的 List 本质上是一个按插入顺序排序的字符串数组。
关键特性:
- 支持双向读写,可从头部(左)或尾部(右)插入与弹出;
- 单个列表最多容纳
2^32 - 1 = 4294967295个元素; - 元素通过下标定位:
0为首个元素,1为第二个,以此类推;也支持负数下标 ,-1表示最后一个元素,-2表示倒数第二个; - 元素可重复 ,常用于日志、任务队列等场景。


1. 命令速查
| 命令 | 说明 |
|---|---|
LPUSH key value [value ...] |
从左边(表头)插入元素 |
RPUSH key value [value ...] |
从右边(表尾)插入元素 |
LPOP key |
弹出左边第一个元素 |
RPOP key |
弹出右边第一个元素 |
LRANGE key start stop |
获取指定范围的元素(支持负数索引) |
LLEN key |
获取列表长度 |
LINDEX key index |
获取指定索引的元素 |
LSET key index value |
修改指定索引的元素 |
LREM key count value |
删除 count 个等于 value 的元素 |
2. 插入语义
bash
LPUSH key value [value ...] # 时间复杂度 O(1),插入表头
RPUSH key value [value ...] # 时间复杂度 O(1),插入表尾
多个 value 会按从左到右的顺序依次插入:
- 对空列表执行
LPUSH mylist a b c,结果为c b a,等价于原子性地依次执行LPUSH mylist a、LPUSH mylist b、LPUSH mylist c; - 对空列表执行
RPUSH mylist a b c,结果为a b c。
Key 不存在时会自动创建空列表;Key 存在但不是列表类型时返回错误。
bash
# 从左边添加,已有元素整体右移
127.0.0.1:6379> LPUSH phone xiaomi apple huawei
(integer) 3
127.0.0.1:6379> TYPE phone
list
# 从右边添加,已有元素整体左移
127.0.0.1:6379> RPUSH id 18 19 20
(integer) 3
127.0.0.1:6379> TYPE id
list
# 追加新元素
127.0.0.1:6379> LPUSH list1 tom
(integer) 1
127.0.0.1:6379> RPUSH list1 jack
(integer) 2
# 获取列表长度
127.0.0.1:6379> LLEN list1
(integer) 2

3. 查询与修改
bash
# LRANGE 取全量:0 到 -1
127.0.0.1:6379> RPUSH list4 a b c d e f
(integer) 6
127.0.0.1:6379> LRANGE list4 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
# LSET 按下标修改
127.0.0.1:6379> LSET list4 2 cloud
OK
127.0.0.1:6379> LRANGE list4 0 -1
1) "a"
2) "b"
3) "cloud"
4) "d"
5) "e"
6) "f"
4. 删除
bash
127.0.0.1:6379> DEL list1
(integer) 1
127.0.0.1:6379> EXISTS list1
(integer) 0
四、Set(集合)
Set 是一个无序的字符串集合 ,同一集合内每个元素唯一、不可重复。它的独特之处在于支持集合间的逻辑运算------交集、并集、差集,因此天然适配"共同好友""标签圈选""去重统计"这类场景。
1. 命令速查
| 命令 | 说明 |
|---|---|
SADD key member [member ...] |
添加一个或多个成员 |
SMEMBERS key |
获取集合所有成员 |
SISMEMBER key member |
判断成员是否在集合中 |
SREM key member [member ...] |
删除一个或多个成员 |
SCARD key |
获取集合成员数量 |
SINTER key1 [key2 ...] |
求交集 |
SUNION key1 [key2 ...] |
求并集 |
SDIFF key1 [key2 ...] |
求差集 |

2. 增删查
bash
# 追加:已存在的元素无法重复添加
127.0.0.1:6379> SADD set1 v2 v3 v4
(integer) 3
127.0.0.1:6379> SADD set1 v2 # 已存在,返回 0
(integer) 0
# 获取集合全部成员(顺序不保证)
127.0.0.1:6379> SMEMBERS set1
1) "v4"
2) "v3"
3) "v1"
4) "v2"
127.0.0.1:6379> SMEMBERS set2
1) "v4"
2) "v2"
# 删除指定元素
127.0.0.1:6379> SADD name1 xiyangyang meiyangyang feiyangyang
(integer) 3
127.0.0.1:6379> SMEMBERS name1
1) "feiyangyang"
2) "meiyangyang"
3) "xiyangyang"
127.0.0.1:6379> SREM name1 meiyangyang
(integer) 1
127.0.0.1:6379> SMEMBERS name1
1) "feiyangyang"
2) "xiyangyang"
3. 集合间运算
bash
# 交集:同时属于 A 和 B 的元素(如 QQ 共同好友)
127.0.0.1:6379> SINTER set1 set2
1) "v4"
2) "v2"
# 并集:属于 A 或属于 B 的元素
127.0.0.1:6379> SUNION set1 set2
1) "v3"
2) "v1"
3) "v2"
4) "v4"
# 差集:属于 A 但不属于 B 的元素(如"我朋友的朋友")
127.0.0.1:6379> SDIFF set1 set2
1) "v3"
2) "v1"
五、ZSet(有序集合)
ZSet 与 Set 一样不允许成员重复,差别在于:每个成员都关联一个双精度浮点型分数(score),Redis 依据分数把所有成员从低到高排序。
关键特性:
- 有序:按 score 升序排列;
- 成员唯一 :value 不可重复,但 score 可以重复;
- 单个有序集合最多容纳
2^32 - 1 = 4294967295个成员; - 每个元素由
score + value两部分构成; - 最经典的应用场景是排行榜。
1. 命令速查
| 命令 | 说明 |
|---|---|
ZADD key score member [score member ...] |
添加带分数的成员 |
ZRANGE key start stop [WITHSCORES] |
按分数升序返回成员 |
ZREVRANGE key start stop [WITHSCORES] |
按分数降序返回成员 |
ZREM key member [member ...] |
删除成员 |
ZCARD key |
获取成员数量 |
ZSCORE key member |
获取成员的分数 |
ZRANK key member |
获取成员的排名(升序) |
2. 创建与批量写入
bash
127.0.0.1:6379> ZADD zset1 1 v1 # 分数为 1
(integer) 1
127.0.0.1:6379> ZADD zset1 2 v2
(integer) 1
127.0.0.1:6379> ZADD zset1 2 v3 # 分数可重复,元素值不可重复
(integer) 1
127.0.0.1:6379> ZADD zset1 3 v4
(integer) 1
127.0.0.1:6379> TYPE zset1
zset
# 一次性写入多个成员
127.0.0.1:6379> ZADD zset2 1 v1 2 v2 3 v3 4 v4 5 v5
(integer) 5
3. 排名、分数与删除
bash
# 查看成员个数
127.0.0.1:6379> ZCARD course
(integer) 4
127.0.0.1:6379> ZCARD zset1
(integer) 4
127.0.0.1:6379> ZCARD zset2
(integer) 5
# 查询指定成员的排名(从 0 开始,按分数升序)
127.0.0.1:6379> ZRANK course go
(integer) 3
127.0.0.1:6379> ZRANK course python
(integer) 1
# 获取成员的分数
127.0.0.1:6379> ZSCORE course cloud
"50"
# 按索引区间读取与删除
127.0.0.1:6379> ZRANGE course 0 -1
1) "cloud"
2) "python"
3) "linux"
4) "go"
127.0.0.1:6379> ZREM course python go
(integer) 2
127.0.0.1:6379> ZRANGE course 0 -1
1) "cloud"
2) "linux"
六、Hash(哈希)
Hash 即字典,用于保存字符串字段(field)与字符串值(value)之间的映射,本质上是一个 Key 之下再挂一组 K/V 的二级结构。它特别适合存储对象,单个 Hash 最多可包含 2^32 - 1 个键值对。
特点: 无序、以 K/V 对组织、适合存放彼此相关的一组数据。


1. 命令速查
| 命令 | 说明 |
|---|---|
HSET key field value |
设置 hash 字段的值 |
HGET key field |
获取 hash 字段的值 |
HMSET key field1 value1 [field2 value2 ...] |
批量设置(Redis 4.0+ 推荐直接用 HSET) |
HMGET key field1 [field2 ...] |
批量获取字段 |
HGETALL key |
获取所有字段和值 |
HKEYS key |
获取所有字段名 |
HVALS key |
获取所有字段值 |
HDEL key field [field ...] |
删除一个或多个字段 |
HEXISTS key field |
判断字段是否存在 |
2. 完整操作示例
bash
# 创建 Hash(Key 不存在时自动创建;field 已存在则旧值被覆盖)
127.0.0.1:6379> HSET 9527 name zhouxingxing age 20
(integer) 2
127.0.0.1:6379> TYPE 9527
hash
# 查看所有字段与值
127.0.0.1:6379> HGETALL 9527
1) "name"
2) "zhouxingxing"
3) "age"
4) "20"
# 增加字段
127.0.0.1:6379> HSET 9527 gender male
(integer) 1
127.0.0.1:6379> HGETALL 9527
1) "name"
2) "zhouxingxing"
3) "age"
4) "20"
5) "gender"
6) "male"
# 读取指定字段 / 批量读取
127.0.0.1:6379> HGET 9527 name
"zhouxingxing"
127.0.0.1:6379> HGET 9527 age
"20"
127.0.0.1:6379> HMGET 9527 name age
1) "zhouxingxing"
2) "20"
# 删除指定字段
127.0.0.1:6379> HDEL 9527 age
(integer) 1
127.0.0.1:6379> HGET 9527 age
(nil)
127.0.0.1:6379> HGETALL 9527
1) "name"
2) "zhouxingxing"
3) "gender"
4) "male"
# 批量设置多个字段
127.0.0.1:6379> HMSET 9527 name zhouxingxing age 50 city hongkong
OK
127.0.0.1:6379> HGETALL 9527
1) "name"
2) "zhouxingxing"
3) "gender"
4) "male"
5) "age"
6) "50"
7) "city"
8) "hongkong"
# 分别取出所有 field 与所有 value
127.0.0.1:6379> HKEYS 9527
1) "name"
2) "gender"
3) "age"
4) "city"
127.0.0.1:6379> HVALS 9527
1) "zhouxingxing"
2) "male"
3) "50"
4) "hongkong"
# 删除整个 Hash
127.0.0.1:6379> DEL 9527
(integer) 1
127.0.0.1:6379> EXISTS 9527
(integer) 0
七、消息队列
消息队列 把要传输的数据放入队列中,从而实现应用之间的数据交换。它的三大价值是:解耦、异步、削峰限流 。常见的消息队列中间件有 Kafka、RabbitMQ、Redis。

消息队列分为两种模型:
1. 生产者 / 消费者模式(Producer / Consumer)
多个消费者同时监听同一个队列,但一条消息只能被抢到它的那一个消费者消费一次 。队列可以由多个生产者写入、由多个消费者取出处理,应用最为广泛。


在 Redis 中,能真正实现这套语义的数据类型只有 List 和 Streams(此外 Redis 还提供了发布/订阅 Pub/Sub 模式)。
用 List 实现消息队列: 将需要延后处理的任务序列化成字符串塞进 Redis 列表,另一个线程从列表中轮询取出处理。几个入队、出队命令就能组合出多种用法:
| 组合 | 语义 |
|---|---|
LPUSH + RPOP |
左进右出(FIFO) |
RPUSH + LPOP |
右进左出(FIFO) |
LPUSH + BRPOP |
左进右阻塞出 |
RPUSH + BLPOP |
右进左阻塞出 |

bash
# 生产消息
127.0.0.1:6379> LPUSH haizeiwang jishu1 jishu2 jishu3
(integer) 3
# 消费消息
127.0.0.1:6379> RPOP haizeiwang
"jishu3"
127.0.0.1:6379> RPOP haizeiwang
"jishu2"
127.0.0.1:6379> RPOP haizeiwang
"jishu1"
127.0.0.1:6379> RPOP haizeiwang
(nil)
# 验证队列消息已全部消费完成
127.0.0.1:6379> LRANGE haizeiwang 0 -1
(empty list or set)
及时消费问题: 若消费者想实时处理数据,就要在程序里写一个 while(true) 不断调用 RPOP / LPOP,这会带来不必要的 CPU 空转开销。
为此 Redis 提供了 BLPOP、BRPOP 这类阻塞式读取 命令(前缀 B 即 Blocking):客户端在没有读到队列数据时自动阻塞,直到有新数据写入才继续,从而省下无效轮询的开销。
2. 发布者 / 订阅者模式(Publisher / Subscriber)
发布者将消息发布到指定频道(channel),事先监听该频道的一个或多个订阅者都会收到同一条消息 。即"一消息多消费者",适用于社交应用中的群聊、群发、群公告等场景。

需注意:Pub/Sub 不持久化消息,离线订阅者会丢失期间的消息;若要求消息不丢,应使用 List + 阻塞弹出或 Streams。
八、接入 Redis 的三种方式
1. Shell 脚本访问 Redis
Redis 官方客户端 redis-cli 可直接嵌入 Shell 脚本,实现批量写入。
bash
# 为脚本添加执行权限
[root@localhost ~]# chmod +x write_redis.sh
# 运行脚本
[root@localhost ~]# ./write_redis.sh
OK
......
OK
已成功写入100条数据到 Redis。
# 验证结果
[root@localhost ~]# redis-cli
127.0.0.1:6379> INFO keyspace
# Keyspace
db0:keys=100,expires=0,avg_ttl=0
127.0.0.1:6379> KEYS key:*
可选增强:
bash
# 带密码认证(若 Redis 设置了 requirepass)
[root@localhost ~]# redis-cli -h 127.0.0.1 -p 6379 -a your_password
# 批量管道导入,性能远高于逐条写入
[root@localhost ~]# cat data.txt | redis-cli --pipe
-a会让密码出现在进程列表中,生产环境建议使用--askpass交互输入或通过配置文件指定。
2. 程序连接 Redis
Redis 支持多种开发语言的客户端,官方清单见:
以 Python 为例,选用 redis-py 库(使用手册:https://redis.io/docs/latest/develop/clients/redis-py/)。
bash
pip install redis
建立连接:
bash
import redis
r = redis.Redis(host='192.168.108.172', port=6379, password='123456', db=0)
print(r)
参数说明:
| 参数 | 含义 |
|---|---|
host |
Redis 服务器 IP 地址(此处为局域网地址) |
port |
Redis 默认端口 6379 |
password |
认证密码,说明服务端配置了 requirepass 123456 |
db |
使用的逻辑库编号,Redis 默认有 16 个库,编号 0~15 |
print(r) 打印的是客户端对象的内部描述,用于调试确认连接配置是否正确。
⚠️ 脚本文件名不要取作
redis.py,否则会与redis模块同名冲突,导致导入异常。
接收 set 的返回值:
bash
import redis
r = redis.Redis(host='192.168.108.172', port=6379, password='123456', db=0)
print(r)
# 接收 set 操作的返回值
result = r.set('color1', 'red')
print(result) # 输出 True(或 'OK',取决于 redis-py 版本)
r.set('color1', 'red') 向 Redis 写入一个字符串键值对(键 color1、值 red),等价于在 CLI 中执行 SET color1 red。
| redis-py 版本 | r.set() 成功时的返回值 |
|---|---|
| 4.0.0 及以上 | True(布尔值,当前主流版本) |
| 3.x 及更早 | b'OK'(字节串) |
自 redis-py 4.0 起,为贴合 Python 习惯,成功操作统一返回 True,失败则抛出异常(如连接错误、认证失败)。
存取值与字符串操作:
bash
# 存储与读取
r.set('color1', 'red')
value = r.get('color1')
print(value)
# 字符串数字操作:incr 自增、decr 自减、append 追加
r.set('int1', 10)
result = r.incr('int1')
result = r.decr('int1')
print(result)
列表操作:
bash
r.lpush('mylist', 'nihao')
r.lpush('mylist', 'laogao')
print(r.lrange('mylist', 0, -1))
逐行解读:
r.lpush('mylist', 'nihao'):用LPUSH把nihao从左侧(头部)推入mylist;Key 不存在时 Redis 会自动创建,结果为['nihao'];r.lpush('mylist', 'laogao'):再次左插,列表是"头进",新元素在前,结果变为['laogao', 'nihao'];r.lrange('mylist', 0, -1):取索引0到-1(即全部元素),-1表示最后一个元素、0表示第一个;- 返回的是字节串(bytes)组成的列表 ,因为 Redis 存储的是二进制安全字符串,输出形如
[b'laogao', b'nihao']。每个字符串前的b'...'表示 bytes 类型,而非普通str。
小知识:列表是"左进右出"还是"右进左出"?
LPUSH从左边插入 → 新元素在头部;RPUSH从右边插入 → 新元素在尾部;- 索引
0是最左边(最新LPUSH的元素),-1是最右边(最早插入的元素)。
哈希操作:
bash
r.hset('student', 'name', 'lisi')
r.hset('student', 'age', '18')
print(r.hget('student', 'name'))
print(r.hget('student', 'age'))
print(r.hgetall('student'))
r.hset('student', 'name', 'lisi'):在名为student的哈希中设置字段name的值为lisi,等价于HSET student name lisi;- 再设置
age为18。注意 Redis 中所有值都是字符串,即使看起来像数字,存储时也是字符串类型; r.hget(...)返回 bytes 类型(redis-py 默认返回字节),输出b'lisi'、b'18';r.hgetall(...)返回一个dict,但键和值都是 bytes 类型。
九、高可用演进路线
主从复制 → 加上自动故障转移 = 哨兵模式 → 再加上数据分片与写扩展 = Redis Cluster
1. 主从复制(Master / Slave Replication)
主从复制是 Redis 实现高可用、读写分离、数据冗余的核心机制,也是所有更高层架构的基础。它允许一个主节点(Master)将数据复制到一个或多个从节点(Slave / Replica)。
- 目的:数据冗余 + 读写分离
- 原理:主节点把数据变更同步给从节点,从节点保有与主节点一致的数据副本
五大特点:
| 特点 | 说明 |
|---|---|
| 一主多从 | 一个 Master 可以有多个 Slave |
| 从节点单主 | 一个 Slave 只能有一个 Master |
| 单向同步 | 数据流向只能由 Master → Slave |
| 主节点读写 | Master 可读可写 |
| 从节点只读 | Slave 只读 |
故障接管的前提: 当 Master 出现故障,可以自动将一个 Slave 提升为新的 Master,因此 Slave 需要设置与 Master 相同的连接密码;并且新 Master 需要通过持久化机制完成数据恢复。
主从同步工作原理(五步):
- Slave 向 Master 发送
sync命令; - Master 启动后台存盘进程,同时收集所有新的修改数据命令;
- Master 完成存盘后,将整个数据文件传送给 Slave;
- Slave 接收数据文件并加载到内存,完成首次完全同步;
- 后续有新数据产生时,Master 持续将新命令传递给 Slave 完成增量同步。
实验环境(1 主 2 从)
准备三台配置相同的虚拟机,并关闭防火墙:
| 主机名 | IP 地址 | 系统 |
|---|---|---|
| master | 192.168.108.10 | CentOS 7.9 |
| slave01 | 192.168.108.11 | CentOS 7.9 |
| slave02 | 192.168.108.12 | CentOS 7.9 |
配置所有节点
bash
# 所有节点执行
[root@localhost ~]# cd /usr/local/redis-6.2.14/
[root@localhost redis-6.2.14]# vim redis.conf
75 bind 0.0.0.0 -::1
配置从节点
bash
# slave01、slave02 指向 master 的 IP 和端口
[root@localhost redis-6.2.14]# vim redis.conf
480 replicaof 192.168.108.10 6379
# 不修改配置文件,通过命令动态指定也可以
127.0.0.1:6379> REPLICAOF MASTER_IP PORT # 新版推荐
127.0.0.1:6379> SLAVEOF MASTER_IP PORT # 旧版写法,将被淘汰
重启所有 Redis
bash
[root@localhost redis-6.2.14]# redis-cli shutdown
[root@localhost redis-6.2.14]# redis-server redis.conf &
验证同步状态
bash
[root@master ~]# redis-cli
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.108.12,port=6379,state=online,offset=280,lag=0
slave1:ip=192.168.108.11,port=6379,state=online,offset=280,lag=0
master_failover_state:no-failover
master_replid:9abdc709c2e13658f9fe30908d53b7fd2ddd8e29
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:280
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:280
bash
[root@slave01 ~]# redis-cli
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:192.168.108.10
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_read_repl_offset:280
slave_repl_offset:280
在主节点写入数据,验证是否被同步到从节点:
bash
# master 节点
127.0.0.1:6379> SET name laogao
OK
# slave01、slave02 查看,数据已同步过来
127.0.0.1:6379> GET name
"laogao"

解除主从关系
在从节点执行 REPLICAOF NO ONE 或 SLAVEOF NO ONE 即可取消主从复制。取消后会断开与 Master 的连接、不再存在复制关联,但不会清除 Slave 上已有的数据。
bash
# 新版
127.0.0.1:6379> REPLICAOF NO ONE
# 旧版
127.0.0.1:6379> SLAVEOF NO ONE
2. 哨兵模式(Sentinel)
Redis Sentinel 是官方提供的高可用(HA)解决方案 ,用于在主从架构之上实现自动故障检测与故障转移。
- 目的:在主从复制的基础上,实现自动故障转移
- 原理:哨兵是一个独立的分布式系统,由多个 Sentinel 实例(进程)组成,用于监控 Redis 主从节点的健康状态
✅ 哨兵本身不存储数据,只负责监控与协调。
四大主要功能:
| 功能 | 说明 |
|---|---|
| 监控 Monitoring | 持续检查 Master 与 Replica 是否正常运行 |
| 通知 Notification | 被监控实例异常时,通过 API 通知管理员或其他系统 |
| 自动故障转移 Automatic Failover | 主节点宕机时,自动将从节点提升为新主,并更新其他从节点的复制源 |
| 配置提供者 Configuration Provider | 客户端可通过 Sentinel 获取当前主节点地址,实现动态服务发现 |
架构组成:
- Master:主节点,处理写请求;
- Replica(Slave):从节点,复制主节点数据,可处理读请求;
- Sentinel 节点 :独立进程,通常部署奇数个(如 3 个)以避免脑裂。
故障转移流程(六步):
- 主观下线(SDOWN) :某个 Sentinel 发现主节点无响应(超过
down-after-milliseconds),将其标记为主观下线; - 客观下线(ODOWN) :达到
quorum配置值数量的 Sentinel 达成共识,确认主节点已宕机; - 选举 Leader:Sentinel 之间通过 Raft 算法选举出一个 Leader 负责执行故障转移;
- 提升新主 :Leader 选择一个"最优"从节点(优先级高、复制偏移量大、运行稳定)执行
REPLICAOF NO ONE,将其转为主节点; - 重配从节点:其他从节点重新指向新主节点;
- 通知客户端:通过发布/订阅机制通知客户端主节点已变更。
使用场景:
| 场景 | 说明 |
|---|---|
| 高可用缓存服务 | 主节点宕机时自动切换,保障业务连续性 |
| 避免人工干预 | 无需运维手动执行 REPLICAOF NO ONE |
| 读写分离 + 自动容灾 | 结合主从复制,实现读扩展与写高可用 |
| 中小规模集群 | 适用于不需要分片(Sharding)的场景,大规模应选 Redis Cluster |
⚠️ Sentinel 不解决数据分片问题,仅解决单主节点的高可用。
操作步骤
延续上面的实验,此时三台 Redis 处于一主二从状态,三台都要执行。
bash
[root@master redis-6.2.14]# cp sentinel.conf sentinel.conf.bak
[root@master redis-6.2.14]# vim sentinel.conf
# 主节点 IP、端口,以及哨兵投票数量 2
# 当有 2 个及以上哨兵认为主节点不可用时,即为客观下线,触发主从故障转移
84 sentinel monitor mymaster 192.168.108.10 6379 2
# 超过该时间主节点未响应哨兵,则哨兵将其主观下线,单位毫秒
125 sentinel down-after-milliseconds mymaster 30000
启动哨兵(三台都要做):
bash
[root@localhost redis-6.2.14]# redis-sentinel sentinel.conf &
[2] 9203
查看哨兵状态:
bash
[root@master redis-6.2.14]# redis-cli -p 26379
127.0.0.1:26379> INFO sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.108.10:6379,slaves=2,sentinels=3
验证故障转移: 模拟故障,将 master 关机,可以看到剩下的两台 slave 开始选举新的 master 主机。
bash
# 将 master 恢复,启动并放在后台运行
[root@master ~]# cd /usr/local/redis-6.2.14/
[root@master redis-6.2.14]# redis-server redis.conf &
[root@master redis-6.2.14]# redis-sentinel sentinel.conf &
原 master 回归后会自动以 slave 身份加入集群,跟随新主。
✅ 哨兵模式是 Redis 实现自动高可用的标准方案,适用于对可用性要求高、但无需数据分片的业务场景。超大规模集群应考虑 Redis Cluster。
3. Redis Cluster(3 主 3 从)
Redis Cluster 是 Redis 3.0+ 官方推出的分布式解决方案 ,核心是数据分片(Sharding)+ 主从复制 + 去中心化故障转移,用于解决单机 Redis 的容量、性能与单点故障瓶颈,实现水平扩展、高可用与高并发。
- 目的:同时解决高可用、海量数据存储、高并发读写,即分布式扩展
- 原理:通过数据分片进行存储,并通过多主多从架构实现高可用
核心概念
Redis Cluster 是无中心架构 的分布式系统,数据自动分散到多个节点,每个节点只存部分数据;节点间通过 Gossip 协议 通信,自带故障转移,无需 Sentinel。
关键角色:
| 角色 | 职责 |
|---|---|
| 主节点 Master | 处理读写、管理哈希槽、参与故障投票,是核心节点 |
| 从节点 Replica | 异步复制主节点数据,默认只读;主节点宕机时自动选举晋升 |
| 哈希槽 Hash Slot | 集群固定 16384 个槽(0~16383),是数据分片的最小单位 |
| 节点 ID | 每个节点的唯一标识,用于集群内识别与通信 |
五大核心特性:
- 数据分片:突破单机内存限制,总容量 = 所有主节点内存之和;
- 高可用:部分节点故障不影响整体,自动故障转移;
- 线性扩展:加节点即可提升容量与并发;
- 去中心化:无中心节点,避免单点瓶颈;
- 自动路由:客户端连接任意节点,自动重定向到目标节点。
工作原理
1. 数据分片(哈希槽机制)
- 槽位总数:
16384(2¹⁴) - 键 → 槽映射:
bash
HASH_SLOT = CRC16(key) mod 16384
- 槽位分配:每个主节点负责一段连续 槽位。例如 3 主集群:
0-5460、5461-10922、10923-16383。

2. 节点通信(Gossip 协议)
节点间通过集群总线 (独立端口,默认为服务端口 +10000)通信,消息类型包括:
PING / PONG:心跳检测、状态同步;FAIL:广播节点失效;UPDATE:槽位映射、集群拓扑更新。
3. 请求路由流程
- 客户端连接任意节点,发送命令;
- 节点计算 key 所属槽位;
- 槽位归属本节点 → 直接处理;否则 → 返回
MOVED重定向; - 智能客户端缓存槽位映射,减少重定向次数。
4. 故障转移(高可用)
- 故障检测 :某主节点超时无响应,多数主节点将其标记为
FAIL; - 从节点选举 :该主节点的从节点发起
FAILOVER请求; - 投票晋升:主节点投票通过,从节点升级为主并接管槽位;
- 拓扑更新:Gossip 同步新状态,集群恢复。
5. 数据一致性
- 异步复制:主从复制为异步,存在短暂数据不一致;
- 最终一致性 :故障转移后数据最终一致,不保证强一致;
- 写安全:多数主节点可达时,写操作尽量保留。
使用场景
适合:
- 海量数据存储(> 100 GB):电商商品库、用户画像、社交内容、IoT 设备数据------突破单机内存上限,分布式存储海量热数据;
- 高并发读写(QPS ≥ 5 万):秒杀、抢购、热点评论、实时排行榜------多主节点并行处理,并发能力线性提升。
不适合:
- 强事务、多键跨槽操作(如
MSET多个不同槽的 key); - 数据量小、低并发的场景(用哨兵 / 主从更简单);
- 需要强一致性的场景(需搭配分布式事务)。
3 主 3 从实战
架构: Cluster 自 Redis 3.0 起支持,是官方自带的集群方式。其原理采用分布式思想,数据会均分到所有主节点上;当数据量过大时服务器均摊压力,各主节点存放的都是分片数据 而非全量数据。这是目前生产环境采用较多的部署方式,至少需要 6 台节点:3 主 3 从。
| 系统 | IP 地址 | 主机名 | 角色 |
|---|---|---|---|
| CentOS 7.9 | 192.168.108.21 | redis1 | Master |
| CentOS 7.9 | 192.168.108.22 | redis2 | Master |
| CentOS 7.9 | 192.168.108.23 | redis3 | Master |
| CentOS 7.9 | 192.168.108.24 | redis4 | Slave |
| CentOS 7.9 | 192.168.108.25 | redis5 | Slave |
| CentOS 7.9 | 192.168.108.26 | redis6 | Slave |
准备 6 台已安装 Redis 的虚拟机,同时执行:关闭防火墙、修改配置文件。
bash
# 所有主机操作
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# cd /usr/local/redis-6.2.14/
[root@localhost redis-6.2.14]# vim redis.conf
# 监听地址
75 bind 0.0.0.0 -::1
# 开启 cluster 集群
1387 cluster-enabled yes
# 启动 Redis
[root@localhost redis-6.2.14]# redis-server redis.conf &
创建集群(任意一台执行即可):
bash
[root@redis1 redis-6.2.14]# redis-cli --cluster create 192.168.108.21:6379 192.168.108.22:6379 192.168.108.23:6379 192.168.108.24:6379 192.168.108.25:6379 192.168.108.26:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.108.25:6379 to 192.168.108.21:6379
Adding replica 192.168.108.26:6379 to 192.168.108.22:6379
Adding replica 192.168.108.24:6379 to 192.168.108.23:6379
M: fcbf04a3649f4e9e6b381861a94393c31eb67e67 192.168.108.21:6379 slots:[0-5460] (5461 slots) master
M: f3cb00b07a7836666bd3fd391040ff308ad35685 192.168.108.22:6379 slots:[5461-10922] (5462 slots) master
M: 90507dea1ca425cfe6ca993f8c453b2377ded5f0 192.168.108.23:6379 slots:[10923-16383] (5461 slots) master
S: 95fd02ecaf3fb34822fd56ed7ae61b05d782d892 192.168.108.24:6379 replicates 90507dea1ca425cfe6ca993f8c453b2377ded5f0
S: 18b45e542ebbf318fd9a92cfe2adcde4c255c72b 192.168.108.25:6379 replicates fcbf04a3649f4e9e6b381861a94393c31eb67e67
S: 8f5e04a03ae0984d843dab8fb9cd0cc4c4537624 192.168.108.26:6379 replicates f3cb00b07a7836666bd3fd391040ff308ad35685
Can I set the above configuration? (type 'yes' to accept): yes # 输入 yes 确认
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
>>> Performing Cluster Check (using node 192.168.108.21:6379)
[0-5460]表示该节点负责槽位 0--5460,(5461 slots)表示共 5461 个槽位。
查看集群状态:
bash
[root@redis1 redis-6.2.14]# redis-cli
127.0.0.1:6379> CLUSTER NODES
192.168.108.21:6379@16379 myself,master - 0 1770089899000 1 connected 0-5460
192.168.108.22:6379@16379 master - 0 1770089899000 2 connected 5461-10922
192.168.108.23:6379@16379 master - 0 1770089898000 3 connected 10923-16383
192.168.108.24:6379@16379 slave 90507dea... 0 1770089900314 3 connected
192.168.108.25:6379@16379 slave fcbf04a3... 0 1770089899000 1 connected
192.168.108.26:6379@16379 slave f3cb00b0... 0 1770089897000 2 connected
127.0.0.1:6379> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1134
cluster_stats_messages_pong_sent:1172
cluster_stats_messages_sent:2306
cluster_stats_messages_ping_received:1167
cluster_stats_messages_pong_received:1134
cluster_stats_messages_meet_received:5
创建数据: 数据必须写入其所属槽位对应的节点,否则会收到 MOVED 重定向提示。
bash
# redis1:该 key 的槽位不属于本节点,返回重定向
127.0.0.1:6379> SET name gqd
(error) MOVED 5798 192.168.108.22:6379 # 提示应在 redis2 操作
# redis2:槽位归属正确,写入成功
127.0.0.1:6379> SET name 'gqd'
OK
127.0.0.1:6379> GET name
"gqd"
# redis1 上读取同样会被重定向
127.0.0.1:6379> GET name
(error) MOVED 5798 192.168.108.22:6379
如何透明地跨节点读写? 使用 redis-cli -c 开启集群模式,客户端会自动跟随重定向:
bash
[root@redis1 redis-6.2.14]# redis-cli -c
127.0.0.1:6379> SET age 18
OK
127.0.0.1:6379> GET age
"18"
# 换一台机器,同样能取到------客户端自动跳转到归属节点
[root@redis3 redis-6.2.14]# redis-cli -c
127.0.0.1:6379> GET age
-> Redirected to slot [741] located at 192.168.108.21:6379
"18"
模拟故障:主节点宕机后会发生什么
关掉 redis1 节点,再次查看集群信息:
bash
[root@redis1 redis-6.2.14]# init 0
bash
# redis2 上查看节点信息
127.0.0.1:6379> CLUSTER NODES
192.168.108.21:6379@16379 master,fail - ...
192.168.108.25:6379@16379 master - 0 1770091177432 7 connected 0-5460
结果可知,集群仍保持 3 台 master,原来的 redis5 节点被选举为新的 master。
完整过程解析: 如果 Cluster 中 192.168.108.21:6379(Master 1)挂掉,而它的从节点 192.168.108.25:6379 仍然存活,整个集群会自动完成故障转移(failover),服务不中断、数据不丢失。
故障前的角色关系:
| 节点 IP | 角色 | 负责槽 | 副本关系 |
|---|---|---|---|
| 192.168.108.21 | Master | 0 -- 5460 | ← 由 .25 复制 |
| 192.168.108.25 | Slave | (无槽) | 复制 .21 |
其他节点(.22 / .26、.23 / .24)正常运行。
✅ 第 1 步:故障检测(约 15 秒内)
其他 master 节点(.22 和 .23)通过 Gossip 协议发现 .21 无响应。经过 cluster-node-timeout(默认 15 秒)后,多数 master(≥ 2/3)将其标记为 FAIL(客观下线)。
⏱ 在这 15 秒内,访问槽
[0--5460]的请求会失败或超时。
✅ 第 2 步:Slave .25 自动发起选举
.25(原 .21 的 slave)检测到 master 已 FAIL,等待一个短暂随机延迟(通常 < 1 秒),然后向其他 master 节点(.22 和 .23)请求投票。
✅ 第 3 步:获得多数票,晋升为新 Master
.22 和 .23 收到请求后验证 .25 是合法副本。因为有 2 个 master 投票(超过半数),.25 成功当选,执行:
bash
SLAVEOF NO ONE
并接管槽 0--5460。
✅ 第 4 步:集群拓扑更新,恢复服务
所有节点收到通知并更新集群视图:.25 变为 master,槽 0--5460 的 owner 变为 .25,集群状态重新变为:
bash
cluster_state: ok
cluster_slots_fail: 0
客户端再次写入 key(如 SET user:1001 "Alice",其槽落在 0--5460)时,会被自动重定向到 192.168.108.25:6379,操作成功。
故障前后对比:
| 项目 | 故障前 | 故障后(.21 挂) |
|---|---|---|
| Master 节点 | .21、.22、.23 | .25、.22、.23 |
| Slave 节点 | .25、.26、.24 | .26、.24(.25 已晋升) |
| 槽覆盖 | 0--16383 | 0--16383(完整) |
| 集群状态 | ok | 短暂 fail → 恢复为 ok |
| 数据完整性 | 完整 | 完整(无丢失) |
| 客户端影响 | --- | 写入槽 0--5460 暂时失败(< 30 秒),随后自动恢复 |
✅ 整个过程全自动,无需人工干预。
❗ 极端情况:如果 .21 和 .25 同时挂掉?
槽 0--5460 将无人负责,集群状态变为:
bash
cluster_state: fail
cluster_slots_fail: 5461
所有涉及这些槽的读写都会失败(返回 (error) CLUSTERDOWN The cluster is down),必须手动恢复 .21 或 .25 才能恢复服务。
这就是为什么主从节点必须部署在不同物理机 / 不同可用区!
如何验证(动手测试): 关掉 .21 后你会看到------
.21状态由fail?变为fail(fail?状态停留很短暂);.25角色从slave变为master,并拥有0-5460槽;- 几十秒后
CLUSTER INFO显示cluster_state:ok。
挂掉 redis5 的对照测试:
bash
[root@redis2 redis-6.2.14]# redis-cli -c -h 192.168.108.22 -p 6379 CLUSTER NODES
192.168.108.23:6379@16379 master - 0 1770092343225 3 connected 10923-16383
192.168.108.25:6379@16379 master,fail - 1770092246338 1770092243211 7 connected 0-5460
192.168.108.22:6379@16379 myself,master - 0 1770092341000 2 connected 5461-10922
192.168.108.26:6379@16379 slave f3cb00b0... 0 1770092342000 2 connected
192.168.108.24:6379@16379 slave 90507dea... 0 1770092345259 3 connected
192.168.108.21:6379@16379 master,fail - 1770091143695 1770091140000 1 connected
[root@redis2 redis-6.2.14]# redis-cli -c -h 192.168.108.22 -p 6379 CLUSTER INFO
cluster_state:fail # 集群状态 fail
cluster_slots_assigned:16384
cluster_slots_ok:10923
cluster_slots_pfail:0
cluster_slots_fail:5461
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:7
cluster_my_epoch:2
恢复集群: 将关掉的服务器开机、启动 Redis 服务即可,集群会自动重新纳管节点并恢复 ok 状态。
结论: 3 主 3 从架构完全能容忍任意一个 master 宕机,这正是 Redis Cluster 高可用的核心价值。
| 场景 | 集群是否可用 | 数据是否安全 | 是否自动恢复 |
|---|---|---|---|
| 仅 .21(master)挂 | ✅ 是 | ✅ 是 | ✅ 是(由 .25 接管) |
| .21 + .25 同时挂 | ❌ 否 | ⚠️ 槽 0--5460 不可用 | ❌ 否 |
十、容器化部署 Redis
使用 Docker 部署 Redis 是最快捷的方式,默认 Redis 容器即可支持远程连接 ,无需额外修改 bind 与 protected-mode。
bash
# 拉取镜像并启动,映射端口到宿主机
[root@localhost ~]# docker run -d --name redis -p 6379:6379 redis:latest
# 进入容器验证
[root@localhost ~]# docker exec -it redis redis-cli
127.0.0.1:6379> PING
PONG
127.0.0.1:6379> SET name wang
OK
127.0.0.1:6379> GET name
"wang"
启动后可用 Redis Desktop Manager 直接连接宿主机 IP 与 6379 端口,在 Server 面板查看 Redis 版本、运行平台、内存占用、客户端连接数与命令统计,在 Key Statistics 面板查看各逻辑库的 Key 数量与过期情况。
十一、三种架构选型对比
| 维度 | 主从复制 | 哨兵模式 | Redis Cluster |
|---|---|---|---|
| 解决的问题 | 数据冗余、读写分离 | 自动故障转移 | 分片 + 高可用 + 高并发 |
| 数据分片 | ❌ 全量复制 | ❌ 全量复制 | ✅ 16384 槽分片 |
| 写扩展 | ❌ 单主 | ❌ 单主 | ✅ 多主并行 |
| 故障自愈 | ❌ 需人工 | ✅ 自动 | ✅ 自动 |
| 最小节点数 | 2 | 3 Redis + 3 Sentinel | 6(3 主 3 从) |
| 一致性 | 异步 | 异步 | 最终一致 |
| 适用规模 | 小 | 中小 | 大规模 |
| 运维复杂度 | 低 | 中 | 高 |
总结
Redis 的价值远不止"快"。它以 Key-Value 模型为起点,用 String、Hash、List、Set、ZSet 五种数据结构,覆盖了缓存、计数、排行榜、对象存储、集合运算等绝大多数高频场景;再以 List 与发布订阅机制,轻量地承载起消息队列的解耦与削峰职责。而真正让 Redis 走进生产核心的,是它清晰的高可用演进路径:主从复制解决数据冗余与读写分离,哨兵模式把故障转移从人工运维中解放出来,Cluster 则用 16384 个哈希槽完成数据分片与水平扩展。三者层层递进,也各有边界------哨兵不做分片,集群只保证最终一致。选型时不必盲目追新,而应回到数据规模、并发量与一致性要求上对号入座。理解机制背后的取舍,永远比记住命令更重要。