PMo*_*bed 2 postgresql concurrency worker-process
我在PostgreSQL中有如下查询:
UPDATE
queue
SET
queue.status = 'PROCESSING'
WHERE
queue.status = 'WAITING' AND
queue.id = (SELECT id FROM queue WHERE STATUS = 'WAITING' LIMIT 1 )
RETURNING
queue.id
Run Code Online (Sandbox Code Playgroud)
并且许多工人尝试一次处理一项工作(这就是为什么我有限制1的子查询).在此更新之后,每个工作人员都会获取有关id的信息并处理工作,但有时他们会抓取相同的工作并处理两次或更多次.隔离级别为Read Committed.
我的问题是如何保证一件作品要处理一次?我知道那里有很多帖子,但我可以说我已经尝试了大部分帖子但它没有帮助();
AND pg_try_advisory_xact_lock(queue.id)外部查询的WHERE子句,但是...... [?]任何帮助,将不胜感激.
在您描述的情况下不会发生丢失的更新,但它也无法正常工作.
在上面给出的示例中会发生的事情是,给定(比如说)10个工作者同时启动,所有10个工作程序将执行子查询并获得相同的ID.他们都会试图锁定该ID.其中一个会成功; 其他人将阻止第一个人的锁定.一旦第一个后端提交或回滚,其他9个将争夺锁定.一个人会得到它,重新检查WHERE子句并看到queue.status测试不再匹配,并返回而不修改任何行.其他8也会发生同样的情况.因此,您使用10个查询来完成一个查询的工作.
如果您未能明确检查UPDATE结果并看到零行已更新,您可能会认为您丢失了更新,但事实并非如此.由于对执行顺序和隔离规则的误解,导致应用程序中出现并发错误.真正发生的一切就是你有效地序列化你的后端,这样一次只能有一个实际上取得进展.
PostgreSQL可以避免让它们都获得相同的队列项ID的唯一方法是将它们序列化,因此在查询#1完成之前它不会开始执行查询#2.如果你愿意,你可以通过LOCK队列表来做到这一点......但是,你可能只需要一个工作人员.
你不能用咨询锁来解决这个问题,不管怎么说都不容易.你使用非阻塞锁定尝试迭代队列的黑客,直到你得到第一个可锁定的项目,但是会很慢而且很笨拙.
您正在尝试使用RDBMS实现工作队列.这不会很好.这将是缓慢的,它将是痛苦的,并且正确和快速地获得它将非常非常困难.不要自己动手.相反,使用完善的,经过良好测试的系统来实现可靠的任务排队.看看RabbitMQ,ZeroMQ,Apache ActiveMQ,Celery等.还有来自Skytools的PGQ,这是一个基于PostgreSQL的解决方案.
有关:
| 归档时间: |
|
| 查看次数: |
758 次 |
| 最近记录: |