我需要在PHP中使用互斥锁或信号量,但这让我感到害怕。澄清一下,我不怕编写能正确同步且无死锁的代码,也不惧并发编程的危险,而是担心PHP处理边缘情况的能力。
快速背景:编写一个信用卡处理接口,位于用户和第三方信用卡网关之间。需要防止重复请求,并已经有一个可行的系统,但如果用户在毫秒级别同时点击提交(没有启用JS,因此我无法为其禁用按钮),会出现竞争条件,导致我的PHP脚本没有意识到已经发生了重复请求。需要互斥锁/信号量,以确保每个唯一事务只通过一个成功请求。
我在多核Linux机器上通过PHP-FPM在nginx后运行PHP。我想确保:
- 信号量在所有php-fpm进程之间共享,并跨越所有核心(i686内核)。
- php-fpm在持有互斥锁/信号量时处理PHP进程崩溃,并相应地释放它们。
- php-fpm在持有互斥锁/信号量时处理会话中止,并相应地释放它们。
是的,我知道。这些都是非常基本的问题,并且愚蠢地认为任何其他软件都没有一个正确的解决方案。但这是PHP,并不一定考虑并发性,它经常崩溃(取决于您加载了哪些扩展程序),而且处于不稳定的环境中(在PHP-FPM上以及在Web上)。
关于(1),我假设如果PHP使用POSIX函数,这两个条件在SMP i686机器上都成立。至于(2),我从简要浏览文档中看到有一个参数决定此行为(尽管我不明白为什么会希望PHP在会话终止时不释放互斥锁)。但是(3)是我的主要关注点,我不知道是否可以安全地假设php-fpm可以为我处理所有边界情况。我(显然)永远不想出现死锁,但我不确定是否可以相信PHP永远不会使我的代码处于无法获得互斥锁的状态,因为抓住它的会话已经被优雅或不优雅地终止。我考虑使用MySQL的LOCK TABLES
方法,但是在那里我甚至更加怀疑,因为虽然我相信MySQL锁比PHP锁更可靠,但我担心如果PHP在持有MySQL会话锁的同时中止请求(而*没有*崩溃),MySQL可能会保持表格锁定(特别是因为我可以轻易想象导致这种情况发生的代码)。
老实说,我最舒适的选择是使用非常基本的C扩展,以便我可以看到正在进行的POSIX调用以及使用哪些参数来确保我想要的精确行为.. 但我不希望写那些代码。
有人有关于PHP并发方面的最佳实践想分享吗?
flock()
来进行会话:http://thwartedefforts.org/2006/11/11/race-conditions-with-ajax-and-php-sessions/ - Kaii