记录一些 Redis 应用场景
作为版本号
- 场景:
- CS 架构、微服务模式下,服务端提供一个接口可以查询大量数据,以数组形式返回; 数据量如此之大,以至于保存在 MySQL 和 Redis 都会导致请求延迟过大,无法应对高并发场景。
- Server 端采用本地内存缓存的形式应对高并发场景,缓存会设置超时时间
- 某些情况下,数据数组会发生变化,CS 之间以先推后拉的形式通知,即服务端先通知客户端,客户端再查询最新数据
- 问题:
存在下面可能的时序:
- Client 刚调用了查询接口,创建了本地缓存
- Server 更新了数组,通知 Client 拉取
- Client 拉取时,由于缓存未超时,拉取到了旧数据
- 方案:
- 在 Redis 中用一个整型的 key 作为版本号
- 当写入数据之后,利用
Incr
原子性的升高版本号,然后再发通知 - 在缓存的 key 设计中,把版本号作为 key 的一部分
- 查询时先查出最新版本号,再查询/建立缓存,避免使用旧数据
- 优点:
- 既解决了
- 改进:
- 上面流程并没有及时释放旧缓存,如果并发修改数据,会导致缓存残留 OOM。 可以在发现版本号变化(查询时)后,开启一个异步处理,短时间内就可清理无用的旧缓存
作为任务队列
微博头条评论区排序显示
-
基本排序方法
-
关注好友优先显示
特殊场景
Lua 脚本 VS SPOP
问题: 需要将一个集合中的数据一次性取出
方案 1:
SPOP key [count]
该命令在 redis3.2 之后提供,可以一次取出集合中的多个元素。
方案 2: 利用 lua 脚本,将元素取出并删除,实现原子操作。这样不用依赖 redis3.2 版本以上就可以实现。
- 使用 lua 脚本时要注意,如果要兼容 cordis,在同一个脚本中涉及的 key 要在一个分片上。
方案 3:
利用SMEMBERS
将所有元素取出,然后用SREM
一次性删除这些取出的元素,之后再开始对元素进行处理。虽然操作不是原子的,但是也符合取出后再处理的逻辑。