0824_并發(fā)沖突處理

并發(fā)沖突處理

概述

大家可能都有這樣的經(jīng)驗项戴,在家里很多功能很容易實現(xiàn),一下就做完了肤无,但是在做線上產(chǎn)品的時候先蒋,就變得無比復(fù)雜,需要花費很多的時間宛渐。

自己寫的程序在家跑竞漾,所有的業(yè)務(wù)都很正常,一旦發(fā)布到線上窥翩,就會出現(xiàn)很多bug业岁,而且很多bug在測試的時候很難重現(xiàn),這是在互聯(lián)網(wǎng)開發(fā)的時候經(jīng)常遇到的現(xiàn)象寇蚊。

這些難以重現(xiàn)的bug笔时,大部分是由于并發(fā)產(chǎn)生的,為了能讓大家充分的了解并發(fā)的問題仗岸,并且建立并發(fā)環(huán)境下的程序設(shè)計思維允耿,特地為大家準備了幾個小案例

1.png

上圖是一個網(wǎng)站典型的場景,遇到內(nèi)容比較多的情況下扒怖,我們會使用分頁

如果是在移動端较锡,我們采用的是上拉刷新和下拉刷新,比如手機微博

2.png

分頁功能由來已久盗痒,我們現(xiàn)在來看下常見的分頁有什么問題呢念链?

大家看下面展示的這個項目是用thinkPHP來編寫的。很多流行的框架和開源項目都對分頁做了支持积糯,那么大家來看一個演示案例掂墓。

3.png

看到的現(xiàn)在的第一頁是最新的新聞,如果點擊下一頁看成,相對來說是老一點的新聞君编。

4.png

這個時候如果新打開一個瀏覽器窗口,剛剛的分頁頁面不要關(guān)閉川慌,并且在后臺里面再發(fā)布5篇新聞吃嘿,

假設(shè)在后臺發(fā)布新聞的同時,用戶還在瀏覽第二頁梦重,當發(fā)布完畢以后兑燥,用戶又點了下一頁,則會觀察到了奇特的現(xiàn)象

頁面顯示的第3頁和剛剛看到的第二頁完全一樣琴拧,原本用戶點下一頁希望看到再早一些的新聞降瞳,結(jié)果看到了一樣的數(shù)據(jù),是分頁程序出問題了嗎?非也挣饥。

當再點下一頁除师,程序又正常工作了。剛剛出現(xiàn)的奇怪的那一幕扔枫,其實就是由于并發(fā)產(chǎn)生的沖突汛聚。

在什么地方遇到了并發(fā)操作了呢?其實就是在一個用戶瀏覽頁面的同時短荐,還有人在往數(shù)據(jù)庫里面寫入數(shù)據(jù)倚舀。你會發(fā)現(xiàn)thinkPHP這樣的框架,還是PHPCMS這樣的開源系統(tǒng)忍宋,他們都存在這樣的bug瞄桨。

并發(fā)產(chǎn)生的問題,往往難以捕捉讶踪,更難以重現(xiàn)芯侥,而上面這個案例,算是并發(fā)案例沖突中相對容易重新的典型案例

下面來調(diào)整一下剛剛操作的順序乳讥,看看會得到一些其他的結(jié)果柱查。

比如說:分頁條目數(shù)是每頁5條,在用戶瀏覽某一頁的時候云石,后臺管理員發(fā)布了新的新聞唉工,新聞的數(shù)量小于5條的情況下,點擊下一頁汹忠,會看到有幾條重復(fù)的新聞淋硝,也有更早的新聞

這樣影響用戶體驗,但畢竟點下一頁時候內(nèi)容還是能接的上的宽菜,用戶瀏覽某一頁的時候谣膳,后臺發(fā)布的新聞數(shù)量大于分頁條目數(shù)(5條)

那么再點擊下一頁,其中會有若干條新聞被跳過去了铅乡,無論用戶點多少次下一頁继谚,都看不到那些條目,這種產(chǎn)生的并發(fā)沖突后果是很嚴重的阵幸,而且普遍存在花履。

它具有很好的隱蔽性,在過去很多年幾乎不被察覺

在大門戶網(wǎng)站時代挚赊,網(wǎng)站編輯并不會頻繁的發(fā)布新聞诡壁,而用戶也很少守著新聞列表去逐篇閱讀,然而在微博誕生以后荠割,這種問題就暴露出來了妹卿。

由于社區(qū)類應(yīng)用信息的產(chǎn)生是由用戶產(chǎn)生的,不在是靠編輯在后臺發(fā)布的,就好像微博纽帖,每時每分秒宠漩,都有很多用戶分享心得內(nèi)容

這樣一來你在查看微博列表的同時举反,內(nèi)容就已經(jīng)更新了很多懊直,而且很多人打發(fā)無聊的時間,很多人也會去逐一查看火鼻,不停的上劃室囊,把所有遺漏的條目全部看一遍

這是如果項目設(shè)計不合理,產(chǎn)生并發(fā)事故魁索,就會對用戶體驗造成極大的影響融撞。

待會再講并發(fā)沖突解決方案的時候告訴大家如何解決這種問題

現(xiàn)在來看一個更為常見的例子,大家都知道粗蔚,在微信群搞的抽獎的互動尝偎,上百份禮品,瞬間就被秒殺光鹏控。

在做這類搶購與秒殺抽獎等應(yīng)用的時候致扯,并發(fā)將導(dǎo)致更多的問題。通常比較容易出現(xiàn)的bug有實際商品的訂單量大于庫存量当辐。

通俗點來說就是抖僵,明明已經(jīng)售完,但還是有用戶買到了商品缘揪,庫存值變?yōu)樨摰摹?/p>

又或者明明秒殺到商品的用戶耍群,訂單失敗。

還有企業(yè)的項目找筝,在商品秒殺期間蹈垢,明明用戶數(shù)量不多,卻導(dǎo)致服務(wù)器宕機袖裕。諸如此類的問題就不一一列舉了耘婚。

接下來來看一下用常規(guī)思維來梳理業(yè)務(wù)流程程序是怎樣編寫的。

還是以商城秒殺業(yè)務(wù)為例陆赋。首先需要用產(chǎn)品庫存這樣的一個字段來記錄庫存信息沐祷,每當有用戶購買商品的時候,先查看庫存攒岛,判斷庫存大于0的時候赖临,用戶才能購買

當用戶完成購買流程后,將庫存數(shù)量減一灾锯,直到所有商品賣完兢榨,重復(fù)此過程,直到庫存賣完秒殺活動結(jié)束。

如果按常規(guī)的思路來設(shè)計吵聪,這樣的流程是沒有問題的凌那,商品畢竟是一件一件賣出的,但是吟逝,在互聯(lián)網(wǎng)并發(fā)的情況下帽蝶,就完全不是這樣的。

要知道熱銷商品很有可能在同一時間块攒,有多個用戶都在進行購買流程操作

按照之前的業(yè)務(wù)設(shè)計励稳,假如有ABCD 4個用戶同時在秒殺某件商品時,庫存僅剩2件囱井,按照之前的業(yè)務(wù)流程設(shè)計驹尼,查詢庫存大于0,就可以繼續(xù)后面的購買操作并付款

然而當任意用戶購買成功后庫存即減一庞呕,ABCD4個用戶都認為自己查詢時都有庫存新翎,因此他們都可以完成購買流程,導(dǎo)致的結(jié)果就是庫存數(shù)為負數(shù)住练。

也就是說地啰,商品實際銷售量大于活動的商品數(shù)量,這樣會導(dǎo)致公司的虧損澎羞。

有些公司為了解決這個問題髓绽,采用了一種思路,雖說4個人同時操作妆绞,但是交易成功的這次網(wǎng)絡(luò)請求到達服務(wù)器的時間總會有個先后順序

那么可以將訂單支付成功之后的庫存減一之后的值也隨訂單保存顺呕,如果這個值小于0,就證明有用戶購買了產(chǎn)品括饶,已經(jīng)是賣完的株茶,于是標記訂單失敗。

這樣看上去避免公司造成額外的損失图焰,但卻會給用戶帶來極大的不滿启盛,是一種極差的用戶體驗。它并沒有真正的解決我們的問題技羔。

當然還有些公司解決方案也不高明僵闯,無論是數(shù)據(jù)庫還是文件都可以給他加鎖,在很早期的程序設(shè)計和軟件開發(fā)里面藤滥,鎖是解決并發(fā)問題的萬能靈藥鳖粟。

無論是c++,或java,提到多進程或多線程的時候拙绊,往往也會提到鎖這個字向图。那么作為最早期的通用解決方案泳秀,用到秒殺方案是否合適呢?

那么來看一下加鎖后的工作流程:還是ABCD 4個用戶同時秒殺榄攀,他們都去查詢庫存嗜傅。當某一個用戶,比如A的請求檩赢,優(yōu)先到達時吕嘀,我們就將數(shù)據(jù)表鎖住,不讓其他的數(shù)據(jù)庫連接來動這張表漠畜,待用戶A完成購買流程币他,將庫存量減一后坞靶,把鎖打開憔狞,其他的連接才可以再次操作這張表。

如此一來彰阴,可以保障一個用戶查看庫存以及庫存減一這段時間內(nèi)瘾敢,不可能還有其他用戶可以對表做出修改,這一并發(fā)沖突的問題就沒有了尿这。不過這樣的做法真的合適嗎簇抵?

要知道ABCD 4個用戶都是在同一時間段去秒殺的,由于A用戶在操作中鎖表射众,導(dǎo)致其他用戶只能等待碟摆,而且A完成整個業(yè)務(wù)需要消耗一段時間,只能等A完成以后其他用戶才能操作

這樣一來單位時間內(nèi)的業(yè)務(wù)處理量會大幅降低叨橱,所看到的現(xiàn)象就是網(wǎng)站卡死典蜕,或者服務(wù)器宕機

關(guān)于并發(fā)性能如何設(shè)計,我們可能需要單獨的一次或幾次課來為大家講解罗洗。不過鎖這種很原始的并發(fā)沖突解決方案愉舔,我們可以看到他并不適合互聯(lián)網(wǎng)項目。

之所以大家會有并發(fā)沖突的程序伙菜,是因為大部分程序員轩缤,思維模式都是線性的。

作為程序邏輯思維來講贩绕,線性思維是沒有錯的火的,因為計算機執(zhí)行指令的時候本身就是線性的。然而如果把業(yè)務(wù)也看做是線性的淑倾,就會產(chǎn)生問題了馏鹤。

任何一個程序操作,他都會消耗一定的時間踊淳,即便你的CPU速度再快假瞬,也只是縮短了這個時間范圍而已陕靠,

如果只有一個用戶操作,比如在后臺發(fā)布文章脱茉,看自己發(fā)布的新聞剪芥,是無法感知并發(fā)帶來的沖突的。這就對程序員提出了更高的要求琴许。

理論上來講税肪,所有跨越時間段的操作過程中如果涉及到數(shù)據(jù)修改就會有可能產(chǎn)生并發(fā)沖突,因此在設(shè)計程序的時候榜田,要保障應(yīng)用程序的質(zhì)量益兄,就需要去做并發(fā)沖突處理,只是實現(xiàn)業(yè)務(wù)需求與實現(xiàn)業(yè)務(wù)的同時做好質(zhì)量需求箭券,就是好程序員與壞程序員的差別净捅。

那么分析了產(chǎn)生并發(fā)沖突的原因以后,就比較容易思考解決方案了辩块。大體的思路有兩種:一種是將并發(fā)操作變?yōu)閱尉€操作蛔六,另一種是讓所有跨越時間的段的操作不去更改數(shù)據(jù)。

再來看一下分頁废亭,或者上拉或者下拉刷新的解決方法国章。剛剛提出的2種的解決思路,哪一種比較合適呢豆村?對于發(fā)布數(shù)據(jù)和瀏覽數(shù)據(jù)液兽,比如微博,有可能把這種并發(fā)操作變?yōu)閱尉€操作嗎掌动?好像不太容易四啰。

那么能夠走得路就剩下第二條,也就是跨時間段的過程中不要改變數(shù)據(jù)坏匪,剛剛產(chǎn)生的bug到底是什么數(shù)據(jù)改變導(dǎo)致了bug拟逮。回顧下代碼實現(xiàn)的本質(zhì)适滓,就容易找到其中的緣由了敦迄。

通常在實現(xiàn)分頁的時候,首頁看到的是最新的數(shù)據(jù)凭迹,那么從數(shù)據(jù)庫中取數(shù)據(jù)的sel語句是select * from news order by desc limt 0罚屋,10,這樣取到最新的數(shù)據(jù)嗅绸,如果點擊下一頁脾猛,查詢語句不變,只是分頁條目不在是第0-9鱼鸠,而是第10-19條猛拴,如果在這個過程中有新的數(shù)據(jù)插入羹铅,會發(fā)現(xiàn)有一個東西變了,就是原有數(shù)據(jù)在數(shù)據(jù)庫的排序序號變了愉昆,如果我新發(fā)布一條數(shù)據(jù)职员,原來的第一條最新的新聞就會變成第二條,原來的第10條會變成第11條跛溉。這就是一個時間段內(nèi)的操作過程中有數(shù)據(jù)發(fā)生了改變焊切。

既然無法把這樣的并發(fā)操作變成單線操作,那么只可以選擇不讓數(shù)據(jù)發(fā)生改變芳室,這樣并發(fā)bug就可以得到很好的解決了专肪。

需要了解詳細解決方案的,會把無bug程序?qū)嵗窒斫o大家堪侯。

跨時間段的讓數(shù)據(jù)不改變不好走嚎尤,那么可以選擇第一種思路,讓并發(fā)操作變?yōu)閱尉€操作抖格,之前提到的加鎖是解決方案之一诺苹,但是對用戶體驗不好性能很差咕晋,基本上無法再互聯(lián)網(wǎng)項目中使用雹拄。如果不能加鎖,那么常用的解決方案是什么掌呜?

可以用隊列滓玖。如果將所有的用戶請求進行排隊,有一個服務(wù)來訂閱這個隊列质蕉,那么不管有多少用戶訪問势篡,最終到服務(wù)器端,處理服務(wù)的就只有一個進程模暗。這樣就實現(xiàn)了一個由并發(fā)操作轉(zhuǎn)換成單線操作禁悠。

總結(jié)

  • 并發(fā)發(fā)送的原因
    由于在一個業(yè)務(wù)進行過程中,業(yè)務(wù)所涉及的數(shù)據(jù)被他人改變兑宇,造成并發(fā)問題碍侦。

  • 解決思路

  1. 數(shù)據(jù)被他人改變->設(shè)置數(shù)據(jù)只可以自己改變(多線變單線[秒殺])
  2. 數(shù)據(jù)被更改->設(shè)置數(shù)據(jù)不可更改(selsect * from news roder by time desc limit 0, 10, 降序變升序--升序難度大點,但可以解決并發(fā)問題[微博])

未來編程模式->函數(shù)式編程并發(fā)模型

附加:高質(zhì)量代碼

負載隶糕、性能瓷产、數(shù)據(jù)安全、并發(fā)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末枚驻,一起剝皮案震驚了整個濱河市濒旦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌再登,老刑警劉巖尔邓,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晾剖,死亡現(xiàn)場離奇詭異,居然都是意外死亡梯嗽,警方通過查閱死者的電腦和手機钞瀑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來慷荔,“玉大人雕什,你說我怎么就攤上這事∠跃В” “怎么了贷岸?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長磷雇。 經(jīng)常有香客問我偿警,道長,這世上最難降的妖魔是什么唯笙? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任螟蒸,我火速辦了婚禮,結(jié)果婚禮上崩掘,老公的妹妹穿的比我還像新娘七嫌。我一直安慰自己,他們只是感情好苞慢,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布诵原。 她就那樣靜靜地躺著,像睡著了一般挽放。 火紅的嫁衣襯著肌膚如雪绍赛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天辑畦,我揣著相機與錄音吗蚌,去河邊找鬼。 笑死纯出,一個胖子當著我的面吹牛蚯妇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播潦刃,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼侮措,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了乖杠?” 一聲冷哼從身側(cè)響起分扎,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胧洒,沒想到半個月后畏吓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體墨状,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年菲饼,在試婚紗的時候發(fā)現(xiàn)自己被綠了肾砂。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡宏悦,死狀恐怖镐确,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饼煞,我是刑警寧澤源葫,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站砖瞧,受9級特大地震影響息堂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜块促,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一荣堰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧竭翠,春花似錦振坚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至褥实,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間裂允,已是汗流浹背损离。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绝编,地道東北人僻澎。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像十饥,于是被迫代替她去往敵國和親窟勃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容