Redis Lua脚本 math.random

我刚刚发现Redis中Lua环境的一个有趣的行为:

我有一个Lua脚本执行一些简单的设置操作并在脚本结束时生成一个唯一的时间戳 ID,以将Redis用作时间戳 Oracle,如下所示:

local time = redis.call('TIME')
local millis = (tonumber(time[1]) * 1000) + math.floor(tonumber(time[2]) / 1000)
local version = string.format("%.0f",mills) .. string.format("%05d", math.random(99999))

现在version类似于145209287564117083,由时间戳和五个随机数字组成 - 至少我是这么认为的。

实际发生的是,尾部的五个随机数字(由math.random(99999)生成)根本不是随机的,而是始终是数字17083,无论脚本执行多少次。

对我来说,这不是一个大问题(因为我可以在脚本返回后附加随机数字),但我没有预料到这种行为,因此需要花费相当长的时间找到我的错误。

我希望这些信息可以节省一些时间。

点赞
用户3001538
用户3001538

我认为这种行为的原因是 Redis 试图防止人们在脚本中生成随机键,因为在复制中这些脚本会被发送到复制品(而不是数据本身)。因此,生成随机键可能会导致不一致的复制品。

所以在调用 redis.call('TIME') 后,不允许在脚本中向 Redis 写入。

我猜想,Redis 中的 Lua 环境总是出于同样的原因从 math.random() 返回相同的数字。

2016-01-06 16:02:45
用户1186811
用户1186811

如果您正在调用一个lua脚本,最好的做法是将时间作为脚本参数传入。这使您完全避免了redis.call("TIME"),然后您可以使用当前时间设置种子。

local time = ARGV[1];
math.randomseed(time);
local millis = (tonumber(time[1]) * 1000) + math.floor(tonumber(time[2]) / 1000)
local version = string.format("%.0f",mills) .. string.format("%05d", math.random(99999))

这也避免了与复制相关的任何未来问题,因为所有实例都将接收相同的参数并生成相同的输出。

2016-07-08 22:08:30