RabbitMQ重复删除消息

时间:2015-10-23 19:39:10

标签: php rabbitmq

在正在运行的RabbitMQ服务器用户PHP上,

我有一个事件会触发一条消息"将用户X帐户带到5美元"到"充电"队列。但是,许多事件可能会发送此信息,如果有多个工作人员在系统上工作,我可以看到一个问题,即在用户获得双倍费用的情况下会发生竞争条件。

    $accountBalance = -25.00 // starts
    event 1: "Bring User X Account to $5"
    event 1: check balance, $balance = -25.00
    event 2: "Bring User X Account to $5"
    event 1: $chargeAmount = 30
    event 2: check balance, $balance = -25.00
    event 1: Charge Card $30 // takes 3s
    event 2: $chargeAmount = 30
    event 2: Charge Card $30 // takes 6s
    event 3: "Bring User X Account to $5"
    event 3: check balance, $balance = -25.00
    event 1: add transaction $30 //   $accountBalance = 5.00 
    event 1: END
    event 4: "Bring User X Account to $5"
    event 4: check balance, $balance = 5.00
    event 4: END
    event 2: add transaction $30 //   $accountBalance = 35.00 
    event 2: END
    event 3: $chargeAmount = 30
    event 3: Charge Card $30 // takes 3s
    event 3: add transaction $30 //   $accountBalance = 65.00 
    event 2: END
    $accountBalance = 65.00

正如你所看到的,有4个事件进入,而不是一次收费30美元,它收费三次。只有事件4退出,但因为事件1很快就结束了。

我玩过锁定的想法,但由于每个工作人员可能在一个独立的服务器上,这有点模糊。

是否有任何易于使用的开箱即用解决方案?

1 个答案:

答案 0 :(得分:1)

您需要使用分布式锁定来防止两个任务同时发生,同时使您的任务具有幂等性。即使您确实有锁,任务也需要能够运行并检测工作已完成并忽略。这两个概念共同发挥作用。

您可以使用memcached之类的内容进行分布式锁定。例如,您可以尝试LockBundle之类的内容。

$memcached = new Memcached();
$this->adapter = new MemcachedAdapter($memcached);
$lock = new Lock("test", $this->adapter);
$lock->acquire();
// Do stuff here //
$lock->release();

只需将锁密钥设置为您想要保护的粒度即可。如果您正在尝试为memcached崩溃做出一些有弹性的东西,那么HA有一些问题。

您还可以构建类似的东西,使用数据库表,您在字段上有PK并让进程尝试在表中插入值。 PK将阻止任何第二次尝试,并且一旦第一次尝试提交,后续的将由于PK违规而解除阻塞并失败。

然后可能会使用像Zookeeper这样的东西,虽然我从来没有这样做过。这比我想的memcached更有弹性。