我需要在PHP中使用互斥鎖或信號量,它嚇壞了我。爲了澄清,我不害怕編寫無死鎖的代碼,這些代碼能夠正確同步或者擔心併發編程的風險,但是PHP處理邊緣情況的能力如何。在PHP中預防競爭條件的最可靠和安全的方法
快速背景:寫一個位於用戶和第三方信用卡網關之間的信用卡處理程序接口。需要防止重複的請求,並且已經有一個適用的系統,但是如果用戶點擊提交(w/out JS啓用,所以我不能禁用它們的按鈕)幾毫秒,一個競爭條件發生在我的PHP腳本沒有意識到已經有重複的請求。需要一個信號量/互斥量,所以我可以確保每個唯一事務只有一個成功的請求。
我在多核心Linux機器上通過PHP-FPM與多進程運行PHP後面的nginx。我想確定
- 信號量在所有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的同時中止請求(帶* out *崩潰)會話鎖,MySQL可能會鎖定表(尤其是因爲我可以輕鬆設想導致此問題發生的代碼)。
老實說,我最舒服的是一個非常基本的C擴展,我可以準確地看到POSIX調用正在做什麼以及用什麼參數來確保我想要的確切行爲......但我並不期待編寫代碼。
任何人都有關於PHP願意分享的任何與併發有關的最佳實踐?
我不熟悉你的設置,但是當我看到你需要從被處理停止重複請求,我想知道爲什麼你無法檢查存儲在用戶會話中的[表單鍵](http://net.tutsplus.com/tutorials/php/secure-your-forms-with-form-keys/)。 – nickb 2012-02-15 07:14:40
這基本上是我現有的重復請求預防,而且似乎有一個特定的時間點,對於某些具有多個PHP進程的設置,存在與兩個PHP處理後端的爭用條件,請參閱token/nonce/whatever尚未處理。隨機數通常用於防止重放攻擊(或普通的XSS),但在我的情況下,它已經受到保護 - 除了數毫秒後作爲競爭條件重播的情況。 – 2012-02-15 07:28:25
也許這(略有過時)的論文在PHP和會話鎖定/比賽條件對你很有意思。但是,似乎至少PHP 5.3.2已經在會話中使用一致的'flock()':http://thwartedefforts.org/2006/11/11/race-conditions-with-ajax-and-php-sessions/ – Kaii 2012-02-15 08:45:55