一、Redis 是什么
开源的内存 键值数据库,数据存在内存中,读写速度极快(10万+ QPS)
支持数据持久化,可将内存数据保存到磁盘
单线程模型(6.0 后 I/O 多线程,命令执行仍单线程),避免了线程安全问题
常用场景:缓存、会话管理、排行榜、消息队列、分布式锁
二、数据类型
类型
说明
典型场景
String
最基本类型,可存字符串/数字/二进制
缓存、计数器、分布式锁
Hash
字段-值映射,类似 HashMap
存储对象(用户信息)
List
有序列表,支持头尾操作
消息队列、最新列表
Set
无序不重复集合
标签、共同好友、去重
Sorted Set (ZSet)
有序集合,每个元素带分数
排行榜、延迟队列
Bitmap
位操作
签到、在线状态
HyperLogLog
基数统计(近似值)
UV 统计
Stream
消息流(5.0+)
消息队列
三、常用命令
String
bash
复制代码
SET key value # 设置值
GET key # 获取值
SET key value EX 60 # 设置值,60秒过期
SETNX key value # 不存在时才设置(分布式锁基础)
INCR key # 值+1(原子操作)
DECR key # 值-1
MSET k1 v1 k2 v2 # 批量设置
MGET k1 k2 # 批量获取
List
bash
复制代码
LPUSH list a b c # 从左侧插入
RPUSH list x y z # 从右侧插入
LPOP list # 从左侧弹出
RPOP list # 从右侧弹出
LRANGE list 0 -1 # 获取所有元素
LLEN list # 获取长度
LREM list 2 a # 删除2个值为a的元素(0=全部,正=从左,负=从右)
LTRIM list 0 2 # 只保留索引0~2的元素,其余删除
Set
bash
复制代码
SADD set a b c # 添加元素
SMEMBERS set # 获取所有元素
SISMEMBER set a # 判断元素是否存在
SREM set a # 删除元素
SINTER set1 set2 # 交集
SUNION set1 set2 # 并集
SDIFF set1 set2 # 差集
Sorted Set
bash
复制代码
ZADD rank 100 "张三" # 添加元素(分数100)
ZRANGE rank 0 -1 WITHSCORES # 按分数升序获取
ZREVRANGE rank 0 9 # 按分数降序取前10(排行榜)
ZSCORE rank "张三" # 获取分数
ZRANK rank "张三" # 获取排名
ZREM rank "张三" # 删除元素
Hash
bash
复制代码
HSET user:1 name "张三" # 设置字段
HGET user:1 name # 获取字段
HMSET user:1 name "张三" age 25 # 批量设置字段
HGETALL user:1 # 获取所有字段和值
HDEL user:1 age # 删除字段
通用命令
bash
复制代码
DEL key # 删除
EXISTS key # 判断是否存在
EXPIRE key 60 # 设置过期时间(秒)
TTL key # 查看剩余过期时间
TYPE key # 查看数据类型
KEYS pattern # 查找key(生产慎用,会阻塞)
SCAN 0 MATCH user:* COUNT 100 # 渐进式遍历(推荐替代KEYS)
FLUSHDB # 清空当前库
四、发布订阅
bash
复制代码
SUBSCRIBE channel1 # 订阅频道(会阻塞等待消息)
PUBLISH channel1 "hello" # 向频道发送消息
PSUBSCRIBE news.* # 模式订阅(匹配 news.xxx 的所有频道)
UNSUBSCRIBE channel1 # 取消订阅
发布订阅不持久化 ,消息发出后如果没有订阅者则丢失
需要持久化消息队列建议使用 Stream 类型
五、Stream(消息队列)
bash
复制代码
XADD mystream * name "张三" age 25 # 添加消息(*表示自动生成ID)
↑ ↑ ↑ ↑ ↑
命令 Stream名 ID 字段名 字段值
XLEN mystream # 消息数量
XRANGE mystream - + # 获取所有消息
XREAD COUNT 2 BLOCK 0 STREAMS mystream 0 # 阻塞读取消息
XGROUP CREATE mystream mygroup 0 # 创建消费者组
XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream > # 消费者读取
XACK mystream mygroup 消息ID # 确认消费
六、Geospatial(地理空间)
bash
复制代码
GEOADD city 116.40 39.90 "北京" # 添加地理位置(经度 纬度 名称)
GEOADD city 121.47 31.23 "上海"
GEOPOS city "北京" # 获取坐标
GEODIST city "北京" "上海" km # 计算两地距离(单位:km)
GEOSEARCH city FROMMEMBER "北京" BYRADIUS 1500 km # 搜索半径内的城市
七、HyperLogLog
bash
复制代码
PFADD uv:page1 user1 user2 user3 # 添加元素
PFCOUNT uv:page1 # 统计基数(近似UV数)
PFMERGE uv:total uv:page1 uv:page2 # 合并多个HyperLogLog
八、Bitmap(位图)
bash
复制代码
SETBIT sign:user1:202603 0 1 # 第0天签到(位偏移量)
GETBIT sign:user1:202603 0 # 查询第0天是否签到
BITCOUNT sign:user1:202603 # 统计当月签到天数
九、Bitfield(位域)
bash
复制代码
BITFIELD mykey SET u8 0 200 # 在偏移0处设置8位无符号整数值200
BITFIELD mykey GET u8 0 # 获取偏移0处的8位无符号整数
BITFIELD mykey INCRBY u8 0 1 # 自增1
十、事务
Redis 事务通过 MULTI/EXEC 实现,将多条命令打包一次性执行:
bash
复制代码
MULTI # 开启事务
SET k1 v1 # 命令入队
SET k2 v2 # 命令入队
EXEC # 执行所有入队命令
# 或
DISCARD # 放弃事务
Redis 事务不支持回滚 :如果某条命令执行失败,其他命令仍会执行
WATCH 实现乐观锁:如果被监视的 key 在事务执行前被修改,事务自动取消
bash
复制代码
WATCH key # 监视key
MULTI
SET key newvalue
EXEC # 如果key被其他客户端修改,EXEC返回nil
十一、持久化
RDB(快照)
按时间间隔将内存数据快照写入磁盘(dump.rdb)
优点:文件紧凑,恢复速度快
缺点:可能丢失最后一次快照后的数据
bash
复制代码
# redis.conf 配置
save 900 1 # 900秒内至少1个key变化则触发
save 300 10 # 300秒内至少10个key变化则触发
AOF(追加日志)
记录每次写操作到日志文件(appendonly.aof)
优点:数据更安全,最多丢1秒数据
缺点:文件比RDB大,恢复较慢
bash
复制代码
# redis.conf 配置
appendonly yes
appendfsync everysec # 每秒同步一次(推荐)
# appendfsync always # 每次写都同步(最安全但最慢)
如何选择
对数据安全要求高 → AOF(或 RDB + AOF 混合)
对性能要求高,可容忍少量丢失 → RDB
十二、缓存常见问题
问题
说明
解决方案
缓存穿透
查询不存在的数据,每次都打到数据库
布隆过滤器;缓存空值
缓存击穿
热点key过期瞬间,大量请求打到数据库
互斥锁;热点key永不过期
缓存雪崩
大量key同时过期,数据库压力骤增
过期时间加随机值;多级缓存
十三、过期与淘汰策略
过期删除策略
惰性删除 :访问key时才检查是否过期
定期删除 :每隔一段时间随机抽查一批key删除过期的
内存淘汰策略(内存满时)
策略
说明
noeviction
不淘汰,写入报错(默认)
allkeys-lru
所有key中淘汰最近最少使用的(最常用 )
volatile-lru
有过期时间的key中淘汰LRU
allkeys-random
随机淘汰
volatile-ttl
淘汰即将过期的key
十四、常用架构
主从复制
主节点写,从节点读,实现读写分离
从节点异步复制主节点数据
bash
复制代码
# 从节点配置
replicaof 主节点IP 6379
哨兵模式(Sentinel)
监控主从节点状态
主节点宕机时自动故障转移 ,选举新主节点
集群模式(Cluster)
数据分片存储在多个节点(16384个槽位)
支持水平扩展,突破单机内存限制
十五、Spring Boot 集成 Redis
java
复制代码
// 依赖:spring-boot-starter-data-redis
@Autowired
private StringRedisTemplate redisTemplate;
// String 操作
redisTemplate.opsForValue().set("key", "value", 60, TimeUnit.SECONDS);
String val = redisTemplate.opsForValue().get("key");
// Hash 操作
redisTemplate.opsForHash().put("user:1", "name", "张三");
// 删除
redisTemplate.delete("key");