键设计

键命名规范:建议使用冒号分隔,如 user:1001:info,这样在 Redis 客户端中查看时层次更清晰

String

image-20260516143614664

缓存对象

使用 String 来缓存对象有两种方式:

  • 直接缓存整个对象的 JSON,命令例子: SET user:1 '{"name":"xiaolin", "age":18}'
  • 采用将 key 进行分离为 user:ID:属性,采用 MSET 存储,用 MGET 获取各属性值,命令例子: MSET user:1:name xiaolin user:1:age 18 user:2:name xiaomei user:2:age 20

常规计数

因为 Redis 处理命令是单线程,所以执行命令的过程是原子的。因此 String 数据类型适合计数场景,比如计算访问次数、点赞、转发、库存数量等等。

分布式锁

SET 命令有个 NX 参数可以实现「key不存在才插入」,可以用它来实现分布式锁:

上锁

image-20260515204057591

释放锁

image-20260515204133718

为什么需要lockvalue?因为A线程还没执行完,锁过期,B线程过来拿到锁,A线程执行完删除锁就把B的锁删了;通过获取锁时从ThreadLocal存储的值和Redis中的lockvalue比较,自己线程的锁才删

Redisson

1. 看门狗机制核心原理

  • 在获取锁成功后,创建一个定时任务
  • 定时任务每隔 10 秒(默认超时时间的 1/3)执行一次
  • 通过 Lua 脚本检查锁是否还存在并延长过期时间

2. 可重入锁原理

数据结构设计,用Hash:

image-20260515205835498

加锁:

image-20260515205931367

解锁:

image-20260515210148020

List

image-20260516143548201

基本操作

1
2
3
4
5
6
7
8
# 将一个或多个值value插入到key列表的表头(最左边),最后的值在最前面
LPUSH key value [value ...]
# 将一个或多个值value插入到key列表的表尾(最右边)
RPUSH key value [value ...]
# 移除并返回key列表的头元素
LPOP key
# 移除并返回key列表的尾元素
RPOP key
  • 分页查询
  • 最新N条记录

以上都可以LRANGE实现

1
2
# 返回列表key中指定区间内的元素,区间以偏移量start和stop指定,从0开始
LRANGE key start stop
1
2
3
4
# 从key列表表头弹出一个元素,没有就阻塞timeout秒超时(timeout=0是一直阻塞)
BLPOP key [key ...] timeout
# 从key列表表尾弹出一个元素,没有就阻塞timeout秒超时(timeout=0是一直阻塞)
BRPOP key [key ...] timeout

消息队列

利用List的阻塞式获取可以实现消息队列

image-20260515230209360

  • 消息保序:使用 LPUSH;

  • 阻塞读取:使用 BRPOP;

  • 重复消息处理:生产者自行实现全局唯一 ID;

  • 消息的可靠性:使用 BRPOPLPUSH

    由于网络波动,BRPOP了可能还没执行客户端就挂了,可以用BRPOPLPUSH(这个命令的作用是让消费者程序从一个 List 中读取消息,同时,Redis 会把这个消息再插入到另一个 List(可以叫作备份 List)留存),重启时,会先从备份 List获取数据消费

Stream

专门用来实现消息队列的

发布订阅

Redis 的发布订阅(Pub/Sub)是一种消息通信模式,用于解耦消息发送者和接收者,实现一对多的实时消息通知

使用专业的MQ工具的话,Stream和发布订阅就不要用了

Hash

image-20260516143522705

一般对象用 String + Json 存储,对象中某些频繁变化的属性可以考虑抽出来用 Hash 类型存储

1
2
# 语法:HSET key field1 value1 field2 value2 ...
HSET user:1000 name "Alice" age "30"

Set

image-20260516143500410

1
2
3
4
5
6
# uid:1 用户对文章 article:1 点赞
> SADD article:1 uid:1
(integer) 1
# uid:2 用户对文章 article:1 点赞
> SADD article:1 uid:2
(integer) 1

Set 类型支持交集运算,所以可以用来计算共同关注的好友、公众号

Zset

Zset 类型(有序集合类型)相比于 Set 类型多了一个排序属性 score(分值)

1
2
3
4
5
6
# arcticle:1 文章获得了200个赞
> ZADD user:xiaolin:ranking 200 arcticle:1
(integer) 1
# arcticle:2 文章获得了40个赞
> ZADD user:xiaolin:ranking 40 arcticle:2
(integer) 1

BitMap

Bitmap,即位图,是一串连续的二进制数组(0和1),可以通过偏移量(offset)定位元素。BitMap通过最小的单位bit来进行0|1的设置,表示某个元素的值或者状态,时间复杂度为O(1)

image-20260516144050684

1
2
3
4
5
6
7
8
9
# 设置值,其中value只能是 0 和 1
SETBIT key offset value

# 获取值
GETBIT key offset

# 获取指定范围内值为 1 的个数
# start 和 end 以字节为单位
BITCOUNT key start end

Bitmap 类型非常适合二值状态统计的场景

GEO

执行下面的这个命令,就可以把 ID 号为 33 的车辆的当前经纬度位置存入 GEO 集合中:

1
GEOADD cars:locations 116.034579 39.030452 33

当用户想要寻找自己附近的网约车时,LBS 应用就可以使用 GEORADIUS 命令。

例如,LBS 应用执行下面的命令时,Redis 会根据输入的用户的经纬度信息(116.054579,39.030452 ),查找以这个经纬度为中心的 5 公里内的车辆信息,并返回给 LBS 应用。

1
GEORADIUS cars:locations 116.054579 39.030452 5 km ASC COUNT 10

Pipeline

多条命令一次打包,减少网络IO

通过redisTemplate.executePipelined执行批量操作:

image-20260518153838814

注意:

  1. 注意 Pipeline 不支持原子性:它只负责打包发送,执行过程中可能被其他客户端的命令“插队”。如果某条命令失败,其后续命令仍会继续执行。对原子性有强要求,请使用 Lua 脚本或事务。
  2. Redis Cluster 的使用限制:在 Redis 集群(Cluster)模式下使用 Pipeline 时,请确保 Pipeline 中的所有命令都操作同一个 slot 的 key,否则会报错。