1. 引言
Redis(Remote Dictionary Server)是一个基于内存的高性能键值存储系统,由 Salvatore Sanfilippo(网名 antirez)于 2009 年开发并开源。它以极低的延迟、丰富的数据结构和简洁的协议著称,被广泛应用于缓存、消息队列、分布式锁、排行榜、会话管理等场景。
根据 DB-Engines 的排名,Redis 长期位居键值存储数据库榜首,是后端开发者必须掌握的核心中间件之一。本文将从 Redis 的安装部署、核心数据结构、持久化机制、高可用架构、常见应用场景以及性能调优等方面,系统性地带你深入理解 Redis。
2. Redis 核心特性与适用场景
2.1 核心特性
- 基于内存存储:数据读写都在内存中完成,单线程模型下依然能支撑每秒十万级 QPS。
- 丰富的数据结构:支持 String、Hash、List、Set、ZSet(有序集合)、Bitmap、HyperLogLog、Geo、Stream 等。
- 持久化机制:提供 RDB 快照和 AOF 日志两种持久化方式,兼顾性能与数据安全。
- 高可用与分布式:支持主从复制、哨兵(Sentinel)模式以及 Redis Cluster 集群模式。
- 原子性操作:所有命令都是原子操作,配合 Lua 脚本可实现复杂事务逻辑。
- 发布订阅:内置 Pub/Sub 消息机制,支持简单的消息通信。
2.2 适用场景
| 场景 | 说明 | 典型数据结构 |
|---|---|---|
| 缓存 | 减轻数据库压力,提升读性能 | String、Hash |
| 分布式锁 | 多实例互斥访问共享资源 | String(SETNX) |
| 排行榜 | 按分数排序的实时榜单 | ZSet |
| 计数器 | 点赞数、访问量、库存扣减 | String(INCR) |
| 会话管理 | 分布式环境下的 Session 共享 | String、Hash |
| 消息队列 | 轻量级异步解耦 | List、Stream |
| 去重统计 | UV 统计、签到 | HyperLogLog、Bitmap |
| 附近的人 | 地理位置检索 | Geo |
3. Redis 安装与基础使用
3.1 安装方式
以 Ubuntu / Debian 系统为例,使用 apt 安装:
bash
sudo apt update
sudo apt install redis-server
以 CentOS / RHEL 系统为例:
bash
sudo yum install redis
使用 Docker 快速启动:
bash
docker run -d --name redis -p 6379:6379 redis:7.2
3.2 启动与连接
bash
# 启动服务
redis-server /etc/redis/redis.conf
# 连接客户端
redis-cli -h 127.0.0.1 -p 6379
# 验证连接
127.0.0.1:6379> PING
PONG
3.3 基础配置
Redis 的配置文件通常位于 /etc/redis/redis.conf,常用配置项如下:
conf
# 绑定地址
bind 127.0.0.1
# 端口
port 6379
# 是否以守护进程方式运行
daemonize yes
# 日志级别
loglevel notice
# 最大内存限制(超出后按淘汰策略处理)
maxmemory 256mb
# 内存淘汰策略
maxmemory-policy allkeys-lru
4. Redis 核心数据结构详解
4.1 String(字符串)
String 是 Redis 最基础的数据类型,可以存储字符串、整数或浮点数,最大容量为 512MB。
bash
# 设置与获取
SET user:name "zhangsan"
GET user:name
# 自增自减(计数器)
SET page:views 100
INCR page:views
DECR page:views
INCRBY page:views 50
# 设置过期时间
SET session:token "abc123" EX 3600
适用场景:缓存对象、计数器、分布式锁、限流。
4.2 Hash(哈希)
Hash 适合存储对象,每个 Hash 可以包含多个字段,内存占用比 String 序列化更优。
bash
# 存储用户信息
HSET user:1001 name "lisi" age 25 city "beijing"
HGET user:1001 name
HGETALL user:1001
# 批量操作
HMSET user:1002 name "wangwu" age 30
HMGET user:1002 name age
# 字段自增
HINCRBY user:1001 age 1
适用场景:存储对象属性、购物车、用户资料。
4.3 List(列表)
List 是双向链表结构,支持从两端插入和弹出元素,适合实现队列和栈。
bash
# 右侧入队(队列)
RPUSH task:queue "task1" "task2" "task3"
LPOP task:queue
# 左侧入队(栈)
LPUSH task:stack "job1"
LPOP task:stack
# 获取范围
LRANGE task:queue 0 -1
# 阻塞式弹出(实现阻塞队列)
BRPOP task:queue 5
适用场景:消息队列、最新消息列表、时间线。
4.4 Set(集合)
Set 是无序、去重的字符串集合,支持集合间的交、并、差运算。
bash
# 添加与查看
SADD user:1001:tags "java" "redis" "mysql"
SMEMBERS user:1001:tags
# 判断成员是否存在
SISMEMBER user:1001:tags "java"
# 集合运算
SADD user:1002:tags "java" "python"
SINTER user:1001:tags user:1002:tags # 交集
SUNION user:1001:tags user:1002:tags # 并集
SDIFF user:1001:tags user:1002:tags # 差集
适用场景:标签系统、好友关系、抽奖去重、共同关注。
4.5 ZSet(有序集合)
ZSet 在 Set 的基础上为每个元素关联一个分数(score),按分数排序,适合排行榜场景。
bash
# 添加成员及分数
ZADD leaderboard 100 "playerA" 85 "playerB" 92 "playerC"
# 按分数升序/降序获取
ZRANGE leaderboard 0 -1
ZREVRANGE leaderboard 0 -1
# 获取排名
ZRANK leaderboard "playerB"
ZREVRANK leaderboard "playerB"
# 分数增减
ZINCRBY leaderboard 10 "playerA"
# 按分数区间查询
ZRANGEBYSCORE leaderboard 80 100
适用场景:排行榜、延时队列、优先级队列。
4.6 高级数据结构
- Bitmap(位图):基于 String 的位操作,适合签到、在线状态统计。
- HyperLogLog:用于基数统计,误差约 0.81%,适合 UV 统计。
- Geo:存储地理位置,支持附近的人检索。
- Stream:Redis 5.0 引入的消息流,支持消费者组,适合可靠消息队列。
bash
# Bitmap 签到示例
SETBIT user:sign:20240101 0 1
GETBIT user:sign:20240101 0
# HyperLogLog UV 统计
PFADD uv:20240101 "user1" "user2" "user3"
PFCOUNT uv:20240101
# Geo 地理位置
GEOADD city:locations 116.40 39.90 "beijing"
GEOSEARCH city:locations FROMLONLAT 116.40 39.90 BYRADIUS 100 km
5. Redis 持久化机制
Redis 是内存数据库,为防止进程退出导致数据丢失,提供了两种持久化方案。
5.1 RDB(快照持久化)
RDB 通过定期生成内存数据的二进制快照文件(默认 dump.rdb)实现持久化。
触发方式:
- 手动执行
SAVE(阻塞)或BGSAVE(异步)。 - 满足配置的自动保存条件。
conf
# 900 秒内至少 1 次写操作则触发快照
save 900 1
save 300 10
save 60 10000
优点:文件紧凑、恢复速度快、适合备份。
缺点:可能丢失最后一次快照之后的数据;生成快照时若数据量大可能影响性能。
5.2 AOF(追加日志持久化)
AOF 将每次写命令追加到日志文件(默认 appendonly.aof),重启时通过重放命令恢复数据。
conf
# 开启 AOF
appendonly yes
# 同步策略:always / everysec / no
appendfsync everysec
同步策略对比:
| 策略 | 数据安全性 | 性能影响 |
|---|---|---|
| always | 每条命令都同步,最安全 | 性能最差 |
| everysec | 每秒同步一次,最多丢 1 秒数据 | 性能较好(推荐) |
| no | 由操作系统决定何时同步 | 性能最好,但可能丢较多数据 |
优点:数据安全性高,最多丢失 1 秒数据。
缺点:文件体积较大,恢复速度较慢。
5.3 混合持久化
Redis 4.0 起支持 RDB + AOF 混合持久化,AOF 文件头部为 RDB 快照,后续追加增量命令,兼顾恢复速度与数据安全。
conf
aof-use-rdb-preamble yes
6. Redis 高可用架构
6.1 主从复制
主从复制是 Redis 高可用的基础。主节点负责写操作,从节点同步数据并分担读压力。
conf
# 从节点配置
replicaof 192.168.1.10 6379
复制原理:
- 从节点发送
PSYNC命令请求同步。 - 主节点执行
BGSAVE生成 RDB 快照并发送给从节点。 - 从节点加载快照,主节点继续发送期间的增量写命令。
- 后续主节点将写命令实时推送给从节点。
6.2 哨兵模式(Sentinel)
哨兵模式用于监控主从架构,在主节点故障时自动完成故障转移,实现高可用。
conf
# sentinel.conf
sentinel monitor mymaster 192.168.1.10 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
启动哨兵:
bash
redis-sentinel /etc/redis/sentinel.conf
哨兵职责:
- 监控:持续检查主从节点是否正常。
- 通知:节点异常时通知管理员或其他程序。
- 自动故障转移:主节点宕机后,从从节点中选举新的主节点。
- 配置提供:客户端通过哨兵获取当前主节点地址。
6.3 Redis Cluster(集群模式)
Redis Cluster 是官方提供的分布式解决方案,支持数据分片和自动故障转移,适合海量数据场景。
核心特性:
- 数据自动分片到 16384 个哈希槽(slot)。
- 每个节点负责一部分槽位。
- 支持水平扩展,最多 1000 个节点。
- 部分节点故障时集群仍可用。
bash
# 创建集群(6 个节点,3 主 3 从)
redis-cli --cluster create \
192.168.1.10:7000 192.168.1.11:7000 192.168.1.12:7000 \
192.168.1.13:7000 192.168.1.14:7000 192.168.1.15:7000 \
--cluster-replicas 1
哈希槽分配 :每个 key 通过 CRC16(key) % 16384 计算所属槽位,槽位由对应节点负责。
7. Redis 常见应用场景实战
7.1 缓存穿透、击穿与雪崩
缓存穿透:查询不存在的数据,请求直接打到数据库。
解决方案:
- 缓存空值并设置较短过期时间。
- 使用布隆过滤器(Bloom Filter)前置过滤。
缓存击穿:热点 key 过期瞬间,大量请求同时打到数据库。
解决方案:
- 热点数据设置永不过期。
- 使用互斥锁(分布式锁)保证只有一个请求回源。
缓存雪崩:大量 key 在同一时间过期,导致数据库压力骤增。
解决方案:
- 过期时间加随机值,避免同时失效。
- 使用多级缓存(本地缓存 + Redis)。
- 服务降级与限流。
7.2 分布式锁
基于 Redis 实现分布式锁,使用 SETNX 加锁,DEL 释放锁,并设置过期时间防止死锁。
bash
# 加锁(原子操作)
SET lock:order:1001 "token-abc" NX EX 30
# 释放锁(使用 Lua 脚本保证原子性)
EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock:order:1001 "token-abc"
注意事项:
- 锁的 value 使用唯一标识,防止误删他人锁。
- 设置合理过期时间,避免业务未完成锁已过期。
- 生产环境建议使用 Redisson 等成熟客户端。
7.3 消息队列
使用 List 实现简单的生产者-消费者模式:
bash
# 生产者
LPUSH msg:queue "hello"
# 消费者(阻塞式)
BRPOP msg:queue 0
使用 Stream 实现更可靠的消息队列,支持消费者组和消息确认:
bash
# 生产者
XADD stream:orders * orderId "1001" amount "99.9"
# 创建消费者组
XGROUP CREATE stream:orders group1 0
# 消费者读取
XREADGROUP GROUP group1 consumer1 COUNT 1 STREAMS stream:orders >
7.4 排行榜
使用 ZSet 实现实时排行榜:
bash
# 用户得分更新
ZINCRBY game:rank 10 "playerA"
# 获取 Top 10
ZREVRANGE game:rank 0 9 WITHSCORES
# 获取用户排名
ZREVRANK game:rank "playerA"
8. Redis 性能优化与最佳实践
8.1 内存优化
- 使用 Hash 替代大量 String 存储对象,减少内存碎片。
- 合理设置
maxmemory和淘汰策略。 - 使用
MEMORY USAGE key查看 key 内存占用。 - 定期清理过期 key 和无效数据。
8.2 命令优化
- 使用 Pipeline 批量发送命令,减少网络 RTT。
- 使用
MGET、MSET批量操作替代循环单条命令。 - 避免使用
KEYS命令(会阻塞),改用SCAN游标遍历。 - 大 key 拆分,避免单 key 过大导致阻塞。
8.3 连接管理
- 客户端使用连接池,避免频繁创建连接。
- 合理设置连接超时和空闲回收时间。
- 监控连接数,防止连接泄漏。
8.4 监控与告警
常用监控指标:
- 内存使用率(
INFO memory)。 - 命中率(
INFO stats中的keyspace_hits/keyspace_misses)。 - 连接数(
INFO clients)。 - 慢查询日志(
SLOWLOG GET)。
bash
# 查看慢查询
SLOWLOG GET 10
# 设置慢查询阈值(微秒)
CONFIG SET slowlog-log-slower-than 10000
9. 总结
Redis 作为高性能内存数据库,凭借丰富的数据结构、灵活的持久化机制和完善的高可用方案,已成为现代后端架构中不可或缺的组件。本文从安装部署、核心数据结构、持久化、高可用架构到实战场景,系统性地梳理了 Redis 的核心知识体系。
在实际项目中,建议根据业务场景合理选择数据结构,重视缓存一致性、内存管理和高可用设计,并结合监控体系持续优化。希望本文能帮助你从入门到实战全面掌握 Redis。