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