实现基于并发表的队列的最佳方法

Mig*_*l E 12 mysql queue

我在 MySQL 中有一个表,表示要处理的链接队列。链接由外部应用程序一一处理,最后删除。这是一个大容量队列,我有处理应用程序的多个实例,分布在多个服务器上。

如何确保每条记录仅由一个应用程序选取?有没有办法标记/锁定记录?

现在,为了避免两个或多个获取相同的链接,我只允许每个实例获取一组特定的记录(基于其 ID 的 MOD),但这不是增加队列处理的透明方式只需添加新实例即可加快速度。

jyn*_*nus 9

第一:MySQL 是实现这一点的最糟糕的软件之一,特别是如果它非常动态。原因是像 MEMORY 和 MyISAM 这样的引擎只有全表锁,而像 InnoDB 这样更合适的引擎有更高的写惩罚(提供 ACID 属性),并且针对访问空间和时间上接近的记录(那些设置在内存上)进行了优化)。MySQL 也没有一个好的更改通知系统——它必须作为轮询来实现。有许多针对该任务进行了更优化的软件

话虽如此,如果性能/效率要求不是很高,我已经看到成功实现这种访问。许多人无法只为一小部分业务逻辑引入和维护一个完整的独立技术。

SELECT FOR UPDATE是您正在寻找的 - 读取序列化。虽然 UPDATE/DELETE 将始终在运行 MYSQL 事务期间锁定该行,但您可能希望在进程进行时避免大型事务,因此:

START TRANSACTION;
SELECT * FROM your_table WHERE state != 'PROCESSING' 
  ORDER BY date_added ASC LIMIT 1 FOR UPDATE;
if (rows_selected = 0) { //finished processing the queue, abort}
else {
UPDATE your_table WHERE id = $row.id SET state = 'PROCESSING'
COMMIT;

// row is processed here, outside of the transaction, and it can take as much time as we want

// once we finish:
DELETE FROM your_table WHERE id = $row.id and state = 'PROCESSING' LIMIT 1;
}
Run Code Online (Sandbox Code Playgroud)

MySQL 会在选择行时锁定除一个之外的所有并发选择。由于这可能会同时导致大量锁定连接,因此请使初始事务尽可能小,并尝试一次处理多于 1 行。


Vla*_*cea 5

正如我在本文中解释的那样,MySQL 8 引入了对 SKIP LOCKED 和 NO WAIT 的支持。

SKIP LOCKED 可用于实现作业队列(又名批处理队列),以便您可以跳过已被其他并发事务锁定的锁。

NO WAIT 可用于避免等待直到并发事务释放我们也对锁定感兴趣的锁。如果没有 NO WAIT,我们要么必须等到锁被释放(在当前持有锁的事务提交或释放时)或锁获取超时。因此,NO WAIT 就像一个值为 的锁超时0

有关 SKIP LOCK 和 NO WAIT 的更多详细信息,请查看这篇文章