2016-01-06 30 views
2

我只是碰到Lua環境中的Redis的一個有趣的現象來 - 使用Redis的作爲時間戳甲骨文 - 這樣的:Redis的Lua中的Math.random

... 
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,無論多麼頻繁執行腳本。

對我來說,這是不是什麼大不了的(因爲我可以追加腳本返回後的隨機數字),但我沒想到這個行爲,因此需要相當長的一段時間才能找到我的錯誤。

我希望這個信息可以節省一些時間。

+0

嘗試'''math.randomseed(os.time())'''在腳本的頂部。 – warspyking

+1

@warspyking - 將不起作用,這是因爲Redis Lua沙箱沒有'os' lib,並且在任何情況下,Redis的math.random被設計爲在使用基於腳本的複製時產生相同的值v3.2之前的唯一模式) –

+0

@Itamar嗯,它確實可以是任何不斷變化的東西。不一定是'''os.time'''。 – warspyking

回答

2

我認爲這種行爲的原因是,Redis嘗試t o防止人們在腳本內部生成隨機密鑰,因爲在複製時,這些腳本會被髮送到副本(而不是數據本身)。因此生成隨機密鑰可能會導致不一致的副本。

這就是爲什麼在呼叫redis.call('TIME')之後,腳本中不允許寫入Redis。

我的猜測是,由於相同的原因,Redis中的Lua環境總是返回與math.random()相同的數字。

+1

非常真實。但是,從v3.2開始,有一種新的複製模式可以改變這種行爲:http://redis.io/commands/eval#selective-replication-of-commands –

2

如果您正在調用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)) 

這也避免了任何未來的問題瓦特/複製,因爲所有的情況下,將收到相同的參數,併產生相同的輸出。

+2

儘管OP實際上並沒有提出問題,但我認爲這是「我應該如何在redis lua腳本中生成僞隨機數字?」這個問題的最佳答案。 –