2011-03-16 85 views
6

我开始使用Redis,并遇到以下问题。Redis中的自动增量

我有一堆物体,比方说我的系统中有Messages。每一个新的User连接时,我做到以下几点:

  1. INCR一些全局变量,比方说g_message_id,并保存INCR的返回值(的g_message_id当前值)。

  2. LPUSH将新消息(包括id和实际消息)放入列表中。

其他客户端使用值g_message_id来检查是否有任何新消息要获取。

问题是,一个客户端可以INCRg_message_id,但没有时间另一个客户端试图读取它之前LPUSH消息,假设有一个新的消息。

换句话说,我正在寻找一种方法来完成在SQL中添加行,以及使用自动递增索引的方式。

注意

我不能使用列表索引,因为我经常要删除列表中的部分,使之无效。

我的现实情况稍微复杂一些,这是一个更简单的版本。

目前的解决方案

最好的解决方案我已经出来,我打算做的是使用WATCHTransactions尝试和执行“自动增量”自己。

但是在Redis中这是一个很常见的用例,我很惊讶没有现成的答案,所以我担心我做错了什么。

回答

7

如果我的阅读正确,您将使用g_message_id作为id序列和标记以指示新消息可用。一种选择是将其分成两个变量:一个用于分配消息标识符,另一个作为标志向客户端发送新消息可用的标志。然后

客户可以比较g_new_message_flag的电流/前值知道什么时候可用新信息:

> INCR g_message_id 
(integer) 123 

# construct the message with id=123 in code 

> MULTI 
OK 
> INCR g_new_message_flag 
QUEUED 
> LPUSH g_msg_queue "{\"id\": 123, \"msg\": \"hey\"}" 
QUEUED 
> EXEC 

可能的选择,如果您的客户端可以支持:你可能想看看命令,例如客户可以发布新消息的通知并订阅一个或多个消息通道以接收通知。如有必要,您可以让g_msg_queue为新客户端维护N条消息的积压。基于评论

更新:如果希望每个客户端检测到有可用的消息,弹出所有可用和零淘汰名单,一个选择是使用一个事务读取列表:

# assuming the message queue contains "123", "456", "789".. 
# a client detects there are new messages, then runs this: 

> WATCH g_msg_queue 
OK 
> LRANGE g_msg_queue 0 100000 
QUEUED 
> DEL g_msg_queue 
QUEUED 
> EXEC 
1) 1) "789" 
    2) "456" 
    3) "123" 
2) (integer) 1 

更新2:鉴于新的信息,这是我会做:

  1. 让你的作家客户端使用RPUSH到将新消息附加到列表中。这可以让读者客户端从0开始并在列表中迭代以获取新消息。
  2. 读者只需要记住他们从列表中获取的最后一条消息的索引。
  3. 读者手表g_new_message_flag知道何时从列表中获取。
  4. 然后,每个读卡器客户端将使用“LRANGE列表索引限制”来获取新消息。假设一个阅读器客户端总共看到5条消息,它将运行“LRANGE g_msg_queue 5 15”以获得接下来的10条消息。假设有3个返回,所以它记得索引。您可以根据需要设定极限,并且可以小批量地浏览列表。
  5. 收割者客户端应该在列表上设置一个WATCH,并在事务内部删除它,如果有任何客户正在同时读取它,则中止。
  6. 当阅读器客户端尝试LRANGE并获得0消息时,它可以假定列表已被截断并将其索引重置为。
+0

有趣。这导致了一个相关的问题:当客户端使用其“g_new_message_flag”副本轮询服务器时,服务器如何从列表中检索消息?它可以根据“g_new_message_flag”和用户标志之间的差异取出一些消息,但是如果在减法操作和LPOP之间添加新消息,将弹出错误的消息数量。 – 2011-03-16 18:35:51

+0

我明白你的意思 - 如果客户端应该弹出所有可用的消息并将列表清零,那就更加棘手。我会用一些想法更新我的答案。 – samplebias 2011-03-16 18:58:59

+0

实际上,我不希望客户端删除邮件,只是获取最新邮件。我有几个不同的客户端(可能)有不同的g_msg_queue值,每个客户端都需要阅读已经到达的最新消息。该列表仅由后台进程定期删除(例如每天一次)。 – 2011-03-16 19:12:24

3

你真的需要唯一的顺序ID吗?您可以使用UUIDs来获得唯一性和时间戳以检查新消息。如果您保持所有服务器上的时钟正确同步,那么具有一秒分辨率的时间戳应该可以正常工作。

如果您确实需要唯一的顺序ID,那么您可能必须设置Flickr style ticket server才能正确管理ID的中央列表。实质上,这会将您的g_message_id转换为具有适当事务处理的数据库。

+0

解决了我的问题..UUID完全适合我的情况 – FloatingRock 2014-11-17 12:14:19