鍍金池/ 問答/PHP  Linux/ 關(guān)于php解決并發(fā)的一些疑惑

關(guān)于php解決并發(fā)的一些疑惑

首先 并發(fā)我是這樣理解的:

2 個人同時下單, 庫存只有 1, 那么肯定有一個人無法搶到。也就是說, 庫存只會減 1, 訂單也只會生成一條。

后來我用 Jmemter 模擬 1000 人同時操作, 發(fā)現(xiàn)訂單確實(shí)只有一個, 而且?guī)齑嬉矝]有負(fù)數(shù), 但是我并沒有做什么鎖啊或者隊(duì)列這些一談到并發(fā)就會涉及到的東西。

$a 是查詢到的庫存

$b = $a-1;

if($b>=0){
    生成訂單
    修改庫存
}

如果沒有 if 判斷, 確實(shí)會負(fù)。但是如果加了這個 if 判斷就庫存只減少 1, 訂單只有一條

那么我的問題來了, 加個 if 判斷就能解決并發(fā)? 還是說實(shí)際上真正要處理的是模擬測試后出現(xiàn)的錯誤率 (Jmemter, 模擬 1000 人, error:59.5%), 或者其他?

請各位大佬解答, 如果我的思路有錯誤, 也請毫不留情

回答
編輯回答
近義詞

1、將字段設(shè)置為UNSIGNED,然后基礎(chǔ)sql如 set a=a-1 where a>0,不要先讀出來,然后再操作,可以在一定程度上減少你的并發(fā)為負(fù)數(shù)的可能
2、串行化操作,比如使用redis隊(duì)列
3、使用redis或者別的原子遞增模擬鎖操作,比如 incr("lock") == 1 { 進(jìn)行減操作; 刪除lock)} else 自旋,直到得到鎖進(jìn)行以上操作,或者超時

基本上php解決如上問題的思路!!

2018年9月21日 05:07
編輯回答
我甘愿

你說的訂單問題,其實(shí)是:高并發(fā)場景下,如何正確扣減庫存的問題
if($b>=0) 這樣的判斷,在高并發(fā)的場景下并不使用,因?yàn)檫@樣的業(yè)務(wù)邏輯判斷并不是 原子操作,所以存在 臟讀 的可能。
例如:

由兩個請求同時到達(dá) 服務(wù)端(分別名為:p1, p2),p1 先取到了數(shù)據(jù),走到了 if 判斷,
此時 p2 也取到了數(shù)據(jù),但是 p1 還沒有更新數(shù)據(jù)庫,所以 p2 取到的數(shù)據(jù)跟 p1 是一樣的,所以,p1 p2 得到的 $b 值是一樣的, p2 也可以通過 if 條件,但是這兩個請求只扣減了一次存庫。

如何解決這個問題呢?

  • 加鎖;

  • 隊(duì)列:改并行為串行,依次扣減;

  • 操作轉(zhuǎn)換為原子操作;

不光是數(shù)據(jù)庫操作,高并發(fā)場景下,還可能會面對什么問題呢:

  • 單點(diǎn)問題(當(dāng)然 非剛并發(fā)場景也會面臨這個問題,但是高并發(fā)場景,此問題尤為突出)

  • 最大連接數(shù)問題,eg. web 服務(wù)器 數(shù)據(jù)庫 ...

  • 數(shù)據(jù)安全問題,eg. 臟讀 重復(fù)操作

2017年4月8日 10:40
編輯回答
你好胸

如果插入的訂單沒有數(shù)據(jù)庫唯一性沖突,應(yīng)該會生成多個訂單。建議在if里面先sleep(rand(0,5))再執(zhí)行插入訂單操作,這樣模擬更真實(shí)些。

2017年4月11日 06:13
編輯回答
生性

實(shí)際中可能是這樣的,你的$a是查詢出來的對吧,有可能在高并發(fā)的場景下你走了if判斷但是沒有改變庫存的情況下,其他請求已經(jīng)在讀數(shù)據(jù)了,這個時候你讀到的$a就是沒減少庫存時候的狀態(tài)。這只是其中一點(diǎn),最可怕的是如果你用的mysql數(shù)據(jù)庫,查詢和修改都會加鎖在并發(fā)很高的情況下可能會把表直接鎖死,其他的操作在等待中,一旦等待執(zhí)行時間過長、執(zhí)行過多,數(shù)據(jù)庫就掛掉了。還有你這個測試1000并發(fā)的時候使用的代碼并不是實(shí)際業(yè)務(wù)中的代碼,因?yàn)槿绻麥p庫存這種操作,肯定會有很多相關(guān)的邏輯判斷,1000個并發(fā)執(zhí)行起來就沒你想象的這么完美了。

2018年4月13日 21:36
編輯回答
墨染殤

最好使用Redis做原子鎖 因?yàn)樗蔷€程安全的

2017年1月8日 20:45
編輯回答
好難瘦

這類需求主要還是講邏輯的嚴(yán)密性而非并發(fā)時的情形!
你可能看到了所謂的if,但忽略了數(shù)據(jù)庫的重要性.
比如下單是一個從訂單狀態(tài)庫存狀態(tài)的過程.
那么下單這個過程生成肯定會涉及order_id的唯一性,
此時是否并發(fā)就不再重要,數(shù)據(jù)的唯一性才是最重要的.
而此后,才是你的所謂if減庫存過程.

2017年9月21日 19:48