6

也就是说,我想附加到一个排序集,例如:

“set1”-> [1371772258、1371772265、1371772299 等]

但我不想从我的服务器发送时间值。我想从一台服务器的时钟中获得一致的时间戳,服务器 redis 正在运行。

4

2 回答 2

4

此解决方案从 Redis 版本 2.6.0 开始有效

如果 Redis 提供 Luaos.time功能,可能会有简单的解决方案,但事实并非如此。

所以我发明了一些技巧。我们可以EXPIREAT在未来设置,然后TTL我们将知道当前的 unix 时间戳。

这是概念证明。当然,您至少可以进行 2 项优化:future在您的 redis 数据库中设置一次密钥,然后在 lua 脚本中读取它的 ttl,显然evalsha使用eval.

zaddts.lua

local future_ts, cur_ts, zkey, zmember

future_ts = 2000000000
redis.call('setnx', 'future', 1)
redis.call('expireat', 'future', future_ts)
cur_ts = future_ts - redis.call('ttl', 'future')
zkey = KEYS[1]
zmember = KEYS[2]
return redis.call('zadd', zkey, cur_ts, zmember)

带有硬编码时间戳的 oneliner 示例:

return redis.call('zadd', KEYS[1], 2000000000 - redis.call('ttl', 'future'), KEYS[2])

示例-client.php

<?php
ini_set('display_errors', true);

$r = new Redis();
$r->connect('localhost');

$script = file_get_contents('zaddts.lua');

$r->eval($script, array('events', 'event1'), 2);
sleep(1);
$r->eval($script, array('events', 'event2'), 2);
print_r($r->zrange('events', 0, -1, $withscore = true));
/* Output:
Array
(
    [event1] => 1371777755
    [event2] => 1371777756
)
*/

UPD: [捂脸]我没有看到TIME命令。有了它,lua 脚本变得更加简单:

zaddts.lua

local time_full, time_sec, zkey, zmember

zkey = KEYS[1]
zmember = KEYS[2]

time_full = redis.call('time')
time_sec = tonumber(time_full[1])

return redis.call('zadd', zkey, time_sec, zmember)

UPD 2:由于 redis lua 脚本限制(脚本作为纯函数),带有time调​​用的代码不起作用:

redis 127.0.0.1:6379> eval "return redis.call('zadd', 'events', redis.call('time')[1], 'some-event')" 0
(error) ERR Error running script (call to f_426eeadf424497fc04eb8f06efac0553f3212660): Write commands not allowed after non deterministic commands 

所以第一个版本的代码(带ttl)仍然有意义。

于 2013-06-21T01:23:54.027 回答
1

您可以简单地使用TIME 命令(可用于 Redis 2.6)。它返回两个值:以秒为单位的纪元和微秒数。

您可以直接从应用程序调用它。在这种情况下,将需要 2 次往返(一次用于执行 TIME,一次用于更新 zset)。

于 2013-06-21T08:29:12.107 回答