You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redis Lua脚本中64位整数比较的实现方案求助

原子更新Redis哈希中的64位时间戳(Lua 5.1兼容)

问题背景

需要将C#对象存入Redis哈希,其中ChangeEventTime字段为DateTime.Ticks(64位long型整数),要求原子条件更新:仅当传入的时间戳比Redis中存储的更新时,才执行哈希更新。当前Lua脚本因Redis内置Lua 5.1不支持64位整数,转换时会丢失精度;同时需要亚秒级精度、避免客户端脏写,且工作队列无法保证条目顺序。

可行解决方案

1. 字符串字典序比较(最优方案)

C# DateTime.Ticks是固定长度的数字字符串(最多19位),相同长度的数字字符串的字典序与数值大小完全一致,因此可以直接用字符串比较替代数值比较,完全避开Lua的64位整数限制。

修改后的Lua脚本:

local existing_time = redis.call('HGET', KEYS[1], 'ChangeEventTime')
-- 若不存在旧值,或新时间戳字符串更大,则执行更新
if not existing_time or existing_time < ARGV[1] then
    -- 合并两次HSET为一次,提升性能
    redis.call('HSET', KEYS[1], 'ChangeEventTime', ARGV[1], 'Value', ARGV[2])
end

使用说明:

  • C#侧传入ARGV[1]时,直接调用DateTime.Ticks.ToString()转为字符串即可,无需额外处理
  • 该操作是原子性的,Redis会确保脚本执行期间不会有其他命令插入,完全避免脏写
  • 性能最优,仅需1次HGET和最多1次HSET

2. 拆分64位整数为两个32位字段

如果必须依赖数值比较,可以将64位Ticks拆分为高32位和低32位两个字段存储,分别进行数值比较(Lua 5.1支持32位有符号整数,不会丢失精度)。

C#侧拆分逻辑:

long ticks = DateTime.UtcNow.Ticks;
uint highPart = (uint)(ticks >> 32);
uint lowPart = (uint)ticks;
// 传入Redis时,将highPart、lowPart、Value作为参数

Lua脚本实现:

local existing_high = redis.call('HGET', KEYS[1], 'ChangeEventTimeHigh')
local existing_low = redis.call('HGET', KEYS[1], 'ChangeEventTimeLow')

-- 无旧值时直接写入
if not existing_high then
    redis.call('HSET', KEYS[1], 'ChangeEventTimeHigh', ARGV[1], 'ChangeEventTimeLow', ARGV[2], 'Value', ARGV[3])
    return
end

-- 转换为32位整数(Lua 5.1支持范围)
local existing_high_num = tonumber(existing_high)
local existing_low_num = tonumber(existing_low)
local new_high_num = tonumber(ARGV[1])
local new_low_num = tonumber(ARGV[2])

-- 先比较高32位,高32位相等时再比较低32位
if new_high_num > existing_high_num or (new_high_num == existing_high_num and new_low_num > existing_low_num) then
    redis.call('HSET', KEYS[1], 'ChangeEventTimeHigh', ARGV[1], 'ChangeEventTimeLow', ARGV[2], 'Value', ARGV[3])
end

优缺点:

  • 优势:基于数值比较逻辑,直观易懂
  • 劣势:增加了存储字段,C#侧需要额外的拆分/合并逻辑,复杂度略高于字符串方案

3. 避免使用的方案:Sorted Set存储

虽然Sorted Set的ZADD支持条件更新(GT参数),但Redis的Sorted Set使用双精度浮点数存储score,无法精确表示超过2^53的整数(C# Ticks最大值约9e18,远大于2^53),会导致时间戳精度丢失,因此不适合该场景。


内容的提问来源于stack exchange,提问作者Bryan Lewis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 00:27:20