Google App Engine (PHP) - 用于避免网上银行竞争条件的信号量或替代方案
Google App Engine (PHP) - Semaphores or alternatives to avoid Race Condition for an Internet Banking
我正在 网上银行 、运行 Google App Engine 开发,并在 PHP.
竞争条件是一个大问题。
用户的钱永远不能少于 0.00 美元(我知道我还有其他问题要担心,但现在让我们只关注这个问题)。
伪代码:
<?php
$user_id = $_GET['user_id'];
$withdraw_amount = $_GET['withdraw_amount'];
if(getUserBalance($user_id) - $withdraw_amount >= 0){
setUserBalance($user_id, getUserBalance($user_id) - $withdraw_amount);
sendMoneyToUser($user_id, $withdraw_amount);
echo 'Success';
}
else{
echo 'Insufficient funds';
}
?>
Google 云 SQL 数据库:
USER_ID BALANCE
1 10.00
2 20.00
*以上数据库是实际数据库的一个非常简单的版本。 SQL lock tables/rows 在现实世界中对我不起作用。但是如果你有另一个使用 SQL 而不是 PHP 的解决方案,我想知道它。
竞争条件案例:
GAE instance #1 GAE instance #2 (SAME TIME)
user_id = '1' user_id = '1'
withdraw_amount = 10.00 withdraw_amount = 10.00
balance = getUserBalance('1') balance = getUserBalance('1')
//balance = 10.00 //balance = 10.00
10.00 - 10.00 >= 0 -> (true) 10.00 - 10.00 >= 0 -> (true)
setUserBalance ('1', 0.00) setUserBalance ('1', 0.00)
sendMoneyToUser('1', 10.00) sendMoneyToUser('1', 10.00)
User gets .00 User gets .00
The user now has .00 in his hands, but he had just .00 in the bank!!!
如何防止竞争条件?
请记住,Google App Engine 上的代码是 运行,我无权访问 PHP 信号量 扩展。
一种方法是使用互斥库,该库使用 redis
之类的东西作为后端,这样您就可以从不同的机器调用它而不会出现问题。
在操作开始之前获取特定于用户的锁,完成您的工作然后释放锁。在您进行操作时,连续调用操作将失败,因为它们无法获取锁。
在伪代码中,这将很简单:
$lockName = "some string that contains the user/customer ID in it to be unique per customer";
if ( ! $mutex->acquireLock($lockName, 60) ) {
throw new Exception ("An operation is already running, please wait for it to finish and try again!");
}
// do the transaction data here, substract the amount, etc.
// once done, release the lock:
$mutex->releaseLock($lockName);
我正在 网上银行 、运行 Google App Engine 开发,并在 PHP.
竞争条件是一个大问题。 用户的钱永远不能少于 0.00 美元(我知道我还有其他问题要担心,但现在让我们只关注这个问题)。
伪代码:
<?php
$user_id = $_GET['user_id'];
$withdraw_amount = $_GET['withdraw_amount'];
if(getUserBalance($user_id) - $withdraw_amount >= 0){
setUserBalance($user_id, getUserBalance($user_id) - $withdraw_amount);
sendMoneyToUser($user_id, $withdraw_amount);
echo 'Success';
}
else{
echo 'Insufficient funds';
}
?>
Google 云 SQL 数据库:
USER_ID BALANCE
1 10.00
2 20.00
*以上数据库是实际数据库的一个非常简单的版本。 SQL lock tables/rows 在现实世界中对我不起作用。但是如果你有另一个使用 SQL 而不是 PHP 的解决方案,我想知道它。
竞争条件案例:
GAE instance #1 GAE instance #2 (SAME TIME)
user_id = '1' user_id = '1'
withdraw_amount = 10.00 withdraw_amount = 10.00
balance = getUserBalance('1') balance = getUserBalance('1')
//balance = 10.00 //balance = 10.00
10.00 - 10.00 >= 0 -> (true) 10.00 - 10.00 >= 0 -> (true)
setUserBalance ('1', 0.00) setUserBalance ('1', 0.00)
sendMoneyToUser('1', 10.00) sendMoneyToUser('1', 10.00)
User gets .00 User gets .00
The user now has .00 in his hands, but he had just .00 in the bank!!!
如何防止竞争条件?
请记住,Google App Engine 上的代码是 运行,我无权访问 PHP 信号量 扩展。
一种方法是使用互斥库,该库使用 redis
之类的东西作为后端,这样您就可以从不同的机器调用它而不会出现问题。
在操作开始之前获取特定于用户的锁,完成您的工作然后释放锁。在您进行操作时,连续调用操作将失败,因为它们无法获取锁。
在伪代码中,这将很简单:
$lockName = "some string that contains the user/customer ID in it to be unique per customer";
if ( ! $mutex->acquireLock($lockName, 60) ) {
throw new Exception ("An operation is already running, please wait for it to finish and try again!");
}
// do the transaction data here, substract the amount, etc.
// once done, release the lock:
$mutex->releaseLock($lockName);