Widodws下面加鎖失敗, Linux下是ok的
在修改用戶余額/積分的時候需要增加一個業(yè)務(wù)鎖來實現(xiàn)具體的功能
需要加鎖的時候發(fā)現(xiàn)加鎖失敗,然后去追了一下插件的源碼,發(fā)現(xiàn)代碼核心用的都是Symfony/lock,然后去翻看官方文件, 跳過插件直接去加鎖
平臺 | 第1秒發(fā)送第一次請求 | 第1次程序響應(yīng)時間 | 第2秒發(fā)送第二次請求 | 第2次程序響應(yīng)時間 | 結(jié)果 |
---|---|---|---|---|---|
Webman | 加鎖成功,業(yè)務(wù)執(zhí)行中 | 5s | 加鎖成功,業(yè)務(wù)執(zhí)行中 | 10s | ✗ |
Thinkphp6 | 加鎖成功,業(yè)務(wù)執(zhí)行中 | 5s | 加鎖失敗,返回異常 | 0s | ✓ |
use support\Redis;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\Store\RedisStore;
public function lock(){
$redis = Redis::connection('default')->client();
$store = new RedisStore($redis,300);
$factory = new LockFactory($store);
$lock = $factory->createLock('pdf-invoice-generation-webman');
if ($lock->acquire()) {
//模擬接口請求5秒后響應(yīng)
$this->httpSend("http://tp6.com/index.php/pipe/curl");
return "Webman加鎖成功";
}
return 'gg';
}
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\Store\RedisStore;
public function lock(){
$redis = new \Redis();
$redis->connect('127.0.0.1', '6379');
$redis->auth('admin123');
$store = new RedisStore($redis, 300, false);
$factory = new LockFactory($store);
$lock = $factory->createLock('pdf-invoice-generation-tp6');
if ($lock->acquire()) {
//模擬接口請求5秒后響應(yīng)
$this->httpSend('http://tp6.com/index.php/pipe/curl');
echo 'TP6加鎖成功';die;
}
echo 'gg';die;
}
"require": {
"php": ">=8.0",
"workerman/webman-framework": "^1.5.0",
"monolog/monolog": "^2.0",
"yzh52521/webman-lock": "^1.0",
"psr/container": "^1.1.1",
"illuminate/redis": "^9.52",
"illuminate/events": "^9.52",
"guzzlehttp/guzzle": "^7.5"
},
感覺是你加鎖成功并完成業(yè)務(wù)以后,沒有釋放鎖造成。
tp
框架因為fpm的原因在請求結(jié)束自動給你釋放了,Webman
卻不會。
推測Webman顯示一次Webman加鎖成功
,以后每次都是gg
.
tp
框架取決于httpSend
阻塞時間,如果真的是阻塞5s。那每5秒內(nèi)顯示一次TP6加鎖成功
然后顯示gg
,按周期循環(huán)。
createLock 這個第三個參數(shù)就是是否自動釋放鎖, 默認是true
TP 同時請求2次, 第一次等待5秒后顯示TP加鎖成功, 第二次無需等待秒返回gg
Webman 同時請求2次, 一直顯示的是Webman加鎖成功, 不會出現(xiàn)gg的情況
真實的業(yè)務(wù)場景TP肯定是對的, 第一次請求加鎖成功->程序執(zhí)行中, 此時用戶來了第二次請求->加鎖失敗->立馬返回異常
也就是說Webman的那兩個插件其實都是有問題的
$this->httpSend("http://tp6.com/index.php/pipe/curl");
后面自己釋放鎖。$lock->release();
他的自動釋放肯定有條件的,比如業(yè)務(wù)執(zhí)行超過一定時間。你知道業(yè)務(wù)阻塞5s,那超時就要設(shè)置比這長。
取消了httpSend
增加了
sleep(5);
$lock->release();
結(jié)果還是和之前一樣, 第二次請求是10秒鐘后執(zhí)行成功
有點坑啊,我還用webman搞了個正式運營的網(wǎng)站。
官方文檔說不建議在windows下使用,我理解為windows的webman性能不如linux的webman。
按現(xiàn)在的情況,感覺window下的webman干不過fpm框架的,畢竟apache、nginx都支持windows的。
public function lock()
{
var_dump('start ' . microtime(true));
$redis = Redis::connection()->client();
$store = new RedisStore($redis, 300);
$factory = new LockFactory($store);
var_dump('lock ' . microtime(true));
$lock = $factory->createLock('pdf-invoice-generation-webman');
if ($lock->acquire()) {
//模擬接口請求5秒后響應(yīng)
sleep(5);
$lock->release();
var_dump('lock release ' . microtime(true));
return "Webman加鎖成功";
}
return 'gg';
}
// windows環(huán)境
// 'count' => cpu_count() * 4,
// 兩個請求同時訪問
string(20) "start 1678857468.215"
string(20) "lock 1678857468.2428"
string(28) "lock release 1678857473.2614"
string(21) "start 1678857473.2629"
string(20) "lock 1678857473.2632"
string(28) "lock release 1678857478.2766"
windows版本下的workman不支持多線程,所以一個阻塞就會阻塞所有的請求。windows下面千萬不要用于正式環(huán)境。
作者開發(fā)的另外一個版本,估計是已經(jīng)放棄了:
https://github.com/walkor/workerman-MT
測試了一下,自定義進程可以解決阻塞問題。
http://www.wtbis.cn/doc/webman/others/task.html
感覺windows環(huán)境可以再優(yōu)化一下。
webman http://0.0.0.0:8787 4 [ok]
上面的進程數(shù)數(shù)4無意義,只會誤導人。
應(yīng)該按照設(shè)置的進程數(shù)量,自動拆分,每個端口對應(yīng)一個進程,端口范圍8787~8791。至于怎么負載均衡,由用戶自己去使用apache或nginx處理。
webman http://0.0.0.0:8787-8791 4 [ok]