文章目录
- Redis内存数据库:从数据类型到集群部署
-
- 前言
- 一、Redis简介
-
- [1.1 什么是Redis?](#1.1 什么是Redis?)
- [1.2 Redis的优势](#1.2 Redis的优势)
- [1.3 Redis常见应用场景](#1.3 Redis常见应用场景)
- [1.4 Redis特性](#1.4 Redis特性)
- [1.5 单线程模型](#1.5 单线程模型)
- [1.6 哈希槽的基本概念](#1.6 哈希槽的基本概念)
- 二、缓存原理
- 三、Redis数据类型
-
- [3.1 字符串string](#3.1 字符串string)
- [3.2 列表list](#3.2 列表list)
- [3.3 集合set](#3.3 集合set)
- [3.4 有序集合zset](#3.4 有序集合zset)
- [3.5 哈希hash](#3.5 哈希hash)
- 四、Pipeline流水线
- 五、Redis持久化
-
- [5.1 RDB(Redis DataBase)](#5.1 RDB(Redis DataBase))
- [5.2 AOF(Append-only File)](#5.2 AOF(Append-only File))
- [5.3 如何选择RDB还是AOF?](#5.3 如何选择RDB还是AOF?)
- 六、主从复制
- 七、哨兵模式(Sentinel)
- [八、Redis Cluster集群(3主3从)](#八、Redis Cluster集群(3主3从))
-
- [8.1 核心概念](#8.1 核心概念)
- [8.2 部署实战(3主3从)](#8.2 部署实战(3主3从))
- 九、Python连接Redis
- 十、容器部署Redis
- 写在最后
Redis内存数据库:从数据类型到集群部署
从缓存原理到五种数据类型,从持久化到主从哨兵集群,一篇文章吃透Redis核心知识
前言
在现代应用架构中,Redis已经成为不可或缺的关键组件。它凭借10万+ QPS的高性能、丰富的数据结构和灵活的部署方式,广泛应用于缓存、分布式锁、计数器、排行榜、消息队列等场景。
但很多开发者对Redis的理解停留在"会set和get"的层面,对其数据类型、持久化机制、高可用架构缺乏系统认识。
本文将系统讲解Redis的完整知识体系,涵盖核心概念、五种数据类型、持久化机制、主从复制、哨兵模式、Cluster集群 以及Python实战,帮助你在生产环境中用好Redis。
一、Redis简介
1.1 什么是Redis?
Redis是完全开源的,遵守BSD协议,是一个高性能的key-value数据库。
Redis与其他key-value缓存产品的三大特点:
- 支持持久化:可以将内存中的数据保存在磁盘中,重启时可以再次加载使用
- 丰富的数据结构:不仅支持简单的key-value类型,还提供list、set、zset、hash等数据结构的存储
- 支持数据备份:即master-slave模式的数据备份
1.2 Redis的优势
| 优势 | 说明 |
|---|---|
| 性能极高 | 10万~100万+ QPS,微秒级响应;MySQL通常几千~几万QPS,毫秒级响应 |
| 丰富的数据类型 | Strings、Lists、Hashes、Sets及Ordered Sets |
| 原子性 | 所有操作都是原子性的,多个操作也支持事务(MULTI/EXEC) |
| 丰富的特性 | publish/subscribe、通知、key过期等 |
1.3 Redis常见应用场景
一、热点数据缓存
这是Redis最经典的应用场景。将热点数据(如商品详情、用户信息)缓存到Redis,可大幅降低数据库压力。
实现要点:
- 缓存策略:采用Cache-Aside模式(先查缓存,未命中再查数据库并更新缓存)
- 过期控制:设置合理的TTL
- 缓存键设计:使用业务前缀+唯一标识,如
product:info:1001 - 空值处理:对查询不到的数据缓存空值(短TTL),防止缓存穿透
二、分布式锁
Redis的SETNX命令天然适合实现分布式锁。
实现要点:
- 加锁:使用
SET key value NX PX 30000(不存在则设置,过期时间30秒) - 解锁:通过Lua脚本原子性判断并删除锁,避免误删
- 续期:对长时间运行的任务,需定时延长锁的有效期
- 重试机制:获取锁失败时,实现合理的重试策略
三、计数器与限流
Redis的原子递增命令INCR非常适合实现计数器功能,结合过期时间可实现接口限流。
典型应用:
- 文章阅读量、视频播放次数统计
- 接口访问频率限制(如每分钟最多100次请求)
- 秒杀活动中的库存计数
四、排行榜系统
Redis的SortedSet(有序集合)数据结构完美适配排行榜需求,支持按分数实时排序。
五、分布式会话
在分布式系统中,使用Redis存储用户会话信息,可实现多服务实例间的会话共享。
六、消息队列
利用Redis的List数据结构可实现简单的消息队列,适合对消息可靠性要求不高的场景。
七、位图应用
Redis的Bitmap是一种节省空间的二进制数据结构,适合存储大量布尔值信息。
典型场景:
- 用户签到记录
- 活跃用户统计
- 权限标记
八、地理信息存储
Redis的GEO数据结构专门用于存储和操作地理坐标信息,适合LBS场景。
1.4 Redis特性
- 速度快:10W QPS,基于内存,C语言实现
- 单线程:避免线程竞争开销
- 持久化:支持RDB和AOF
- 支持多种数据结构
- 支持多种编程语言
- 功能丰富:支持Lua脚本、发布订阅、事务、pipeline等
- 主从复制
- 支持高可用和分布式
1.5 单线程模型
Redis 6.0版本前一直是单线程方式处理用户的请求。
为什么单线程还这么快?
- Redis的操作访问内存,数据库是访问硬盘
- Redis核心功能比数据库更简单,避免了复杂的约束和查询
- 单线程模型避免线程竞争开销
- 使用epoll IO多路复用
epoll的工作原理:
用一个生活例子来理解:你想吃烧烤、饺子和炒菜,有三种方案:
- 自己一个个买,一个个等 → 单线程,花的时间最多
- 三个人各买各的,分别等 → 多线程,等待时间是三者最大值,系统开销更大
- 自己买三份,都告诉老板"好了叫我",一个线程同时等待三份饭 → IO多路复用
epoll相当于事件通知/回调机制,select是你自己在几个摊位之间不停地问,没人提醒你。最关键的是操作系统能通知到应用程序哪个客户端来数据了。
注意事项:
- 一次只运行一条命令
- 避免执行长(慢)命令:
keys *、flushall、flushdb、slow lua script、mutil/exec、operate big value
1.6 哈希槽的基本概念
槽的数量:Redis集群将整个键空间划分为16384个哈希槽(0-16383)。
数据映射规则 :通过HASH_SLOT = CRC16(key) mod 16384公式计算键对应的槽号,确保相同key会始终映射到同一槽。
数据分布与节点管理:每个集群节点负责部分槽的集合,支持在线调整。
二、缓存原理
2.1 计算机系统的三层存储结构
| 层级 | 访问时间 | 容量 |
|---|---|---|
| CPU | 20~40ns | 1~32MB |
| 内存 | 100ns | 32~96GB |
| 磁盘 | 3~5ms | 1~4TB |
2.2 缓存的两个特征
- 缓存是一个快速子系统:数据存在缓存中时,能避免每次从慢速子系统中存取数据
- 缓存容量总是小于后端慢速系统:不可能把所有数据都放在缓存系统中
2.3 Redis缓存处理请求的两种情况
缓存命中:Redis中有相应数据,直接读取Redis,性能非常快。
缓存缺失 :Redis中没有保存相应数据,就从后端数据库中读取数据,性能就会变慢。一旦发生缓存缺失,为了让后续请求能从缓存中读取到数据,需要把缺失的数据写入Redis,这个过程叫作缓存更新。
2.4 Redis作为旁路缓存
Redis是一个独立的系统软件,和业务应用程序是两个软件。应用程序想要使用Redis缓存,需要在程序中增加相应的缓存操作代码。所以,我们也把Redis称为旁路缓存。
需要在应用程序中增加三方面的代码:
- 读取数据时,显式调用Redis的GET操作接口
- 缓存缺失时,从数据库中读取数据
- 缓存更新时,显式调用SET操作接口
2.5 缓存的类型
只读缓存:所有的数据写请求直接发往后端的数据库。对于删改的数据,如果Redis已经缓存了相应的数据,应用需要把这些缓存的数据删除。
读写缓存:所有的写请求也会发送到缓存,在缓存中直接对数据进行增删改操作。
根据业务应用对数据可靠性和缓存性能的不同要求,有两种策略:
| 策略 | 说明 | 特点 |
|---|---|---|
| 同步直写 | 写请求发给缓存的同时,也会发给后端数据库 | 优先保证数据可靠性 |
| 异步写回 | 所有写请求都先在缓存中处理 | 优先提供快速响应 |
2.6 缓存穿透、缓存击穿和缓存雪崩
缓存雪崩
定义 :指缓存层由于大面积失效(如同一时间批量过期)或缓存服务宕机,导致所有请求瞬间涌入数据库,导致数据库崩溃的现象。

通俗理解:想象一个游乐场,所有出口的闸机同时坏了或者同时过期了,几千人一下子全部冲向检票口,大门瞬间被挤爆。
发生场景:
- 批量Key同时过期
- Redis集群宕机
解决方案:
- 过期时间加随机值:给Key的过期时间加个随机范围(如10分钟+1~5分钟),打散过期时间
- 搭建高可用集群:Redis多主多从,哨兵模式,避免单点故障
- 服务限流熔断:使用Sentinel或Hystrix限制并发数
- 多级缓存:本地缓存(Guava)+Redis
缓存穿透
定义 :指查询一个根本不存在的数据(缓存中没有,数据库中也没有)。因为缓存不缓存空值,所以每次请求都会绕过缓存直接去查数据库。

通俗理解:你拿着一张假身份证去游乐场检票,检票员看了一眼说没这张票,就让你去后台查。后台查了半天也没有,就让你回去了。结果来了一万个拿着假身份证的人,都去后台折腾。
发生场景:
- 攻击者恶意查询不存在的ID
- 业务代码Bug导致反复查无效Key
解决方案:
- 接口层增加校验:如用户鉴权校验,ID做基础校验,id<=0的直接拦截
- 缓存空结果:对查询的空结果也进行缓存
- 布隆过滤器:将所有可能对应的数据为空的key进行统一的存放,并在请求前做拦截
缓存击穿
定义 :指热点Key在某个时刻过期,此时恰好有大量并发请求同时打过来。因为缓存中没有,这些请求都会去查询数据库。

通俗理解:游乐场只有一个VIP通道,这个通道刚好关闭了,但此时有一万人正排队等着通过,结果大家一拥而上,把通道旁边的闸机挤坏了。
发生场景:秒杀活动、热点新闻爆发。
与雪崩的区别:雪崩是大面积(很多Key一起挂),击穿是单点(一个热点Key挂了,但它很重要)。
解决方案:
- 加锁排队:在查询数据库的时候加锁排队
- 设置永不过时:对于某些经常使用的缓存,设置为永不过期
三、Redis数据类型
Redis支持五种数据类型:string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)。
3.1 字符串string
字符串是一种最基本的Redis值类型。Redis字符串是二进制安全的,一个字符串类型的值最多能存储512M字节的内容。Redis中所有key都是字符串类型的。
常用命令:
| 命令 | 说明 |
|---|---|
| `SET key value [EX seconds] [PX milliseconds] [NX | XX]` |
GET 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 ...] |
批量获取 |
SET命令的参数:
EX seconds:将键的过期时间设置为seconds秒PX milliseconds:将键的过期时间设置为milliseconds毫秒NX:只在键不存在时,才对键进行设置操作XX:只在键已经存在时,才对键进行设置操作
实操示例:
bash
# 设置和获取
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
# 设置过期时间
127.0.0.1:6379> set title ceo ex 3
OK
127.0.0.1:6379> get title
(nil) # 3秒后过期
# NX和XX
127.0.0.1:6379> setnx title coo # title不存在,设置成功
(integer) 1
127.0.0.1:6379> setnx title ceo # title已存在,设置失败
(integer) 0
127.0.0.1:6379> set title ceo xx # title存在,设置成功
OK
127.0.0.1:6379> set age 20 xx # age不存在,不操作
(nil)
# 批量操作
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> set num 10
OK
127.0.0.1:6379> INCR num
(integer) 11
127.0.0.1:6379> DECR num
(integer) 10
127.0.0.1:6379> INCRBY mykey 5
(integer) 5
# 获取过期时长
127.0.0.1:6379> TTL name
(integer) 97
127.0.0.1:6379> PERSIST name # 取消过期时间
(integer) 1
127.0.0.1:6379> TTL name
(integer) -1 # -1表示永不过期
3.2 列表list
Redis列表是简单的字符串列表,按照插入顺序排序。支持双向读写,可以添加一个元素到列表的头部(左边)或者尾部(右边)。
特点:有序、可重复、左右都可以操作。
常用命令:
| 命令 | 说明 |
|---|---|
LPUSH key value [value ...] |
从左边插入元素 |
RPUSH key value [value ...] |
从右边插入元素 |
LPOP key |
弹出左边第一个元素 |
RPOP key |
弹出右边第一个元素 |
LRANGE key start stop |
获取列表指定范围的元素 |
LLEN key |
获取列表长度 |
LINDEX key index |
获取指定索引的元素 |
LREM key count value |
删除列表中count个等于value的元素 |
实操示例:
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> LLEN list1
(integer) 2
# 获取指定位置元素
127.0.0.1:6379> LPUSH list2 a b c d
(integer) 4
127.0.0.1:6379> LINDEX list2 0
"d"
127.0.0.1:6379> LRANGE list2 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
# 修改指定索引值
127.0.0.1:6379> lset list4 2 cloud
OK
# 删除数据
127.0.0.1:6379> lpop list5
"d"
127.0.0.1:6379> RPOP list5
"a"
# 修剪列表(只保留指定区间)
127.0.0.1:6379> LTRIM list6 2 3
OK
3.3 集合set
Set是一个无序的字符串合集,同一个集合中的每个元素是唯一无重复的。支持在两个不同的集合中对数据进行逻辑处理,常用于取交集、并集、统计等场景。
特点:无序、无重复、集合间操作。
常用命令:
| 命令 | 说明 |
|---|---|
SADD key member [member ...] |
添加一个或多个成员 |
SMEMBERS key |
获取集合所有成员 |
SISMEMBER key member |
判断成员是否在集合中 |
SREM key member [member ...] |
删除一个或多个成员 |
SCARD key |
获取集合成员数量 |
SINTER key1 [key2 ...] |
求多个集合的交集 |
SUNION key1 [key2 ...] |
求多个集合的并集 |
SDIFF key1 [key2 ...] |
求差集 |
实操示例:
bash
# 创建集合
127.0.0.1:6379> SADD set1 v1
(integer) 1
127.0.0.1:6379> SADD set2 v2 v4
(integer) 2
# 追加数据(重复值无法添加)
127.0.0.1:6379> SADD set1 v2 v3 v4
(integer) 3
127.0.0.1:6379> SADD set1 v2
(integer) 0 # 已存在,添加失败
# 获取所有数据
127.0.0.1:6379> SMEMBERS set1
1) "v4"
2) "v3"
3) "v1"
4) "v2"
# 删除元素
127.0.0.1:6379> srem name1 meiyangyang
(integer) 1
# 集合间操作
127.0.0.1:6379> SINTER set1 set2 # 交集
1) "v4"
2) "v2"
127.0.0.1:6379> SUNION set1 set2 # 并集
1) "v3"
2) "v1"
3) "v2"
4) "v4"
127.0.0.1:6379> SDIFF set1 set2 # 差集
1) "v3"
2) "v1"
3.4 有序集合zset
Redis有序集合和集合类似,是不包含相同字符串的合集。差别是,每个有序集合的成员都关联着一个双精度浮点型的评分(score) ,用于排序。有序集合的成员不能重复,但评分可以重复。常用于排行榜的场景。
特点:有序、无重复元素、每个元素由score和value组成。
常用命令:
| 命令 | 说明 |
|---|---|
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 |
获取成员的排名(升序) |
实操示例:
bash
# 创建有序集合
127.0.0.1:6379> ZADD zset1 1 v1
(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> ZADD zset2 1 v1 2 v2 3 v3 4 v4 5 v5
(integer) 5
# 实现排名
127.0.0.1:6379> ZADD course 90 linux 99 go 60 python 50 cloud
(integer) 4
# 正序排序
127.0.0.1:6379> ZRANGE course 0 -1
1) "cloud"
2) "python"
3) "linux"
4) "go"
# 倒序排序
127.0.0.1:6379> ZREVRANGE course 0 -1
1) "go"
2) "linux"
3) "python"
4) "cloud"
# 带分数显示
127.0.0.1:6379> ZRANGE course 0 -1 WITHSCORES
1) "cloud"
2) "50"
3) "python"
4) "60"
5) "linux"
6) "90"
7) "go"
8) "99"
# 查询排名
127.0.0.1:6379> ZRANK course go
(integer) 3
# 获取分数
127.0.0.1:6379> ZSCORE course cloud
"50"
# 删除元素
127.0.0.1:6379> ZREM course python go
(integer) 2
3.5 哈希hash
hash即字典,用于保存字符串字段field和字符串值value之间的映射。一个hash最多可以包含2^32-1个key/value键值对。
特点:无序、K/V对、适用于存放相关的数据。
常用命令:
| 命令 | 说明 |
|---|---|
HSET key field value |
设置hash字段的值 |
HGET key field |
获取hash字段的值 |
HMSET key field1 value1 [field2 value2 ...] |
批量设置字段 |
HMGET key field1 [field2 ...] |
批量获取字段 |
HGETALL key |
获取hash中所有字段和值 |
HDEL key field [field ...] |
删除一个或多个字段 |
HEXISTS key field |
判断字段是否存在 |
实操示例:
bash
# 创建hash
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
# 查看指定field的value
127.0.0.1:6379> HGET 9527 name
"zhouxingxing"
# 获取多个值
127.0.0.1:6379> HMGET 9527 name age
1) "zhouxingxing"
2) "20"
# 删除指定field
127.0.0.1:6379> HDEL 9527 age
(integer) 1
# 批量设置
127.0.0.1:6379> HMSET 9527 name zhouxingxing age 50 city hongkong
OK
# 查看所有field
127.0.0.1:6379> HKEYS 9527
1) "name"
2) "gender"
3) "age"
4) "city"
# 查看所有value
127.0.0.1:6379> HVALS 9527
1) "zhouxingxing"
2) "male"
3) "50"
4) "hongkong"
四、Pipeline流水线
Redis客户端执行一条命令分4个过程:发送命令 → 命令排队 → 命令执行 → 返回结果 ,这个过程称为Round Trip Time(RTT,往返时间)。
Redis提供了批量操作命令(如mget、mset)有效节约RTT。但大部分命令不支持批量操作,例如要执行n次hgetall命令,需要消耗n次RTT。
Pipeline机制能将一组Redis命令进行组装,通过一次RTT传输给Redis,再将这组命令的执行结果按顺序返回。
两者性能对比:
| 网络延迟 | 非Pipeline | Pipeline |
|---|---|---|
| 本机 | 0.17ms | 573ms |
| 内网服务器 | 0.41ms | 1610ms |
| 异地机房 | 7ms | 80000ms |
结论:使用Pipeline执行速度比逐条执行要快,特别是客户端与服务端的网络延迟越大,性能提升越明显。
五、Redis持久化
Redis作为一个键值对内存数据库,数据都存储在内存当中。存储在内存当中的数据,只要服务器关机或Redis进程退出,内存中的数据就会消失。
为了避免内存中数据丢失,Redis提供了对持久化的支持,我们可以选择不同的方式将数据从内存中保存到硬盘当中。
5.1 RDB(Redis DataBase)
RDB是一种快照存储持久化方式,具体就是将Redis某一时刻的内存数据保存到硬盘的文件当中,默认保存的文件名为dump.rdb。
开启RDB持久化方式:
方式一:save命令(同步操作)
bash
127.0.0.1:6379> save
OK
当客户端向服务器发送Save命令请求进行持久化时,服务器会阻塞Save命令之后的其他客户端的请求,直到数据同步完成。如果数据量太大,同步数据会执行很久,所以最好不要在生产环境使用Save命令。
方式二:bgsave命令(异步操作)
bash
127.0.0.1:6379> bgsave
Background saving started
Redis服务器主进程会Fork一个子进程来数据同步,在将数据保存到RDB文件之后,子进程会退出。主进程仍然可以接收其他请求,但Fork子进程是同步的。
方式三:服务器配置自动触发
bash
# 以下是默认值
save 900 1 # 900秒内修改了1个KEY即触发保存RDB
save 300 10 # 300秒内修改了10个KEY即触发保存RDB
save 60 10000 # 60秒内修改了10000个KEY即触发保存RDB
RDB文件生成过程:
- 生成临时RDB文件,并写入数据
- 完成数据写入,用临时文件替代正式RDB文件
- 删除原来的DB文件
RDB的优点:
- 与AOF方式相比,通过RDB文件恢复数据比较快
- RDB文件非常紧凑,适合于数据备份
- 通过RDB进行数据备份,由于使用子进程生成,对Redis服务器性能影响较小
RDB的缺点:
- 如果服务器宕机,采用RDB的方式会造成某个时段内数据的丢失
- 使用Save命令会造成服务器阻塞
- 使用Bgsave命令在Forks子进程时,如果数据量太大,Forks的过程也会发生阻塞
5.2 AOF(Append-only File)
与RDB存储某个时刻的快照不同,AOF持久化方式会记录客户端对服务器的每一次写操作命令,并将这些写操作以Redis协议追加保存到AOF文件末尾。
开启AOF持久化方式:
bash
# 修改配置文件
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
⚠️ 注意:AOF模式默认是关闭的。第一次开启AOF后,并重启服务生效后,会因为AOF的优先级高于RDB,而AOF默认没有数据文件存在,从而导致所有数据丢失。
正确启用AOF功能,防止数据丢失:
bash
# 先动态开启AOF,此时会生成appendonly.aof
127.0.0.1:6379> config set appendonly yes
OK
# 然后修改配置文件
[root@localhost ~]# vim /etc/redis.conf
appendonly yes
三种写入策略:
| 策略 | 说明 | 特点 |
|---|---|---|
appendfsync always |
每一个写操作都保存到AOF文件 | 很安全,但很慢 |
appendfsync everysec |
每秒写入一次AOF文件 | 默认策略,最多丢失1s数据 |
appendfsync no |
交由操作系统决定何时写入 | 最快,但最不安全 |
AOF文件重写:
AOF重写是通过读取服务器当前的数据库状态来实现的。例如:
bash
rpush list "A" rpush list "B" rpush list "C" rpush list "D" rpush list "E" rpush list "F"
这六条命令可以直接用一条命令代替:
bash
rpush list "A" "B" "C" "D" "E" "F"
重写方式:
- 在配置文件中设置
no-appendfsync-on-rewrite - 客户端发送
bgrewriteaof命令
AOF文件损坏修复:
bash
[root@localhost ~]# redis-check-aof --fix /var/lib/redis/appendonly.aof
AOF的优点:
- AOF只是追加日志文件,对服务器性能影响较小,速度比RDB要快,消耗的内存较少
AOF的缺点:
- AOF方式生成的日志文件太大
- 恢复数据的速度比RDB慢
5.3 如何选择RDB还是AOF?
| 对比项 | RDB | AOF |
|---|---|---|
| 恢复速度 | 快 | 慢 |
| 文件体积 | 小 | 大 |
| 数据安全性 | 可能丢失一段时间数据 | 最多丢失1s数据 |
| 性能影响 | 较小 | 较小 |

结论 :如果想要数据足够安全,可以两种方式都开启。当RDB与AOF两种方式都开启时,Redis会优先使用AOF日志来恢复数据,因为AOF保存的文件比RDB文件更完整。
六、主从复制
Redis主从复制(Master-Slave Replication)是Redis实现高可用、读写分离和数据冗余的核心机制之一。
目的:数据冗余和读写分离。
原理:主从复制是Redis高可用性的基础。它允许一个Redis服务器(主节点,Master)将其数据复制到一个或多个Redis服务器(从节点,Slave/Replica)。
主从复制特点:
- 一个master可以有多个slave
- 一个slave只能有一个master
- 数据流向是从master到slave单向的
- master可读写,slave只读
主从同步工作原理:
- slave向master发送sync命令
- master启动后台存盘进程,并收集所有修改数据命令
- master完成存盘后,传送整个数据文件到slave
- slave接受数据文件,加载到内存中完成首次完全同步
- 后续有新数据产生时,master继续将新的数据命令传递给slave完成同步
配置从节点:
bash
# 修改配置文件
replicaof 192.168.108.10 6379
或者通过命令:
bash
127.0.0.1:6379> REPLICAOF MASTER_IP PORT
验证:
bash
# master节点
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
# slave节点
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.108.10
master_port:6379
master_link_status:up
取消主从同步:
bash
127.0.0.1:6379> REPLICAOF NO ONE
七、哨兵模式(Sentinel)
Redis哨兵模式是Redis官方提供的高可用性解决方案,用于在主从架构中实现自动故障检测与故障转移。
目的:在主从复制的基础上,实现自动故障转移。
主要功能:
- 监控:持续检查主节点和从节点是否正常运行
- 通知:当被监控的Redis实例异常时,可通过API通知管理员或其他系统
- 自动故障转移:当主节点宕机,Sentinel会自动将一个从节点提升为新主节点
- 配置提供者:客户端可通过Sentinel获取当前主节点地址
哨兵本身不存储数据,只负责监控和协调。
故障转移流程:
- 主观下线(Sdown):某个Sentinel发现主节点无响应
- 客观下线(ODOWN):多个Sentinel(≥quorum配置值)达成共识
- 选举Leader:Sentinel之间通过Raft算法选举出一个Leader
- 提升新主 :Leader选择一个"最优"从节点执行
REPLICAOF NO ONE - 重配从节点:其他从节点重新指向新主节点
- 通知客户端:通过发布/订阅机制通知客户端主节点变更
配置哨兵:
bash
# 复制配置文件
cp sentinel.conf sentinel.conf.bak
# 编辑配置文件
vim sentinel.conf
# sentinel monitor mymaster 192.168.108.10 6379 2
# sentinel down-after-milliseconds mymaster 30000
启动哨兵:
bash
redis-sentinel sentinel.conf &
查看哨兵状态:
bash
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
master0:name=mymaster,status=ok,address=192.168.108.10:6379,slaves=2,sentinels=3
八、Redis Cluster集群(3主3从)
Redis集群是Redis 3.0+官方推出的分布式解决方案,核心是数据分片+主从复制+去中心化故障转移,解决单机Redis的容量、性能、单点故障瓶颈。
8.1 核心概念
关键角色:
- 主节点(Master):处理读写、管理哈希槽、参与故障投票
- 从节点(Replica/Slave):异步复制主节点数据,默认只读
- 哈希槽(Hash Slot):集群固定16384个槽(0~16383),是数据分片的最小单位
- 节点ID:每个节点唯一标识,用于集群内识别与通信
核心特性:
- 数据分片:突破单机内存限制,总容量 = 所有主节点内存之和
- 高可用:部分节点故障不影响整体,自动故障转移
- 线性扩展:加节点即可提升容量与并发
- 去中心化:无中心节点,避免单点瓶颈
- 自动路由:客户端连接任意节点,自动重定向到目标节点
数据分片(哈希槽机制):
text
HASH_SLOT = CRC16(key) mod 16384
每个主节点负责一段连续槽位(如3主集群:0-5460、5461-10922、10923-16383)。
节点通信(Gossip协议):
- 节点间通过集群总线(独立端口,默认+10000)通信
- 消息类型:PING/PONG(心跳检测)、FAIL(广播节点失效)、UPDATE(槽位映射更新)
故障转移:
- 故障检测:某主节点超时无响应,多数主节点标记为FAIL
- 从节点选举:该主节点的从节点发起FAILOVER请求
- 投票晋升:主节点投票通过,从节点升级为主,接管槽位
- 拓扑更新:Gossip同步新状态,集群恢复
8.2 部署实战(3主3从)
环境准备:6台CentOS 7.9虚拟机,IP地址192.168.108.21~26。
所有主机操作:
bash
# 关闭防火墙
systemctl stop firewalld
# 修改配置文件
vim redis.conf
bind 0.0.0.0
cluster-enabled yes
# 启动Redis
redis-server redis.conf &
创建集群:
bash
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
查看集群状态:
bash
127.0.0.1:6379> cluster nodes
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_known_nodes:6
cluster_size:3
创建数据:
bash
# 使用-c参数自动重定向
redis-cli -c
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> get age
"18"
模拟故障:
bash
# 关闭redis1节点
[root@redis1 ~]# init 0
# 查看集群信息,redis5被选举为新master
127.0.0.1:6379> cluster nodes
故障前后对比:
| 项目 | 故障前 | 故障后(.21挂) |
|---|---|---|
| Master节点 | .21, .22, .23 | .25, .22, .23 |
| Slave节点 | .25, .26, .24 | .26, .24 |
| 槽覆盖 | 0-16383 | 0-16383(完整) |
| 集群状态 | ok | 短暂fail→恢复为ok |
| 数据完整性 | 完整 | 完整(无丢失) |
极端情况:如果.21和.25同时挂掉,槽0-5460将无人负责,集群状态变为fail,必须手动恢复才能恢复服务。
九、Python连接Redis
Redis支持多种开发语言访问,下面以Python为例。
安装redis-py库:
bash
pip install redis
基本连接:
python
import redis
r = redis.Redis(host='192.168.108.172', port=6379, password='123456', db=0)
print(r)
字符串操作:
python
# 设置和获取
r.set('color1', 'red')
value = r.get('color1')
print(value) # b'red'
# 数字递增递减
r.set('int1', 10)
result = r.incr('int1') # 自增
print(result) # 11
result = r.decr('int1') # 自减
print(result) # 10
列表操作:
python
r.lpush('mylist', 'nihao')
r.lpush('mylist', 'laogao')
print(r.lrange('mylist', 0, -1))
# [b'laogao', b'nihao']
哈希操作:
python
r.hset('student', 'name', 'lisi')
r.hset('student', 'age', '18')
print(r.hget('student', 'name')) # b'lisi'
print(r.hget('student', 'age')) # b'18'
print(r.hgetall('student')) # {b'name': b'lisi', b'age': b'18'}
⚠️ 注意:文件不要命名为redis.py,会和redis模块名称冲突。
十、容器部署Redis
bash
# 使用Docker运行Redis
docker run --name redis -p 6379:6379 -d -v /data/redis:/data redis
# 进入容器操作
docker exec redis redis-cli info server
docker exec redis redis-cli set name ma
docker exec redis redis-cli get name
docker exec redis redis-cli save

💡 默认Redis容器可以支持远程连接。

写在最后
本文系统讲解了Redis的完整知识体系:
| 章节 | 核心内容 |
|---|---|
| Redis简介 | 特点、优势、应用场景、单线程模型 |
| 缓存原理 | 缓存穿透、击穿、雪崩及解决方案 |
| 数据类型 | string、list、set、zset、hash |
| Pipeline | 批量命令优化RTT |
| 持久化 | RDB、AOF及选择策略 |
| 主从复制 | 数据冗余和读写分离 |
| 哨兵模式 | 自动故障转移 |
| Cluster集群 | 数据分片+高可用 |
| Python实战 | redis-py连接操作 |
| 容器部署 | Docker运行Redis |
核心结论:
- Redis是单线程的,但通过epoll IO多路复用实现了高并发
- 五种数据类型各有适用场景:string做缓存、list做队列、set做去重、zset做排行榜、hash存对象
- RDB和AOF可以同时开启,AOF优先级更高,数据更完整
- 主从复制 解决读写分离,哨兵模式 解决自动故障转移,Cluster集群解决数据分片
- Pipeline能显著提升批量命令的性能,网络延迟越大效果越明显
- 缓存三大问题:穿透、击穿、雪崩,各有对应的解决方案
📌 核心命令速查
bash
# 字符串
SET key value [EX seconds] [NX|XX]
GET key
INCR/DECR key
MSET/MGET
# 列表
LPUSH/RPUSH key value
LPOP/RPOP key
LRANGE key start stop
# 集合
SADD key member
SMEMBERS key
SINTER/SUNION/SDIFF
# 有序集合
ZADD key score member
ZRANGE/ZREVRANGE key start stop [WITHSCORES]
ZRANK key member
# 哈希
HSET key field value
HGET key field
HGETALL key
# 持久化
SAVE/BGSAVE
BGREWRITEAOF
CONFIG SET appendonly yes
# 主从
REPLICAOF host port
REPLICAOF NO ONE
INFO replication
# 集群
CLUSTER NODES
CLUSTER INFO
redis-cli --cluster create ...
知识点思维导图

📝 本文首发于个人技术博客,欢迎交流讨论。如有错误,恳请指正。