[英]Best synchronization strategy to block worker threads when a database is down
[英]Multiple worker threads and Database synchronization
我有多个线程将文件保存在磁盘上并将该信息放入数据库。
在应用程序的另一侧,我有多个线程从数据库中读取此信息并处理提到的文件,一次一个,按file_id
排序:
SELECT * FROM files_to_process ORDER BY file_id
我发明的是制作一个PROCESSING_STATUS
列,它有四种状态NEW
、 PROCESSING
、 FAILED
、 SUCCESS
。
每个工作人员应该只从数据库中读取一行,该行按 ID 排序,状态为NEW
并立即更新为状态PROCESSING
,因此其他工作人员不会处理同一个文件。
但是,有些事情告诉我,我可能会遇到一些竞争条件。
交易会解决这个问题吗?
不幸的是我不能在交易中进行所有操作,因为处理文件需要很多时间并且交易池将被耗尽,所以我必须按以下顺序进行两个交易。
PROCESSING
SUCCESS
或FAILED
非常烦人的是,UPDATE 在 PostgreSQL 中不使用 LIMIT。
你可以这样做:
update files_to_process set processing_status='PROCESSING' where file_id = (
SELECT file_id FROM files_to_process
WHERE processing_status = 'NEW'
ORDER BY file_id FOR UPDATE SKIP LOCKED LIMIT 1
) returning *;
使用此公式,不应存在竞争条件。 您可以在事务中单独运行它(或在自动提交下,只需运行该语句,它就会自动形成自己的事务)。
但与其只使用“处理”,我可能会将其设置为“由机器 worker7 PID 19345 处理”或类似的东西。 否则,如果以不干净的方式失败,您如何知道处理何时失败? (这是在一个事务中完成它的好处,失败应该自行回滚)。
不幸的是我不能在交易中进行所有操作,因为处理文件需要很多时间并且交易池将被耗尽
但是,您的未完成事务永远不应超过可用于工作的 CPU。 除非你有一个非常大的计算场,否则你应该能够使池足够大。 但这种方法的大问题是您无法了解正在发生的事情。
对于两种事务方法,为了提高性能,您可能需要制作部分索引:
create index on files_to_process (file_id ) where processing_status = 'NEW';
否则,您将不得不挖掘所有具有低 file_id 的已完成文件以找到下一个新文件,最终会变慢。 您可能还需要比默认情况更积极地对表进行 VACUUM。
尝试一个互斥锁,简单的例子:
try {
mutex.acquire();
try {
// access and update record to processing
} finally {
mutex.release();
}
} catch(InterruptedException ie) {
// ...
}
根据您的代码,您可以通过多种方式锁定它,请参阅: Is there a Mutex in Java?
编辑:
抱歉,这是一个 c++ 问题,这是 java 版本
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.