redis - 如何以服务器端时间戳作为分数存储在 Redis 排序集中?
问题描述
我想使用一个排序集来存储对象,使用 redis-server 时间戳作为分数。
我知道我可以使用带有*
id 的 Redis Streams,但是 Redis Streams 有一些限制,包括我不能编辑对象,我不能使用等级或字典排序,我不能真正删除中间的对象、联合或相交等。
我想以原子方式执行此操作,并使用 redis-server 时间戳,这样我就可以使用多个客户端ZADD
而不必担心时钟同步。
这该怎么做?
解决方案
解决方案是使用 Lua 脚本:
local time = redis.call('TIME')
local ts = time[1]..string.format('%06d', time[2])
return redis.call('ZADD', KEYS[1], ts, ARGV[1])
这里我们使用 RedisTIME
命令。命令返回:
- 以秒为单位的 unix 时间
- 微秒
所以我们可以连接这两者并使用微秒时间戳。我们需要对微秒部分进行零填充。
由于排序集适用于高达 2^53 的整数值,因此我们的时间戳一直到 2255 年都是安全的。
这是 Redis-Cluster 安全的,因为我们存储在一个密钥中。要使用多个密钥,如果要比较时间戳,请确保使用哈希标签将它们放在同一个节点上。
您可以修改脚本以使用低于微秒的分辨率。
这里的EVAL
命令,简单的传递键和值作为参数,无需事先创建排序集:
EVAL "local time = redis.call('TIME') local ts = time[1]..string.format('%06d', time[2]) return redis.call('ZADD', KEYS[1], ts, ARGV[1])" 1 ssetKey myVal
> SCRIPT LOAD "local time = redis.call('TIME') local ts = time[1]..string.format('%06d', time[2]) return redis.call('ZADD', KEYS[1], ts, ARGV[1])"
"81e366e422d0b09c9b395b5dfe03c03c3b7b3bf7"
> EVALSHA 81e366e422d0b09c9b395b5dfe03c03c3b7b3bf7 1 ssetKey myNewVal
(integer) 1
关于 Redis 版本的说明。如果您正在使用:
- Redis 3.2 之前的版本:对不起,你不能使用
TIME
(非确定性命令)然后用ZADD
. - Redis 版本大于 3.2 但 < 5.0:添加
redis.replicate_commands()
在脚本之上。将脚本视为纯函数 - Redis 5.0 一上来:你很好。
推荐阅读
- android - 插件材料设计图标中的异常
- java - 通过 LLVM 前端编译的 Kotlin/Native 和 Java 字节码有什么区别?
- javascript - 如何使 event.stopPropagation() 为表单内的输入字段工作?
- nativescript - Nativescript 应用程序设置不会保留用户名和密码
- python - 如何处理来自我的 Django 应用程序的外部 API 的 JWT 身份验证?
- git - 计算另一个分支中的行号
- python - 深度学习模型的验证准确率停留在 0.5,而训练准确率正在提高
- java - @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @Id 和序列的问题
- google-cloud-firestore - Google FireStore - 班次计划或资源预订 - 如何查询
- php - 传递的变量在特定行中不起作用