Redis中的自动增量

时间:2011-03-16 17:00:27

标签: redis

我开始使用Redis,我遇到了以下问题。

我有一堆对象,比如我的系统中的Messages。每次新的User连接时,我都会执行以下操作:

  1. INCR一些全局变量,假设为g_message_id,并保存INCR的返回值(g_message_id的当前值)。

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

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

    问题是,假设有新消息,一个客户端可以INCR g_message_id,但在另一个客户端尝试读取消息之前没有时间LPUSH消息。< / p>

    换句话说,我正在寻找一种方法来相当于在SQL中添加行,并使用自动递增的索引来处理。

    备注

    我无法使用列表索引,因为我经常要删除列表中的部分内容,使其无效。

    我的实际情况有点复杂,这是一个更简单的版本。

    当前解决方案

    我提出的最佳解决方案以及我打算做的是使用WATCHTransactions来尝试自己执行“自动增量”。

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

3 个答案:

答案 0 :(得分: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

可能的替代方案,如果您的客户可以支持:您可能需要查看 Redis publish/subscribe个命令,例如客户可以发布新消息的通知并订阅一个或多个消息通道以接收通知。如有必要,您可以保留 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 list index limit ”来获取新邮件。假设一个阅读器客户端总共看到了5条消息,它将运行“ LRANGE g_msg_queue 5 15 ”来获取接下来的10条消息。假设返回3,所以它会记住索引 8 。您可以根据需要设置限制,并可以小批量遍历列表。
  5. 收割者客户端应在列表中设置 WATCH 并在事务中删除它,如果任何客户端同时从中读取,则中止。
  6. 当阅读器客户端尝试LRANGE并获得0条消息时,它可以假定该列表已被截断并将其索引重置为 0

答案 1 :(得分:5)

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

如果您确实需要唯一的顺序ID,那么您可能需要设置Flickr style ticket server来正确管理ID的中央列表。实质上,这会将您的g_message_id移动到具有正确事务处理的数据库中。

答案 2 :(得分:0)

您可以模拟自动递增新行的唯一键。只需使用DBSIZE即可获取当前行数,然后在代码中将该数字递增1,然后将该数字用作新行的键。简单而原子。