Redis 使用指南
简介
Redis 是一个开源的内存数据结构存储系统,可以用作数据库、缓存和消息中间件。它支持多种数据结构,如字符串、哈希、列表、集合、有序集合等。Redis 提供了丰富的命令集来操作这些数据结构,并且支持数据的持久化、复制和集群等功能。
安装
说明如何安装Redis,包括下载、配置和启动步骤。
下载
- 访问 Redis 官方网站 下载最新版本的 Redis。
- 解压下载的文件:
tar xzf redis-<version>.tar.gz cd redis-<version>
编译和安装
- 编译 Redis:
make
- 安装 Redis:
sudo make install
配置和启动
- 复制配置文件:
cp redis.conf /etc/redis.conf
- 启动 Redis 服务器:
redis-server /etc/redis.conf
基本操作
说明如何使用Redis进行基本操作,包括设置键值对、获取键值对、删除键值对等。
设置键值对
使用 SET
命令可以设置键值对:
SET key value
示例:
SET name "John Doe"
获取键值对
使用 GET
命令可以获取键对应的值:
GET key
示例:
GET name
# 返回 "John Doe"
删除键
使用 DEL
命令可以删除一个或多个键:
DEL key [key ...]
示例:
DEL name
检查键是否存在
使用 EXISTS
命令可以检查键是否存在:
EXISTS key
返回1表示存在,0表示不存在。
设置过期时间
使用 EXPIRE
命令可以为键设置过期时间(秒):
EXPIRE key seconds
示例:
EXPIRE name 60 # 60秒后过期
获取剩余生存时间
使用 TTL
命令可以获取键的剩余生存时间:
TTL key
返回-2表示键不存在,-1表示没有设置过期时间,否则返回剩余秒数。
批量操作
使用 MSET
和 MGET
命令可以进行批量操作:
MSET key1 value1 key2 value2 ...
MGET key1 key2 ...
示例:
MSET name "John" age 30
MGET name age
# 返回 ["John", "30"]
数据类型操作
Redis支持多种数据结构,以下是每种数据类型的常用操作:
字符串(String)
- 设置值:
SET key value
- 获取值:
GET key
- 追加值:
APPEND key value
- 获取子串:
GETRANGE key start end
- 设置新值并返回旧值:
GETSET key value
- 自增/自减:
INCR key
/DECR key
使用场景:
- 缓存:存储热点数据,如页面缓存、对象缓存
- 计数器:实现访问量统计、点赞数统计等功能
哈希(Hash)
- 设置字段值:
HSET key field value
- 获取字段值:
HGET key field
- 获取所有字段值:
HGETALL key
- 删除字段:
HDEL key field [field ...]
- 检查字段是否存在:
HEXISTS key field
- 获取所有字段:
HKEYS key
- 获取字段数量:
HLEN key
使用场景:
- 对象存储:存储用户信息、商品信息等结构化数据
- 配置管理:存储系统配置项,支持单个字段的更新
列表(List)
- 左/右插入元素:
LPUSH key value
/RPUSH key value
- 左/右弹出元素:
LPOP key
/RPOP key
- 获取列表长度:
LLEN key
- 获取指定范围元素:
LRANGE key start stop
- 根据索引获取元素:
LINDEX key index
- 根据值删除元素:
LREM key count value
使用场景:
- 消息队列:实现简单的消息队列系统
- 最新动态:存储用户的最新动态、操作日志
集合(Set)
- 添加元素:
SADD key member [member ...]
- 删除元素:
SREM key member [member ...]
- 获取所有元素:
SMEMBERS key
- 检查元素是否存在:
SISMEMBER key member
- 获取集合大小:
SCARD key
- 集合运算:
SUNION
/SINTER
/SDIFF
使用场景:
- 标签系统:存储文章标签、商品分类
- 共同好友:计算两个用户的共同好友
有序集合(Sorted Set)
- 添加元素:
ZADD key score member [score member ...]
- 获取元素分数:
ZSCORE key member
- 获取排名:
ZRANK key member
- 获取指定范围元素:
ZRANGE key start stop [WITHSCORES]
- 删除元素:
ZREM key member [member ...]
- 获取集合大小:
ZCARD key
- 按分数范围获取元素:
ZRANGEBYSCORE key min max
使用场景:
- 排行榜:实现游戏积分榜、热搜榜
- 延迟队列:通过分数存储时间戳实现延迟任务
Bitmaps
- 设置位:
SETBIT key offset value
- 获取位:
GETBIT key offset
- 统计置位数量:
BITCOUNT key [start end]
- 位运算:
BITOP operation destkey key [key ...]
- 查找第一个置位:
BITPOS key bit [start] [end]
使用场景:
- 用户签到:记录用户每日签到情况
- 特征标记:标记用户特征或状态
HyperLogLog
- 添加元素:
PFADD key element [element ...]
- 统计基数:
PFCOUNT key [key ...]
- 合并多个HLL:
PFMERGE destkey sourcekey [sourcekey ...]
使用场景:
- UV统计:统计网站的独立访客数
- 去重统计:统计大规模数据的近似去重数量
Geospatial
- 添加地理位置:
GEOADD key longitude latitude member [longitude latitude member ...]
- 获取位置:
GEOPOS key member [member ...]
- 计算距离:
GEODIST key member1 member2 [unit]
- 查找附近位置:
GEORADIUS key longitude latitude radius unit [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]
使用场景:
- 附近的人:查找用户附近的其他用户
- 位置服务:实现基于位置的搜索和推荐
Streams
- 添加消息:
XADD key ID field value [field value ...]
- 读取消息:
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
- 创建消费者组:
XGROUP CREATE key groupname ID
- 消费消息:
XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
- 确认消息:
XACK key group ID [ID ...]
- 查看待处理消息:
XPENDING key group
使用场景:
- 消息队列:实现可靠的消息队列系统
- 日志收集:收集和存储系统日志
高级特性
Redis提供了多种高级功能来满足不同的使用场景:
持久化
Redis支持两种持久化方式:
-
RDB(Redis Database):
- 定时生成数据快照
- 配置:
save <seconds> <changes>
- 手动保存:
SAVE
(阻塞)或BGSAVE
(后台)
-
AOF(Append Only File):
- 记录每个写操作
- 配置:
appendonly yes
- 同步策略:
appendfsync always|everysec|no
事务
- 使用
MULTI
开始事务 - 使用
EXEC
执行事务 - 使用
DISCARD
取消事务 - 使用
WATCH
实现乐观锁 - 示例:
MULTI SET key1 value1 SET key2 value2 EXEC
发布/订阅
- 发布消息:
PUBLISH channel message
- 订阅频道:
SUBSCRIBE channel [channel ...]
- 取消订阅:
UNSUBSCRIBE [channel ...]
- 模式匹配订阅:
PSUBSCRIBE pattern [pattern ...]
复制
- 主从复制配置:
replicaof <masterip> <masterport>
- 查看复制信息:
INFO replication
- 主从切换:
REPLICAOF NO ONE
集群
- 创建集群:
redis-cli --cluster create ...
- 添加节点:
redis-cli --cluster add-node ...
- 重新分片:
redis-cli --cluster reshard ...
- 查看集群信息:
CLUSTER INFO
- 查看节点信息:
CLUSTER NODES
Lua脚本
- 执行脚本:
EVAL script numkeys key [key ...] arg [arg ...]
- 缓存脚本:
SCRIPT LOAD script
- 执行缓存脚本:
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
- 示例:
EVAL "return redis.call('GET', KEYS[1])" 1 mykey
分布式锁
Redis实现分布式锁的最佳实践:
-
基本实现:
- 获取锁:
SET lock_key unique_value NX PX 30000
- 释放锁:Lua脚本保证原子性
if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
- 获取锁:
-
关键特性:
- 互斥性:使用SETNX保证只有一个客户端能获取锁
- 超时机制:设置合理的过期时间防止死锁
- 可重入性:通过ThreadLocal存储锁信息实现
- 自动续期:使用守护线程定期延长锁的过期时间
-
注意事项:
- 确保value唯一,建议使用UUID
- 设置合理的过期时间,避免业务未完成锁已过期
- 使用Lua脚本保证释放锁的原子性
- 考虑集群模式下的锁可靠性
-
示例代码:
// 获取锁 String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime); if ("OK".equals(result)) { // 获取锁成功 try { // 执行业务逻辑 } finally { // 释放锁 String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); } }
常见问题
以下是使用Redis时可能遇到的常见问题及解决方案:
内存管理
-
内存不足:
- 解决方案:使用
maxmemory
配置限制内存使用 - 设置淘汰策略:
maxmemory-policy
(如volatile-lru) - 使用
MEMORY USAGE
命令监控内存使用
- 解决方案:使用
-
大Key问题:
- 现象:单个Key过大导致性能下降
- 解决方案:拆分大Key,使用多个小Key存储
性能优化
-
慢查询:
- 使用
SLOWLOG
命令查看慢查询 - 优化数据结构设计
- 使用Pipeline减少网络开销
- 使用
-
热点Key问题:
- 现象:某些Key访问过于频繁
- 解决方案:使用本地缓存或读写分离
数据一致性
-
主从延迟:
- 使用
INFO replication
查看复制状态 - 优化网络配置
- 使用
WAIT
命令等待复制完成
- 使用
-
事务原子性:
- 确保使用
MULTI/EXEC
包裹事务 - 使用
WATCH
实现乐观锁
- 确保使用
故障处理
-
主节点故障:
- 使用哨兵模式自动故障转移
- 手动执行
REPLICAOF NO ONE
提升从节点
-
数据丢失:
- 配置合理的持久化策略
- 定期备份RDB文件
- 使用AOF重写压缩日志
安全配置
-
访问控制:
- 设置密码:
requirepass
- 使用
rename-command
重命名危险命令 - 配置防火墙规则
- 设置密码:
-
数据加密:
- 使用SSL/TLS加密网络传输
- 敏感数据在客户端加密存储
分布式缓存问题
-
缓存穿透:
- 现象:大量请求查询不存在的数据,导致请求直接打到数据库
- 解决方案:
- 使用布隆过滤器拦截非法请求
- 缓存空值(设置较短过期时间)
- 接口层增加参数校验
-
缓存击穿:
- 现象:热点key过期瞬间,大量请求直接打到数据库
- 解决方案:
- 设置热点数据永不过期
- 使用互斥锁(如Redis的SETNX)重建缓存
- 使用本地缓存作为二级缓存
-
缓存雪崩:
- 现象:大量缓存同时失效,导致数据库压力骤增
- 解决方案:
- 设置缓存过期时间时增加随机值
- 使用集群模式,分散缓存失效时间
- 实现缓存预热机制
-
数据一致性:
- 现象:缓存与数据库数据不一致
- 解决方案:
- 使用双写策略(先写数据库,再删缓存)
- 使用消息队列异步更新缓存
- 设置合理的缓存过期时间
-
热点数据:
- 现象:某些key访问过于频繁,导致单点压力过大
- 解决方案:
- 使用本地缓存
- 对热点key进行分片
- 使用读写分离架构
参考资料
列出参考的书籍、文档和在线资源。