Redis 教程:从入门到精通
Redis 是一个开源的、基于内存的高性能键值数据库,被广泛应用于缓存、会话存储、消息队列等场景。本教程将帮助你全面了解 Redis 的核心概念和使用方法。
Redis 简介
什么是 Redis?
Redis(Remote Dictionary Server)是一个开源的、基于内存的数据结构存储系统,可以用作数据库、缓存和消息中间件。它支持多种数据类型,如字符串、哈希表、列表、集合、有序集合等,并且提供了丰富的操作命令。
Redis 的主要特点
- 高性能:基于内存操作,读写速度极快
- 丰富的数据类型:支持字符串、哈希、列表、集合、有序集合等
- 原子操作:所有操作都是原子性的,支持事务
- 持久化:支持数据持久化到磁盘(RDB 和 AOF)
- 主从复制:支持主从复制和高可用
- 分布式:支持集群模式,可水平扩展
- Lua 脚本:支持 Lua 脚本执行复杂操作
- 发布/订阅:支持消息的发布与订阅
Redis 与传统数据库的比较
特性 | Redis | 关系型数据库 |
---|---|---|
数据模型 | 键值存储 | 表格关系模型 |
存储方式 | 内存(可持久化) | 磁盘 |
查询语言 | 简单命令 | SQL |
事务支持 | 基本支持 | 完全支持 |
性能 | 极高 | 中等 |
扩展性 | 主从复制、集群 | 主从复制、分库分表 |
适用场景 | 缓存、会话、计数器、排行榜 | 复杂查询、事务处理 |
Redis 安装与配置
安装 Redis
在 Linux 上安装
# Ubuntu/Debian
sudo apt update
sudo apt install redis-server
# CentOS/RHEL
sudo yum install epel-release
sudo yum install redis
在 macOS 上安装
brew install redis
在 Windows 上安装
Windows 不是 Redis 的官方支持平台,但可以通过以下方式使用:
- 使用 WSL(Windows Subsystem for Linux)
- 使用 Docker 容器
- 使用非官方的 Windows 版本:Microsoft Redis
使用 Docker 安装
docker pull redis
docker run --name my-redis -p 6379:6379 -d redis
基本配置
Redis 的配置文件通常位于 /etc/redis/redis.conf
(Linux)或 /usr/local/etc/redis.conf
(macOS)。以下是一些重要的配置项:
# 绑定地址
bind 127.0.0.1
# 端口
port 6379
# 密码保护
requirepass yourpassword
# 最大内存
maxmemory 100mb
# 内存策略
maxmemory-policy allkeys-lru
# 持久化配置
save 900 1
save 300 10
save 60 10000
启动与停止 Redis
# 启动 Redis 服务
sudo systemctl start redis # Linux
brew services start redis # macOS
# 停止 Redis 服务
sudo systemctl stop redis # Linux
brew services stop redis # macOS
# 重启 Redis 服务
sudo systemctl restart redis # Linux
brew services restart redis # macOS
Redis 数据类型与命令
Redis 支持多种数据类型,每种类型都有其特定的使用场景和操作命令。
连接到 Redis
使用 Redis CLI 连接到 Redis 服务器:
redis-cli
# 如果设置了密码
redis-cli -a yourpassword
# 连接到远程服务器
redis-cli -h host -p port -a password
字符串(String)
字符串是 Redis 最基本的数据类型,可以存储文本、整数或二进制数据。
基本命令
# 设置键值
SET key value
# 获取键值
GET key
# 设置键值并指定过期时间(秒)
SETEX key seconds value
# 设置键值并指定过期时间(毫秒)
PSETEX key milliseconds value
# 只在键不存在时设置值
SETNX key value
# 获取值的长度
STRLEN key
# 一次设置多个键值
MSET key1 value1 key2 value2
# 一次获取多个键值
MGET key1 key2
# 删除键
DEL key
# 检查键是否存在
EXISTS key
# 设置过期时间(秒)
EXPIRE key seconds
# 查看剩余过期时间(秒)
TTL key
数值操作
# 将值递增1
INCR key
# 将值递增指定整数
INCRBY key increment
# 将值递增指定浮点数
INCRBYFLOAT key increment
# 将值递减1
DECR key
# 将值递减指定整数
DECRBY key decrement
应用场景
- 缓存:存储页面、API 响应等
- 计数器:如访问次数、点赞数
- 分布式锁:使用 SETNX 实现
- 会话存储:存储用户会话信息
哈希(Hash)
哈希类型是字段和值的映射表,适合存储对象。
基本命令
# 设置哈希表字段的值
HSET key field value
# 获取哈希表字段的值
HGET key field
# 设置多个哈希表字段的值
HMSET key field1 value1 field2 value2
# 获取多个哈希表字段的值
HMGET key field1 field2
# 获取哈希表中所有字段和值
HGETALL key
# 获取哈希表中所有字段
HKEYS key
# 获取哈希表中所有值
HVALS key
# 检查哈希表中是否存在指定字段
HEXISTS key field
# 删除哈希表中的一个或多个字段
HDEL key field1 [field2]
# 获取哈希表中字段的数量
HLEN key
# 为哈希表中的字段值加上增量
HINCRBY key field increment
# 为哈希表中的字段值加上浮点数增量
HINCRBYFLOAT key field increment
应用场景
- 用户信息存储:每个用户 ID 对应一个哈希表,字段为用户属性
- 购物车:用户 ID 作为键,商品 ID 为字段,数量为值
- 配置信息:应用配置、系统参数等
- 缓存对象:缓存数据库查询结果
列表(List)
列表是简单的字符串列表,按照插入顺序排序,可以从头部或尾部添加元素。
基本命令
# 将一个或多个值插入到列表头部
LPUSH key value1 [value2]
# 将一个或多个值插入到列表尾部
RPUSH key value1 [value2]
# 移除并返回列表的第一个元素
LPOP key
# 移除并返回列表的最后一个元素
RPOP key
# 获取列表指定范围内的元素
LRANGE key start stop
# 获取列表长度
LLEN key
# 通过索引获取列表中的元素
LINDEX key index
# 在列表的元素前或后插入元素
LINSERT key BEFORE|AFTER pivot value
# 设置列表指定索引位置的值
LSET key index value
# 移除列表中与参数 value 相等的元素
LREM key count value
# 对一个列表进行修剪,只保留指定区间内的元素
LTRIM key start stop
应用场景
- 消息队列:生产者使用 RPUSH,消费者使用 LPOP
- 最新动态:如社交网络的时间线
- 任务队列:待处理的任务列表
- 最近浏览记录:保存用户最近浏览的商品
集合(Set)
集合是字符串类型的无序集合,集合成员是唯一的。
基本命令
# 添加一个或多个成员到集合
SADD key member1 [member2]
# 获取集合的所有成员
SMEMBERS key
# 判断成员是否是集合的成员
SISMEMBER key member
# 获取集合的成员数
SCARD key
# 移除集合中一个或多个成员
SREM key member1 [member2]
# 随机返回集合中的一个成员
SRANDMEMBER key [count]
# 随机移除并返回集合中的一个成员
SPOP key [count]
# 返回给定所有集合的交集
SINTER key1 [key2]
# 返回给定所有集合的并集
SUNION key1 [key2]
# 返回给定所有集合的差集
SDIFF key1 [key2]
# 将给定集合的交集存储在目标集合中
SINTERSTORE destination key1 [key2]
# 将给定集合的并集存储在目标集合中
SUNIONSTORE destination key1 [key2]
# 将给定集合的差集存储在目标集合中
SDIFFSTORE destination key1 [key2]
应用场景
- 用户标签:存储用户的兴趣爱好、技能等
- 好友关系:存储用户的好友、关注者
- 唯一性检查:如邮箱地址、用户名的唯一性
- 黑名单/白名单:IP 地址、用户 ID 等
有序集合(Sorted Set)
有序集合与集合类似,但每个成员关联一个分数,用于排序。
基本命令
# 添加一个或多个成员到有序集合,或更新已存在成员的分数
ZADD key score1 member1 [score2 member2]
# 获取有序集合的成员数
ZCARD key
# 计算有序集合中指定分数范围的成员数
ZCOUNT key min max
# 获取有序集合中指定成员的分数
ZSCORE key member
# 获取有序集合中指定成员的排名(按分数从小到大)
ZRANK key member
# 获取有序集合中指定成员的排名(按分数从大到小)
ZREVRANK key member
# 获取有序集合中指定范围的成员(按分数从小到大)
ZRANGE key start stop [WITHSCORES]
# 获取有序集合中指定范围的成员(按分数从大到小)
ZREVRANGE key start stop [WITHSCORES]
# 获取有序集合中指定分数范围的成员
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
# 移除有序集合中的一个或多个成员
ZREM key member1 [member2]
# 移除有序集合中指定排名范围的所有成员
ZREMRANGEBYRANK key start stop
# 移除有序集合中指定分数范围的所有成员
ZREMRANGEBYSCORE key min max
# 为有序集合中的成员增加分数
ZINCRBY key increment member
应用场景
- 排行榜:如游戏积分榜、热门文章
- 优先级队列:按优先级处理任务
- 延迟队列:按时间戳排序的任务
- 权重搜索:按相关性排序的搜索结果
Redis 高级特性
事务
Redis 事务允许在一个步骤中执行一组命令,保证所有命令要么全部执行,要么全部不执行。
# 标记一个事务块的开始
MULTI
# 执行所有事务块内的命令
EXEC
# 取消事务,放弃执行事务块内的所有命令
DISCARD
# 监视一个或多个键,如果在事务执行之前这些键被修改,那么事务将被打断
WATCH key1 [key2]
# 取消对所有键的监视
UNWATCH
注意:Redis 的事务不支持回滚操作,如果事务中的某个命令执行失败,其他命令仍会被执行。
发布/订阅
Redis 的发布/订阅功能允许客户端订阅频道,当有消息发布到这些频道时,所有订阅者都会收到消息。
# 订阅一个或多个频道
SUBSCRIBE channel1 [channel2]
# 退订一个或多个频道
UNSUBSCRIBE [channel1 [channel2]]
# 订阅一个或多个符合给定模式的频道
PSUBSCRIBE pattern1 [pattern2]
# 退订一个或多个符合给定模式的频道
PUNSUBSCRIBE [pattern1 [pattern2]]
# 将信息发送到指定的频道
PUBLISH channel message
# 查看订阅与发布系统状态
PUBSUB subcommand [argument [argument ...]]
Lua 脚本
Redis 支持使用 Lua 脚本执行复杂的操作,脚本在 Redis 中是原子性的。
# 执行 Lua 脚本
EVAL script numkeys key1 [key2 ...] arg1 [arg2 ...]
# 执行已缓存的 Lua 脚本
EVALSHA sha1 numkeys key1 [key2 ...] arg1 [arg2 ...]
# 将脚本加入脚本缓存
SCRIPT LOAD script
# 查看脚本是否已被缓存
SCRIPT EXISTS sha1 [sha2 ...]
# 清除所有脚本缓存
SCRIPT FLUSH
# 杀死当前正在运行的脚本
SCRIPT KILL
位图操作
Redis 的位图操作允许对字符串值进行位级操作,适用于需要处理位级数据的场景。
# 对 key 所储存的字符串值,设置或清除指定偏移量上的位
SETBIT key offset value
# 获取 key 所储存的字符串值,获取指定偏移量上的位
GETBIT key offset
# 计算给定字符串中,被设置为 1 的比特位的数量
BITCOUNT key [start end]
# 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上
BITOP operation destkey key1 [key2 ...]
# 返回字符串里面第一个被设置为 1 或 0 的 bit 位
BITPOS key bit [start] [end]
Redis 持久化
Redis 提供了多种持久化选项,以确保数据在服务器重启后不会丢失。
RDB(Redis Database)
RDB 持久化通过创建数据库快照(snapshot)来保存数据。
配置选项
# 900秒(15分钟)内有1个更改
save 900 1
# 300秒(5分钟)内有10个更改
save 300 10
# 60秒内有10000个更改
save 60 10000
# 文件名称
dbfilename dump.rdb
# 是否压缩
rdbcompression yes
# 导出 RDB 文件时是否进行校验和检验
rdbchecksum yes
# 工作目录
dir ./
手动触发
# 创建 RDB 快照
SAVE
# 异步创建 RDB 快照
BGSAVE
优缺点
优点:
- 适合备份和灾难恢复
- 单个紧凑的文件,方便传输
- 性能影响小,fork 子进程执行
- 恢复速度快
缺点:
- 可能会丢失最后一次快照之后的数据
- fork 进程时可能会导致服务短暂停顿
AOF(Append Only File)
AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时重新执行这些命令来恢复数据。
配置选项
# 是否开启 AOF
appendonly yes
# 文件名称
appendfilename "appendonly.aof"
# 同步策略
# always:每个写命令都同步
# everysec:每秒同步一次(默认)
# no:由操作系统决定何时同步
appendfsync everysec
# 重写时是否同步
no-appendfsync-on-rewrite no
# 自动重写触发条件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
手动触发重写
# 手动触发 AOF 重写
BGREWRITEAOF
优缺点
优点:
- 更好的持久性,支持不同的同步策略
- 文件以追加方式记录,不会因为断电而损坏
- 当文件过大时,会自动在后台重写
缺点:
- AOF 文件通常比 RDB 文件大
- 根据同步策略的不同,AOF 可能比 RDB 慢
- 恢复数据时相对较慢
混合持久化
Redis 4.0 引入了混合持久化,结合了 RDB 和 AOF 的优点。
# 开启混合持久化(Redis 4.0+)
aof-use-rdb-preamble yes
在这种模式下,AOF 重写时会先以 RDB 格式写入数据,然后再将重写期间的增量命令以 AOF 格式追加到文件末尾。这样既保证了恢复速度,又尽可能保证了数据安全性。
Redis 复制与高可用
主从复制
Redis 支持主从复制功能,可以让多个 Redis 服务器拥有相同的数据副本。
配置主从复制
在从服务器的配置文件中添加:
# 指定主服务器的 IP 和端口
replicaof <masterip> <masterport>
# 如果主服务器设置了密码,需要配置密码
masterauth <master-password>
# 是否允许从服务器在复制过程中响应读请求
replica-serve-stale-data yes
# 从服务器是否只读
replica-read-only yes
或者在运行时使用命令:
REPLICAOF <masterip> <masterport>
# 取消复制,使从服务器变为主服务器
REPLICAOF NO ONE
复制原理
- 全量复制:从服务器连接主服务器时,主服务器会创建 RDB 文件并发送给从服务器
- 部分复制:在断线重连后,主服务器只发送断线期间的写命令
- 异步复制:主服务器不会等待从服务器确认,可能导致数据不一致
Sentinel(哨兵)
Sentinel 是 Redis 的高可用解决方案,用于监控、通知和自动故障转移。
配置 Sentinel
创建 sentinel.conf
文件:
# 监控名为 mymaster 的主服务器,至少需要 2 个 Sentinel 同意才能进行故障转移
sentinel monitor mymaster 127.0.0.1 6379 2
# 主服务器或从服务器多长时间无响应视为下线(毫秒)
sentinel down-after-milliseconds mymaster 30000
# 故障转移超时时间(毫秒)
sentinel failover-timeout mymaster 180000
# 同时进行故障转移的从服务器数量
sentinel parallel-syncs mymaster 1
# 如果主服务器设置了密码
sentinel auth-pass mymaster password
启动 Sentinel:
redis-sentinel /path/to/sentinel.conf
# 或者
redis-server /path/to/sentinel.conf --sentinel
Sentinel 工作原理
- 监控:定期检查主从服务器是否正常运行
- 通知:当被监控的服务器出现问题时,通过 API 通知系统管理员
- 自动故障转移:当主服务器不可用时,选择一个从服务器升级为主服务器
- 配置提供者:客户端连接 Sentinel 获取当前主服务器地址
Redis Cluster
Redis Cluster 是 Redis 的分布式解决方案,支持数据自动分片和高可用性。
配置 Redis Cluster
在每个节点的配置文件中添加:
# 开启集群模式
cluster-enabled yes
# 集群配置文件(自动生成)
cluster-config-file nodes-6379.conf
# 节点超时时间(毫秒)
cluster-node-timeout 15000
# 是否需要所有槽都分配后集群才能上线
cluster-require-full-coverage yes
创建集群:
# Redis 5.0+ 版本
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1
Redis Cluster 工作原理
- 数据分片:使用哈希槽(hash slot)机制,共 16384 个槽
- 节点通信:使用 Gossip 协议进行节点间通信
- 故障检测:节点间互相监控,当主节点故障时,从节点会被提升为主节点
- 请求重定向:当客户端访问的键不在当前节点时,会返回 MOVED 或 ASK 错误进行重定向
Redis 性能优化
内存优化
合理设置 maxmemory:根据服务器可用内存设置 Redis 最大内存使用量
maxmemory 2gb
选择合适的内存淘汰策略:
# 当内存达到上限时的淘汰策略 maxmemory-policy allkeys-lru # 所有键基于LRU算法淘汰 # 其他选项: # volatile-lru:从设置了过期时间的键中选择最久未使用的键淘汰 # allkeys-lru:从所有键中选择最久未使用的键淘汰 # volatile-lfu:从设置了过期时间的键中选择最少使用的键淘汰 # allkeys-lfu:从所有键中选择最少使用的键淘汰 # volatile-random:从设置了过期时间的键中随机选择键淘汰 # allkeys-random:从所有键中随机选择键淘汰 # volatile-ttl:从设置了过期时间的键中选择将要过期的键淘汰 # noeviction:不淘汰键,写入操作会报错
使用 Redis 数据结构压缩:
# 启用列表压缩 list-compress-depth 1 # 启用哈希压缩 hash-max-ziplist-entries 512 hash-max-ziplist-value 64
持久化优化
调整 RDB 保存频率:
# 减少保存频率,降低磁盘 I/O save 900 1 save 300 10 save 60 10000
AOF 重写优化:
# 增加重写触发阈值 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
选择合适的 AOF 同步策略:
# 每秒同步一次,平衡性能和数据安全 appendfsync everysec
连接优化
设置合理的连接数上限:
# 最大客户端连接数 maxclients 10000
启用 TCP keepalive:
# 检测死连接 tcp-keepalive 300
调整 TCP 缓冲区大小:
# 客户端输出缓冲区限制 client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60
命令优化
- 使用批量操作:使用 MSET、MGET 等批量命令代替多次单个操作
- 使用 Pipeline:将多个命令打包一次发送,减少网络往返
- 使用 Lua 脚本:将复杂操作封装在 Lua 脚本中,减少网络交互
- 避免使用高耗时命令:如 KEYS、SORT、LRANGE 等
Redis 安全最佳实践
设置强密码:
requirepass complex_password_here
禁用危险命令:
rename-command FLUSHALL "" rename-command FLUSHDB "" rename-command CONFIG ""
绑定特定 IP:
bind 127.0.0.1 192.168.1.100
启用 TLS 加密(Redis 6.0+):
tls-port 6379 tls-cert-file /path/to/cert.pem tls-key-file /path/to/key.pem tls-ca-cert-file /path/to/ca.pem
设置访问控制列表(Redis 6.0+):
# 创建用户 ACL SETUSER alice on >password ~* +@all -@dangerous
Redis 常见问题与解决方案
内存占用过高
分析内存使用情况:
bash# 查看内存使用情况 INFO memory # 分析键的内存占用 MEMORY USAGE key
解决方案:
- 设置合理的过期时间
- 使用更紧凑的数据结构
- 增加内存或分片数据
性能下降
分析慢查询:
bash# 查看慢查询日志 SLOWLOG GET 10
解决方案:
- 优化数据结构和命令
- 使用 Pipeline 减少网络往返
- 考虑使用 Redis Cluster 分担负载
持久化问题
RDB 保存失败:
- 检查磁盘空间
- 调整保存频率
- 监控 fork 时间
AOF 文件过大:
- 定期执行 BGREWRITEAOF
- 调整自动重写参数
总结
Redis 是一个功能强大、高性能的内存数据库,广泛应用于缓存、会话管理、消息队列等场景。通过本教程,我们学习了 Redis 的基本概念、数据类型、高级特性、持久化、复制、集群以及性能优化等内容。
希望这份教程能帮助你更好地理解和使用 Redis,充分发挥其在应用开发中的价值。
参考资源
本文档将持续更新,如有问题请通过 GitHub Issues 反馈。
安装与配置
在不同平台上安装 Redis
Linux (Ubuntu/Debian)
# 更新包列表
sudo apt update
# 安装 Redis
sudo apt install redis-server
# 启动 Redis 服务
sudo systemctl start redis-server
# 设置开机自启
sudo systemctl enable redis-server
# 检查 Redis 状态
sudo systemctl status redis-server
macOS
使用 Homebrew 安装:
# 安装 Homebrew(如果尚未安装)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 安装 Redis
brew install redis
# 启动 Redis 服务
brew services start redis
# 检查 Redis 状态
brew services info redis
Windows
Windows 不是 Redis 的官方支持平台,但可以通过以下方式使用:
- 使用 WSL(Windows Subsystem for Linux)安装 Linux 版本的 Redis
- 使用 Microsoft 的 Redis 分支
- 使用 Docker 运行 Redis 容器
Docker
# 拉取 Redis 镜像
docker pull redis:latest
# 运行 Redis 容器
docker run --name my-redis -p 6379:6379 -d redis
# 连接到 Redis 容器
docker exec -it my-redis redis-cli
基本配置
Redis 的配置文件通常位于 /etc/redis/redis.conf
(Linux)或 /usr/local/etc/redis.conf
(macOS)。以下是一些重要的配置项:
# 绑定地址(默认只允许本地连接)
bind 127.0.0.1
# 端口
port 6379
# 密码认证
requirepass yourpassword
# 最大内存限制
maxmemory 100mb
# 内存淘汰策略
maxmemory-policy allkeys-lru
# 持久化配置
save 900 1 # 900秒内至少有1个key变化,则触发保存
save 300 10 # 300秒内至少有10个key变化,则触发保存
save 60 10000 # 60秒内至少有10000个key变化,则触发保存
# AOF 持久化
appendonly yes
appendfilename "appendonly.aof"
连接到 Redis
# 本地连接
redis-cli
# 远程连接
redis-cli -h host -p port -a password
# 使用密码连接
redis-cli
> AUTH yourpassword
Redis 数据类型
字符串(String)
字符串是 Redis 最基本的数据类型,可以存储文本、整数或二进制数据。
# 设置字符串
SET key value
SET name "John Doe"
SET counter 100
# 获取字符串
GET key
GET name # 返回 "John Doe"
# 设置过期时间(秒)
SETEX key seconds value
SETEX session 3600 "user123"
# 原子递增/递减
INCR counter # 将 counter 加 1
INCRBY counter 10 # 将 counter 加 10
DECR counter # 将 counter 减 1
DECRBY counter 5 # 将 counter 减 5
# 同时设置/获取多个值
MSET key1 value1 key2 value2
MGET key1 key2
哈希(Hash)
哈希是字段和值的映射,适合存储对象。
# 设置哈希字段
HSET key field value
HSET user:1000 name "John Doe"
HSET user:1000 email "john@example.com"
HSET user:1000 age 30
# 获取哈希字段
HGET key field
HGET user:1000 name # 返回 "John Doe"
# 获取所有字段和值
HGETALL key
HGETALL user:1000
# 检查字段是否存在
HEXISTS key field
HEXISTS user:1000 name # 返回 1(存在)
# 删除字段
HDEL key field [field ...]
HDEL user:1000 age
# 增加数字
HINCRBY key field increment
HINCRBY user:1000 age 5 # 将 age 增加 5
列表(List)
列表是简单的字符串列表,按照插入顺序排序。
# 从左侧插入元素
LPUSH key value [value ...]
LPUSH mylist "world"
LPUSH mylist "hello"
# 从右侧插入元素
RPUSH key value [value ...]
RPUSH mylist "!"
# 获取列表范围
LRANGE key start stop
LRANGE mylist 0 -1 # 获取所有元素,返回 ["hello", "world", "!"]
# 从左侧弹出元素
LPOP key
LPOP mylist # 返回 "hello"
# 从右侧弹出元素
RPOP key
RPOP mylist # 返回 "!"
# 获取列表长度
LLEN key
LLEN mylist # 返回 1
# 根据索引获取元素
LINDEX key index
LINDEX mylist 0 # 返回 "world"
集合(Set)
集合是字符串的无序集合,不允许重复成员。
# 添加成员
SADD key member [member ...]
SADD myset "apple"
SADD myset "banana" "orange"
# 获取所有成员
SMEMBERS key
SMEMBERS myset # 返回 ["apple", "banana", "orange"]
# 判断成员是否存在
SISMEMBER key member
SISMEMBER myset "apple" # 返回 1(存在)
# 获取集合成员数
SCARD key
SCARD myset # 返回 3
# 删除成员
SREM key member [member ...]
SREM myset "banana"
# 集合操作
SUNION key [key ...] # 并集
SINTER key [key ...] # 交集
SDIFF key [key ...] # 差集
有序集合(Sorted Set)
有序集合类似于集合,但每个成员关联一个分数,用于排序。
# 添加成员和分数
ZADD key score member [score member ...]
ZADD leaderboard 100 "user1"
ZADD leaderboard 85 "user2" 95 "user3"
# 获取成员排名(从小到大)
ZRANK key member
ZRANK leaderboard "user1" # 返回 2
# 获取成员排名(从大到小)
ZREVRANK key member
ZREVRANK leaderboard "user1" # 返回 0
# 获取指定排名范围的成员
ZRANGE key start stop [WITHSCORES]
ZRANGE leaderboard 0 -1 # 返回 ["user2", "user3", "user1"]
ZRANGE leaderboard 0 -1 WITHSCORES # 返回 ["user2", "85", "user3", "95", "user1", "100"]
# 获取指定分数范围的成员
ZRANGEBYSCORE key min max [WITHSCORES]
ZRANGEBYSCORE leaderboard 90 100 # 返回 ["user3", "user1"]
# 增加成员分数
ZINCRBY key increment member
ZINCRBY leaderboard 10 "user2" # 将 user2 的分数增加 10
# 获取成员数量
ZCARD key
ZCARD leaderboard # 返回 3
# 获取成员分数
ZSCORE key member
ZSCORE leaderboard "user1" # 返回 "100"
位图(Bitmap)
位图不是独立的数据类型,而是基于字符串的位操作。
# 设置位
SETBIT key offset value
SETBIT users:active 123 1 # 将用户ID为123的用户标记为活跃
# 获取位
GETBIT key offset
GETBIT users:active 123 # 返回 1
# 统计位图中值为1的位数
BITCOUNT key [start end]
BITCOUNT users:active # 返回活跃用户数
# 位操作
BITOP operation destkey key [key ...]
BITOP AND result users:active:week1 users:active:week2 # 两周都活跃的用户
HyperLogLog
HyperLogLog 用于估计集合中不重复元素的数量,占用空间极小。
# 添加元素
PFADD key element [element ...]
PFADD visitors user1 user2 user3
# 获取基数估计
PFCOUNT key [key ...]
PFCOUNT visitors # 返回 3
# 合并多个 HyperLogLog
PFMERGE destkey sourcekey [sourcekey ...]
PFMERGE total_visitors daily_visitors weekly_visitors
地理空间(Geo)
地理空间用于存储地理位置信息。
# 添加地理位置
GEOADD key longitude latitude member [longitude latitude member ...]
GEOADD locations 116.40 39.90 "Beijing" 121.47 31.23 "Shanghai"
# 计算两地距离
GEODIST key member1 member2 [unit]
GEODIST locations "Beijing" "Shanghai" km # 返回两地距离(千米)
# 获取坐标
GEOPOS key member [member ...]
GEOPOS locations "Beijing" # 返回北京的经纬度
# 查找指定范围内的位置
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
GEORADIUS locations 116.40 39.90 1000 km # 返回北京1000公里范围内的城市
流(Stream)
流是 Redis 5.0 引入的新数据类型,用于消息队列。
# 添加消息
XADD key ID field value [field value ...]
XADD mystream * sensor-id 1234 temperature 19.8
# 读取消息
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
XREAD COUNT 2 STREAMS mystream 0 # 从头开始读取最多2条消息
# 创建消费者组
XGROUP CREATE key groupname ID
XGROUP CREATE mystream mygroup $ # $ 表示从最新消息开始
# 消费者组读取
XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
XREADGROUP GROUP mygroup consumer1 STREAMS mystream > # > 表示未被组内消费的消息
Redis 高级特性
事务
Redis 事务允许在一个步骤中执行一组命令。
# 开始事务
MULTI
# 命令入队
SET user:1:name "John"
SET user:1:email "john@example.com"
INCR visitors
# 执行事务
EXEC
# 取消事务
DISCARD
发布/订阅
Redis 提供了发布/订阅功能,用于消息通信。
# 订阅频道
SUBSCRIBE channel [channel ...]
SUBSCRIBE news
# 发布消息
PUBLISH channel message
PUBLISH news "Breaking news!"
# 模式订阅
PSUBSCRIBE pattern [pattern ...]
PSUBSCRIBE news.*
# 取消订阅
UNSUBSCRIBE [channel [channel ...]]
PUNSUBSCRIBE [pattern [pattern ...]]
Lua 脚本
Redis 支持使用 Lua 脚本执行复杂操作。
# 执行 Lua 脚本
EVAL script numkeys key [key ...] arg [arg ...]
# 示例:原子计数器
EVAL "local current = redis.call('get', KEYS[1]) or 0; \
local new = tonumber(current) + tonumber(ARGV[1]); \
redis.call('set', KEYS[1], new); \
return new;" 1 counter 5
# 加载脚本到缓存
SCRIPT LOAD "return redis.call('get', KEYS[1])"
# 返回 SHA1 校验和,如 "a42059b356c875f0717db19a51f6aaca9ae659ea"
# 使用缓存的脚本
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
EVALSHA "a42059b356c875f0717db19a51f6aaca9ae659ea" 1 mykey
管道(Pipeline)
管道允许一次性发送多个命令,减少网络往返时间。
# 使用 redis-cli 的管道模式
echo -e "SET key1 value1\nSET key2 value2\nGET key1\nGET key2" | redis-cli --pipe
在编程语言中使用管道:
# Python 示例
import redis
r = redis.Redis()
pipe = r.pipeline()
pipe.set('key1', 'value1')
pipe.set('key2', 'value2')
pipe.get('key1')
pipe.get('key2')
results = pipe.execute()
Redis 持久化
RDB(Redis Database)
RDB 通过创建数据快照实现持久化。
# redis.conf 配置
save 900 1 # 900秒内至少有1个key变化,则触发保存
save 300 10 # 300秒内至少有10个key变化,则触发保存
save 60 10000 # 60秒内至少有10000个key变化,则触发保存
dbfilename dump.rdb # RDB 文件名
dir ./ # RDB 文件存储路径
手动触发 RDB:
# 同步保存
SAVE
# 异步保存
BGSAVE
AOF(Append Only File)
AOF 通过记录所有写操作命令实现持久化。
# redis.conf 配置
appendonly yes
appendfilename "appendonly.aof"
# 同步策略
appendfsync always # 每个写命令都同步,最安全,最慢
appendfsync everysec # 每秒同步一次,平衡安全和性能
appendfsync no # 由操作系统决定何时同步,最快,最不安全
AOF 重写(压缩 AOF 文件):
# 手动触发 AOF 重写
BGREWRITEAOF
混合持久化
Redis 4.0 引入了混合持久化,结合了 RDB 和 AOF 的优点。
# redis.conf 配置
aof-use-rdb-preamble yes
Redis 复制与高可用
主从复制
主从复制允许从服务器复制主服务器的数据。
# 在从服务器的 redis.conf 中配置
replicaof <masterip> <masterport>
# 或者使用旧版命令
# slaveof <masterip> <masterport>
# 如果主服务器有密码
masterauth <master-password>
在运行时配置复制:
# 在从服务器上执行
REPLICAOF masterip masterport
# 或者使用旧版命令
# SLAVEOF masterip masterport
# 停止复制,成为主服务器
REPLICAOF NO ONE
哨兵(Sentinel)
哨兵用于监控和自动故障转移。
创建 sentinel.conf
文件:
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
启动哨兵:
redis-sentinel sentinel.conf
# 或者
redis-server sentinel.conf --sentinel
Redis 集群
Redis 集群提供数据分片和高可用性。
# redis.conf 集群配置
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
创建集群:
# 使用 redis-cli 创建集群
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1
集群操作:
# 连接到集群
redis-cli -c -p 7000
# 查看集群信息
CLUSTER INFO
# 查看集群节点
CLUSTER NODES
Redis 安全
设置密码
# redis.conf 配置
requirepass yourpassword
或者在运行时设置:
CONFIG SET requirepass "yourpassword"
连接时使用密码:
redis-cli -a yourpassword
# 或者
redis-cli
> AUTH yourpassword
禁用危险命令
# redis.conf 配置
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
网络安全
# redis.conf 配置
bind 127.0.0.1 # 只监听本地连接
protected-mode yes # 保护模式
访问控制列表(ACL)
Redis 6.0 引入了 ACL:
# 创建用户
ACL SETUSER myuser on >password ~* +@all -@dangerous
# 查看用户
ACL LIST
# 使用用户认证
AUTH myuser password
Redis 性能优化
内存优化
# redis.conf 配置
maxmemory 1gb
maxmemory-policy allkeys-lru # 内存不足时的淘汰策略
内存淘汰策略:
noeviction
:不淘汰,写入操作报错allkeys-lru
:淘汰最近最少使用的键volatile-lru
:淘汰设置了过期时间的键中最近最少使用的allkeys-random
:随机淘汰volatile-random
:随机淘汰设置了过期时间的键volatile-ttl
:淘汰即将过期的键
使用 pipelining 减少网络开销
# Python 示例
import redis
r = redis.Redis()
pipe = r.pipeline()
for i in range(10000):
pipe.set(f'key:{i}', f'value:{i}')
pipe.execute()
合理使用数据结构
- 对于简单键值对,使用 String
- 对于对象,使用 Hash
- 对于列表数据,使用 List
- 对于唯一性集合,使用 Set
- 对于需要排序的集合,使用 Sorted Set
使用 Redis 模块扩展功能
- RedisJSON:原生 JSON 支持
- RediSearch:全文搜索引擎
- RedisTimeSeries:时间序列数据库
- RedisGraph:图数据库
- RedisBloom:概率数据结构
Redis 应用场景
缓存
# Python 示例:缓存模式
import redis
import json
r = redis.Redis()
def get_user(user_id):
# 尝试从缓存获取
user_json = r.get(f'user:{user_id}')
if user_json:
return json.loads(user_json)
# 缓存未命中,从数据库获取
user = db.query(f"SELECT * FROM users WHERE id = {user_id}")
# 存入缓存(设置过期时间)
r.setex(f'user:{user_id}', 3600, json.dumps(user))
return user
会话存储
# Python 示例:会话存储
import redis
import json
import uuid
r = redis.Redis()
def create_session(user_id):
session_id = str(uuid.uuid4())
session_data = {
'user_id': user_id,
'login_time': datetime.now().isoformat(),
'data': {}
}
# 存储会话(30分钟过期)
r.setex(f'session:{session_id}', 1800, json.dumps(session_data))
return session_id
def get_session(session_id):
session_json = r.get(f'session:{session_id}')
if not session_json:
return None
# 刷新过期时间
r.expire(f'session:{session_id}', 1800)
return json.loads(session_json)
排行榜
# Python 示例:游戏排行榜
import redis
r = redis.Redis()
def update_score(user_id, score):
# 更新用户分数
r.zadd('leaderboard', {user_id: score})
def get_top_players(count=10):
# 获取前N名玩家
return r.zrevrange('leaderboard', 0, count-1, withscores=True)
def get_user_rank(user_id):
# 获取用户排名(从0开始)
rank = r.zrevrank('leaderboard', user_id)
return rank + 1 if rank is not None else None
限流器
# Python 示例:简单限流器
import redis
import time
r = redis.Redis()
def is_rate_limited(user_id, limit=10, period=60):
# 键名
key = f'ratelimit:{user_id}'
# 当前时间
now = int(time.time())
# 管道操作
pipe = r.pipeline()
# 添加当前时间戳到有序集合
pipe.zadd(key, {now: now})
# 移除过期的时间戳
pipe.zremrangebyscore(key, 0, now - period)
# 设置过期时间
pipe.expire(key, period)
# 获取集合大小
pipe.zcard(key)
# 执行
_, _, _, count = pipe.execute()
# 检查是否超过限制
return count > limit
消息队列
# Python 示例:简单消息队列
import redis
import json
r = redis.Redis()
def publish_message(queue_name, message):
# 将消息添加到列表末尾
r.rpush(queue_name, json.dumps(message))
def consume_message(queue_name, timeout=0):
# 从列表左侧弹出消息(阻塞操作)
result = r.blpop(queue_name, timeout)
if result:
_, message_json = result
return json.loads(message_json)
return None
使用 Stream 实现更可靠的消息队列:
# Python 示例:使用 Stream 的消息队列
import redis
import json
r = redis.Redis()
def publish_message(stream_name, message):
# 添加消息到流
return r.xadd(stream_name, message)
def create_consumer_group(stream_name, group_name):
try:
# 创建消费者组,从最新消息开始
r.xgroup_create(stream_name, group_name, id='$', mkstream=True)
except redis.exceptions.ResponseError as e:
# 组已存在
if 'BUSYGROUP' not in str(e):
raise
def consume_messages(stream_name, group_name, consumer_name, count=1):
# 读取未被组内消费的消息
messages = r.xreadgroup(group_name, consumer_name, {stream_name: '>'}, count=count)
if not messages:
return []
stream_messages = messages[0][1]
result = []
for message_id, message in stream_messages:
# 处理消息
result.append((message_id, message))
# 确认消息已处理
r.xack(stream_name, group_name, message_id)
return result
分布式锁
# Python 示例:分布式锁
import redis
import uuid
import time
r = redis.Redis()
def acquire_lock(lock_name, timeout=10):
# 生成唯一标识符
identifier = str(uuid.uuid4())
# 获取锁(NX: 只在键不存在时设置,EX:
---
title: "Redis 教程:从入门到精通"
description: "全面学习 Redis 数据库,掌握数据类型、持久化、事务、集群等核心功能,提升应用性能与可扩展性"
head:
- - meta
- name: keywords
content: "Redis,缓存,NoSQL,数据库,键值存储,持久化,事务,集群,高可用,性能优化"
- - meta
- property: og:title
content: "Redis 教程:从入门到精通 - 技术文档"
- - meta
- property: og:description
content: "全面学习 Redis 数据库,掌握数据类型、持久化、事务、集群等核心功能,提升应用性能与可扩展性"
outline: deep
lastUpdated: true
---
# Redis 教程:从入门到精通
Redis 是一个开源的、基于内存的高性能键值数据库,被广泛应用于缓存、会话存储、消息队列等场景。本教程将帮助你全面了解 Redis 的核心概念和使用方法。
## Redis 简介
### 什么是 Redis?
Redis(Remote Dictionary Server)是一个开源的、基于内存的数据结构存储系统,可以用作数据库、缓存和消息中间件。它支持多种数据类型,如字符串、哈希表、列表、集合、有序集合等,并且提供了丰富的操作命令。
### Redis 的主要特点
- **高性能**:基于内存操作,读写速度极快
- **丰富的数据类型**:支持字符串、哈希、列表、集合、有序集合等
- **原子操作**:所有操作都是原子性的,支持事务
- **持久化**:支持数据持久化到磁盘(RDB 和 AOF)
- **主从复制**:支持主从复制和高可用
- **分布式**:支持集群模式,可水平扩展
- **Lua 脚本**:支持 Lua 脚本执行复杂操作
- **发布/订阅**:支持消息的发布与订阅
### Redis 与传统数据库的比较
| 特性 | Redis | 关系型数据库 |
|------|-------|------------|
| 数据模型 | 键值存储 | 表格关系模型 |
| 存储方式 | 内存(可持久化) | 磁盘 |
| 查询语言 | 简单命令 | SQL |
| 事务支持 | 基本支持 | 完全支持 |
| 性能 | 极高 | 中等 |
| 扩展性 | 主从复制、集群 | 主从复制、分库分表 |
| 适用场景 | 缓存、会话、计数器、排行榜 | 复杂查询、事务处理 |