Redis完全指南
目录
Redis 简介
Redis(Remote Dictionary Server)是一个开源(BSD许可)的内存数据结构存储系统,可用作数据库、缓存和消息中间件。它支持多种数据类型,具有内置的复制、Lua脚本、LRU驱动事件、事务以及不同级别的磁盘持久化功能,并通过Redis Sentinel和Redis Cluster提供高可用性服务。
Redis 核心特性
- 高性能:基于内存操作,单线程模型避免锁竞争,QPS可达10万+
- 丰富的数据结构:支持字符串、哈希、列表、集合、有序集合等多种数据类型
- 原子操作:所有操作都是原子性的,多个操作也支持事务功能
- 持久化:支持RDB和AOF两种持久化方式,确保数据不丢失
- 高可用:支持主从复制、哨兵模式和集群模式,保证服务稳定性
- 发布订阅:支持发布/订阅模式的消息机制
- Lua脚本:支持使用Lua脚本扩展Redis功能
Redis数据类型
String
特性
- 最基础的数据类型,存储字符串、数字或二进制数据(图片)
- 最大存储容量为512MB
- 支持原子操作(自增、自减)
- 可以对整个字符串或部分字符串进行操作
优势
- 操作简单高效,适用于缓存、计数器、分布式锁等场景
- 可存储结构化数据(如JSON字符串)
- 支持过期策略:可设置键的过期时间(
EX
参数),自动清理旧数据,无需手动维护
- 二进制安全,可以存储任何格式的数据
应用场景
- 缓存:存储HTML页面、API响应等
- 计数器:如网站访问量、用户点赞数
- 分布式锁:利用原子性操作实现分布式锁
- 会话管理:存储用户会话信息
1 2 3 4 5 6 7 8 9
|
set username "username1"
get username
SET session_id "xyz123" EX 10
|
自增
1 2 3
| set views 100 INCR views get views
|
自减
1 2 3
| set views 100 DECR views get views
|
设置过期时间
1 2
| set token " 4aa5f2ce-f422-4b40-8bee-1f9f3f7fe231" EX 10
|
Hash
特性
- 类似字典,存储键值对的集合(field-value)
- 每个哈希可以存储多达2^32 - 1个键值对
- 适合存储对象(如用户信息、商品详情)
优势
- 可单独操作对象的某个字段,无需修改整个对象,节省带宽
- 内存占用比String存储对象更高效
- 适合存储结构化数据,比JSON字符串更灵活
应用场景
- 用户信息管理:存储用户ID、姓名、年龄等信息
- 商品详情:存储商品ID、名称、价格、库存等
- 购物车:每个用户的购物车可以使用一个Hash,商品ID作为field,数量作为value
- 配置信息:应用配置、系统参数等
1 2 3 4 5 6 7 8 9 10 11
| HSET user:100 name "bob" age 25 email "[email protected]"
HGET user:100 name
HGETALL user:100
HDEL user:100 email
|
List
特性
- 有序列表,元素可重复,底层基于双向链表实现
- 支持从双端插入/删除元素,适合实现队列或栈
- 每个列表最多可存储2^32 - 1个元素
- 支持阻塞操作,可用于实现生产者-消费者模式
优势
- 操作双端元素效率极高(时间复杂度O(1))
- 内部有序,无需额外排序操作
- 支持范围操作,可以获取部分元素
应用场景
- 消息队列:使用LPUSH + RPOP实现简单的消息队列
- 最新动态:如微博、朋友圈的最新N条动态
- 任务队列:任务的派发与执行
- 最近浏览记录:记录用户最近浏览的商品
1 2 3 4 5 6 7 8 9 10 11
| RPUSH fruits "apple" "banana"
LPUSH fruits "orange"
LRANGE fruits 0 2
RPOP fruits
|
Set
特性
- 无序集合,元素唯一,底层基于哈希表实现
- 支持交集、并集、差集等集合运算
- 每个集合最多可存储2^32 - 1个元素
- 可以随机获取集合中的元素
优势
- 天然去重,适合存储标签、好友列表等
- 集合运算可用于社交场景(如共同好友)
- 添加、删除、查找的复杂度都是O(1)
- 支持并发读写,线程安全
应用场景
- 用户标签系统:为用户添加标签,实现兴趣推荐
- 社交关系:粉丝、关注、共同好友等
- 黑白名单:IP黑名单、敏感词过滤
- 随机抽奖:利用SRANDMEMBER或SPOP实现
添加元素
1
| SADD tags "user1" "user2" "user3"
|
元素是否存在
集合交集
1 2 3
| SADD user:1:follows 101 102 103 SADD user:2:follows 102 103 104 SINTER user:1:follows user:2:follows
|
Sorted Set
特性
- 类似Set,但每个元素关联一个分数(Score),按分数排序
- 元素不允许重复,但分数可以重复
- 底层使用跳表和哈希表实现,支持高效的范围查询
- 每个有序集合最多可存储2^32 - 1个元素
优势
- 可高效实现排行榜、延迟队列等场景
- 分数可动态更新,排序实时生效
- 支持按分数范围或元素位置范围查询
- 支持
ZREVRANGE
(倒序取前 N 名)、ZRANK
(查询某个元素的排名)等命令,时间复杂度为 O(logN)
应用场景
- 排行榜系统:游戏积分排行、直播礼物榜、商品销量榜
- 带权重的消息队列:根据优先级处理任务
- 延迟队列:使用时间戳作为score,实现定时任务
- 实时排名更新:用户分数变化后立即刷新名次
添加元素
1 2
| ZADD ranking 80 "user1" 95 "user2" 70 "user3"
|
获取分数从高到低的前2名
1
| ZREVRANGE ranking 0 1 WITHSCORES
|
查看某个元素的分数
增加分数
1
| ZINCRBY ranking 5 "user2"
|
其他数据类型
Bitmap
特性
- 本质上是字符串的位操作,可以将字符串看作是二进制位的数组
- 可对每一位进行设置(0或1)和获取操作
- 最大支持2^32位,约512MB
优势
- 极其节省空间,每个位只占用1bit
- 适合存储布尔类型的数据
- 提供位运算操作,如与、或、异或等
应用场景
- 用户签到记录:每一位代表一天,签到为1,未签到为0
- 在线状态统计:在线为1,离线为0
- 用户行为统计:如是否阅读过某篇文章
- 布隆过滤器:快速判断元素是否存在
记录用户签到
1 2 3
| SETBIT sign:user100 1 1 SETBIT sign:user100 3 1
|
统计签到天数
HyperLogLog
特性
- 用于估算集合中唯一元素的数量(基数统计)
- 占用内存极小,无论数据量多大,只需要12KB内存
- 有一定的误差率,标准误差约为0.81%
优势
- 节省内存:相比Set存储所有元素,内存占用极小
- 性能高效:计算速度快,不随集合大小增长
- 适合海量数据:可处理数十亿级别的不重复数据统计
应用场景
- 网站UV(独立访客)统计
- APP日活、月活用户数统计
- 大规模数据去重统计
添加UV记录
1
| PFADD uv:2025-7-2 "user1" "user2" "user3"
|
统计UV
Geospatial
特性
- 专门用于存储地理位置信息(经纬度坐标)
- 底层基于Sorted Set和地理哈希(Geohash)算法实现
- 支持存储、查询、计算地理位置信息
优势
- 原生支持经纬度存储:提供
GEOADD
(添加地点)、GEORADIUS
(搜索指定范围内的地点)等命令
- 高效空间计算:底层基于地理哈希(
Geohash
)实现,距离计算和范围查询效率高
- 简化开发:无需依赖专门的GIS系统,可直接在Redis中实现位置服务
应用场景
- 附近的人、周边商家搜索(如外卖APP的附近餐厅)
- 两地距离计算(如打车软件的起点到终点距离)
- 地理围栏(Geo-fencing):判断用户是否进入或离开特定区域
- 位置共享和追踪:如共享单车定位、物流配送跟踪
添加地点
1 2
| GEOADD places 116.40 39.90 "北京" 121.47 31.23 "上海"
|
计算两地距离(单位:km)
1
| GEODIST places "北京" "上海" km
|
搜索附近地点
1 2
| GEORADIUS places 116.40 39.90 1000 km
|
Redis整体优势
- 高性能:基于内存操作,单线程模型避免锁竞争,QPS可达10万+
- 持久化:支持RDB和AOF两种持久化方式,确保数据不丢失
- 高可用:支持主从复制、哨兵模式和集群(
Cluster
),保证服务稳定性
- 丰富功能:除基础类型外,还支持发布订阅、Lua脚本、事务等
Redis持久化
Redis是内存数据库,为了保证数据在服务器重启后不丢失,Redis提供了持久化机制。Redis支持两种持久化方式:RDB和AOF。
RDB持久化
原理
RDB(Redis DataBase)持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快照,它恢复时是将快照文件直接读到内存中。
触发方式
- 自动触发:根据redis.conf中配置的save规则自动触发
1 2 3
| save 900 1 # 900秒内至少有1个key被修改 save 300 10 # 300秒内至少有10个key被修改 save 60 10000 # 60秒内至少有10000个key被修改
|
- 手动触发:
SAVE
命令:阻塞Redis服务器进程,直到RDB文件创建完毕
BGSAVE
命令:派生出一个子进程来创建RDB文件,不阻塞服务器进程
优点
- 适合大规模数据恢复,恢复速度比AOF快
- 对于灾难恢复来说是一个很好的选择
- 子进程负责持久化,主进程不进行任何IO操作,保证了Redis的高性能
缺点
- 可能会丢失最后一次持久化后的数据
- 数据量大时,fork子进程会导致服务短暂暂停
AOF持久化
原理
AOF(Append Only File)持久化以日志的形式记录服务器所处理的每一个写操作,以文本的方式记录,可以打开文件看到详细的操作记录。
触发方式
- 通过配置
appendonly yes
开启AOF持久化
- 可以设置同步策略(fsync):
1 2 3
| appendfsync always # 每次有数据修改发生时都会写入AOF文件,性能最差但数据最完整 appendfsync everysec # 每秒钟同步一次,推荐,性能和安全的折中 appendfsync no # 让操作系统决定何时进行同步,性能最好但数据最不安全
|
重写机制
AOF文件会随着时间越来越大,Redis提供了AOF重写功能,通过BGREWRITEAOF
命令用重写的方式来缩小AOF文件的体积。
优点
- 数据安全性高,支持秒级持久化
- 可读性高,AOF文件是纯文本,可以直接读懂
- 支持重写机制,文件体积可控
缺点
- 文件体积通常大于RDB文件
- 恢复速度比RDB慢
- 对性能影响较大,尤其是fsync策略为always时
持久化策略选择
仅使用RDB
- 适合数据相对不重要,可以容忍数分钟的数据丢失
- 追求高性能,数据集较大
仅使用AOF
- 对数据安全性要求较高,能承受较低的性能
- 可以接受AOF文件尺寸较大和恢复速度较慢
RDB + AOF混合使用(推荐)
- 同时开启RDB和AOF,Redis重启时优先使用AOF恢复数据,这样既保证了数据安全性,又具备RDB快照用于备份
- Redis 4.0引入了混合持久化,在AOF重写时,将重写这一刻之前的内存数据以RDB方式写入AOF文件头部,之后的操作再以AOF方式追加,兼具了RDB和AOF的优点
Redis事务
事务概念
Redis事务是一组命令的集合,可以一次执行多个命令,本质是一个命令队列。Redis事务具有以下特点:
- 批量操作:一次执行多个命令
- 顺序执行:事务中的命令按照添加顺序依次执行
- 隔离性:事务执行期间,其他客户端提交的命令不会插入到事务执行命令序列中
事务相关命令
Redis事务主要由以下命令组成:
- MULTI:标记一个事务块的开始
- EXEC:执行所有事务块内的命令
- DISCARD:取消事务,放弃执行事务块内的所有命令
- WATCH:监视一个或多个key,如果在事务执行之前这些key被其他命令所改动,那么事务将被打断
- UNWATCH:取消WATCH命令对所有key的监视
事务执行流程
- 开始事务:使用MULTI命令标记事务开始
- 命令入队:将多个命令加入到事务队列中,这些命令不会立即执行
- 执行事务:使用EXEC命令执行事务队列中的所有命令
1 2 3 4 5 6 7 8
| MULTI
SET user:1:name "Tom" SET user:1:age 25 INCR visitor_count
EXEC
|
事务中的错误处理
Redis事务中的错误分为两种:
- 编译时错误:命令入队时的错误,如语法错误。这种情况下,Redis会拒绝执行整个事务。
1 2 3 4
| MULTI SET user:1:name "Tom" SETNX user:1:age EXEC
|
- 运行时错误:命令执行时的错误,如对字符串执行数学运算。这种情况下,Redis会继续执行事务中的其他命令。
1 2 3 4 5
| MULTI SET user:1:name "Tom" INCR user:1:name SET user:1:age 25 EXEC
|
事务的ACID特性
Redis事务与传统数据库事务的区别:
- 原子性(Atomicity):Redis事务不保证原子性。如果事务中的某个命令执行失败,其他命令仍会被执行,不会回滚。
- 一致性(Consistency):Redis事务可以保证一致性,即执行事务前后数据库从一个一致性状态变换到另一个一致性状态。
- 隔离性(Isolation):Redis事务是完全隔离的,事务执行期间不会被其他命令打断。
- 持久性(Durability):取决于Redis的持久化配置,如果开启了AOF持久化且设置为always同步策略,则可以保证持久性。
事务与乐观锁(WATCH)
Redis提供了WATCH命令实现乐观锁,可以在EXEC执行之前,监视任意数量的key。如果在事务执行之前,这些key被其他命令所改动,那么事务将被打断。
1 2 3 4 5
| WATCH account:1 MULTI DECRBY account:1 100 INCRBY account:2 100 EXEC
|
分布式锁
适用场景
- 分布式系统中的资源竞争控制(如并发修改同一条数据、分布式任务调度)
- 避免重复执行(订单支付状态更新、库存扣减)
优势
- 实现简单:通过
SET key value NX EX
命令(仅当键不存在时设置,同时加过期时间)实现分布式锁,确保唯一性
- 安全性:过期时间防止锁持有者崩溃后锁永久有效(死锁)
1 2 3 4
| SET lock:order "12345" NX EX 10
if GET lock:order == "12345" then DEL lock:order
|
分布式锁的实现方式
基本实现
1 2 3 4 5
| SET resource_name unique_value NX PX 30000
eval "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 resource_name unique_value
|
进阶实现(Redlock算法)
对于高可用的分布式锁,可以使用Redlock算法,它通过多个Redis实例来避免单点故障:
- 获取当前时间(毫秒)
- 按顺序向N个Redis实例尝试获取锁
- 计算获取锁消耗的时间,如果成功获取锁的实例数量超过半数,并且获取锁消耗的时间小于锁的有效时间,则认为获取锁成功
- 如果获取锁失败,向所有Redis实例发送释放锁命令
Redis发布订阅
发布订阅概念
Redis的发布订阅(pub/sub)是一种消息通信模式:发送者(发布者)发送消息,订阅者接收消息。Redis客户端可以订阅任意数量的频道。
发布订阅相关命令
- SUBSCRIBE channel [channel …]:订阅一个或多个频道的消息
- PSUBSCRIBE pattern [pattern …]:订阅一个或多个符合给定模式的频道
- PUBLISH channel message:将信息发送到指定的频道
- UNSUBSCRIBE [channel [channel …]]:退订指定的频道
- PUNSUBSCRIBE [pattern [pattern …]]:退订所有给定模式的频道
- PUBSUB subcommand [argument [argument …]]:查看订阅与发布系统状态
发布订阅示例
1 2 3 4 5 6 7 8 9 10
| SUBSCRIBE channel1
PUBLISH channel1 "Hello Redis Pub/Sub"
1) "message" 2) "channel1" 3) "Hello Redis Pub/Sub"
|
发布订阅的特点
- 松耦合:发布者和订阅者之间没有直接联系,它们只关注频道
- 一对多:一个发布者可以向多个订阅者发送消息
- 即时性:消息发布后立即传递给订阅者
- 无持久化:Redis的发布订阅模式不支持持久化,如果订阅者断线,将会丢失断线期间的所有消息
应用场景
- 实时消息系统:如聊天室、实时通知
- 实时数据更新:如股票价格、体育比分更新
- 系统监控:服务器状态变化通知
- 任务分发:将任务分发给多个工作节点
与专业消息队列的比较
Redis的发布订阅功能相比专业的消息队列系统(如RabbitMQ、Kafka)有以下区别:
- 持久化:Redis的发布订阅不支持消息持久化,而专业MQ支持
- 消息确认:Redis没有消息确认机制,而专业MQ支持ACK确认
- 消息重试:Redis没有消息重试机制,而专业MQ支持
- 消息过滤:Redis支持简单的模式匹配,而专业MQ支持更复杂的过滤
Redis高级特性
Lua脚本
Redis支持使用Lua脚本来执行原子操作,通过EVAL命令可以执行Lua脚本。
优势
- 原子性:脚本的执行是原子性的,不会被其他命令打断
- 减少网络开销:将多个操作放在一个脚本中执行,减少网络往返
- 可复用:可以通过SCRIPT LOAD和EVALSHA复用脚本
示例
1 2 3 4 5
| EVAL "return redis.call('INCR', KEYS[1])" 1 counter
EVAL "local val = redis.call('GET', KEYS[1]); redis.call('DEL', KEYS[1]); return val" 1 mykey
|
管道(Pipeline)
管道技术可以在一次通信中执行多个命令,减少通信次数,提高性能。
优势
- 减少网络往返:一次性发送多个命令,减少网络延迟
- 提高吞吐量:批量处理命令,提高处理效率
与事务的区别
- 管道不保证原子性,而事务保证所有命令一起执行
- 管道不会被打断,但不保证命令的执行顺序
内存优化
数据结构优化
- 使用Hash存储对象,而不是String存储序列化的JSON
- 使用Bitmap代替Set来存储布尔值信息
- 使用HyperLogLog代替Set来统计唯一元素数量
内存淘汰策略
Redis提供了多种内存淘汰策略,可以在redis.conf中配置:
- noeviction:当内存不足时,新写入操作会报错
- allkeys-lru:从所有键中移除最近最少使用的键
- volatile-lru:从设置了过期时间的键中移除最近最少使用的键
- allkeys-random:从所有键中随机移除键
- volatile-random:从设置了过期时间的键中随机移除键
- volatile-ttl:从设置了过期时间的键中移除即将过期的键
性能优化
慢查询分析
Redis提供了慢查询日志功能,可以记录执行时间超过指定阈值的命令:
1 2 3 4 5 6 7 8
| CONFIG SET slowlog-log-slower-than 100
CONFIG SET slowlog-max-len 1000
SLOWLOG GET 10
|
持久化优化
- 使用RDB进行定期备份,AOF进行实时持久化
- 对于AOF,使用everysec同步策略,平衡性能和安全性
- 定期执行BGREWRITEAOF,控制AOF文件大小
连接优化
- 使用连接池复用连接,减少连接创建和销毁的开销
- 合理设置连接池大小,避免连接数过多导致资源浪费
高可用方案
主从复制
主从复制是Redis实现高可用的基础,一个主节点可以有多个从节点:
- 主节点负责写操作,从节点负责读操作,实现读写分离
- 从节点可以提升为主节点,实现故障转移
- 支持链式复制,从节点可以有自己的从节点
哨兵模式(Sentinel)
Redis Sentinel是Redis的高可用解决方案,提供自动故障转移、监控、通知等功能:
- 监控:监控主从节点是否正常运行
- 通知:当监控的节点出现问题时,通知管理员或其他程序
- 自动故障转移:当主节点不可用时,自动选择一个从节点升级为主节点
集群模式(Cluster)
Redis Cluster是Redis的分布式解决方案,支持数据自动分片和高可用:
- 数据自动分片:将数据自动分散到多个节点上
- 无中心架构:所有节点都是平等的,没有中心节点
- 高可用:部分节点不可用时,集群仍能继续提供服务
Redis最佳实践
键值设计
- 键名设计:使用冒号分隔的命名空间,如
user:1000:profile
- 避免大键:拆分大对象,避免一次性操作大量数据
- 设置过期时间:合理设置过期时间,避免内存持续增长
命令使用
- 避免使用
KEYS
命令,使用SCAN
命令代替
- 避免使用
FLUSHALL
、FLUSHDB
等危险命令
- 使用
MGET
、MSET
等批量操作命令提高效率
安全配置
- 设置密码认证
- 禁用危险命令
- 限制最大连接数
- 设置网络访问控制
监控指标
- 内存使用:used_memory、used_memory_rss
- 命令统计:total_commands_processed、instantaneous_ops_per_sec
- 连接数:connected_clients、rejected_connections
- 缓存命中率:keyspace_hits、keyspace_misses
- 持久化状态:rdb_last_save_time、aof_current_size
Redis
适合处理 高频访问、低延迟要求、结构简单 的数据,尤其在缓存、计数、队列、实时排行等场景中表现优异。实际使用时需结合业务需求(如数据量级、持久化要求、并发量),与其他数据库(如 MySQL
、Elasticsearch
)配合,构建高效的系统架构。
参考资料