【问题标题】:what are queue access concurrency solutions?什么是队列访问并发解决方案?
【发布时间】:2009-07-04 18:10:56
【问题描述】:

我试图找出实现队列系统的困难。我知道如何实现一个基本队列,所以我将解释一下我所追求的一些背景:

我将实现一个放置消息的队列,这将来自多个用户,消息将安排在用户定义的时间发布(从 UI 角度来看,允许以分钟为精度多次出现将限制:“每分钟或每小时”发生,但 id 喜欢系统仍然能够处理这个)。

这是我的问题所在: 最终,我可能处于当前需要发布许多消息的情况(也许不是),我希望运行多个进程(脚本的多个实例)来获取 [x,10,25] 编号一次来自队列的消息并处理它们。问题是:如何做到这一点,以便每个实例处理唯一的消息(不处理已经被另一个实例处理的东西)?我担心当前的连接、如何锁定记录以及我可能没有考虑的其他任何事情。

我将使用的技术是 PHP 和 MySQL。我正在寻找上述问题的一些解决方案、我应该在搜索中使用的术语、现实世界的示例、想法、cmets 和想法?

谢谢大家!

我遇到的一个解决方案是使用 Amazon Simple Queue Service ...它承诺独特的消息处理/锁定http://aws.amazon.com/sqs/

【问题讨论】:

    标签: php mysql transactions process innodb


    【解决方案1】:

    好吧,我会这样做:

    为消息制作表格并添加另外两个字段 - “PROCESS_ID”和“PROCESS_TIME”。这些将在后面解释。

    给每个进程一个唯一的 ID。它们可以在启动时生成(如 GUID),或者您可以自己分配它们(然后您可以更轻松地区分它们)。

    当一个进程想要获取一堆消息时,它会执行以下操作:

    1. UPDATE messages SET process_id=$id, process_time=now() where process_id is null LIMIT 20
    2. SELECT * FROM messages WHERE process_id=$id

    这将找到 20 条“免费”消息并“锁定”它们。然后它会找到它锁定的消息并处理它们。每条消息处理完毕后,DELETE它。

    UPDATE 语句应该是非常原子的,特别是如果您使用 InnoDB,它会自动将每个此类语句包装在事务中。 MySQL 应该负责那里的所有并发性。

    PROCESS_TIME 字段是可选的,但您可以使用它来查看进程何时挂起。如果消息被锁定的时间过长,您可以断定出现问题并进行调查。

    【讨论】:

    • 所以我对你的理解是正确的:MySQL 应该按照接收到的顺序处理每个 UPDATE,而且听起来如果同时接收到两个更新,MySQL 应该在内部自行处理,有人有这方面的文档链接吗?
    • 查看关于 InnoDB 部分下的 MySQL 文档。注意关于交易的部分。但是我认为(但我不确定)即使在没有事务支持的 MyISAM 下也可能有效。这个想法是,即使两个 UPDATE 语句可以同时运行,它们肯定不能同时访问同一行。如果他们愿意,这将造成巨大的混乱。但如果他们不能,那么你就已经安全了。您无法准确预测 UDPATE 将影响哪些行,但您知道没有两个 UPDATE 会发生冲突 - 这对您而言就足够了。
    • 我猜使用这种数据库模式,您会经常轮询队列中的消息?
    • 你还能想象到什么?不过不应该那么糟糕——MySQL 应该能够将这个表完全保存在 RAM 中。如果它变得太大,那么你已经有一个更严重的问题......
    • @Vilx,我相信查询缓存会在插入数据时被刷新。此外,进程 P1 如何知道进程 P2 何时在队列中插入消息。进程 P1 将轮询表。因为我认为当很多并发用户执行您的 msql 语句时,表会被阻塞很多?如果只有几个用户使用它,我认为这是一个非常好的解决方案,但我认为它会运行缓慢。
    【解决方案2】:

    你可以扭转这个问题。

    而不是同时将事情从队列中取出。获得所有信息后立即发布。 但是发布它的规则是它在特定时间之前不可见。以这种方式做事可以帮助您避免锁定/争用问题。

    【讨论】:

    • 我喜欢它......有趣的想法,我一定会记住这个作为解决方案......我的情况略有不同,将与 API 交互以实际发布消息到第 3 方系统。
    【解决方案3】:

    查看Beanstalkd 消息队列。它有 PHP 客户端。 Beanstalkd(相对于例如 dropr)的一个不错的功能是您可以延迟消息。也就是说,您可以将消息发布到队列中,直到 X 秒过去后才会将消息传递给客户端。

    Beanstalkd 确实有一个很大的缺点:它是一个内存队列。这意味着如果它(或您的机器)崩溃,则队列为空并且内容丢失。持久性是 beantalkd 下一版本计划的一项功能。

    【讨论】:

    • 它现在已经有一段时间了:-b 使用 binlog 将作业保存在 中的持久存储上。启动时,beantalkd 将恢复 中存在的所有 binlog,然后在正常运行期间,将新作业和状态更改附加到 binlog。
    • 酷,谢谢。然后我将升级我所有的 beanstalkd 实例。
    【解决方案4】:

    几个在线解决方案:

    1. Amazon SQS
    2. Google appengine queue system

    我猜谷歌的解决方案要便宜得多(如果用得不多,甚至可以免费)。

    我也一直在考虑在 PHP/MYSQL 中实现队列并考虑使用:

    1. mysql get_lock 来实现某种锁。
    2. 将队列放入 MYSQL memory heap 数据存储中,因为内存队列比磁盘队列快得多。但是您有在计算机崩溃时丢失数据的风险。
    3. 使用named pipes 与进程通信。

    【讨论】:

      猜你喜欢
      • 2016-10-10
      • 2018-04-02
      • 2022-11-02
      • 1970-01-01
      • 2012-10-14
      • 1970-01-01
      • 2014-12-15
      • 2014-12-04
      • 2020-08-09
      相关资源
      最近更新 更多