溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

并發(fā)到底帶來(lái)了什么問(wèn)題?

發(fā)布時(shí)間:2020-07-18 21:52:07 來(lái)源:網(wǎng)絡(luò) 閱讀:452 作者:Java_老男孩 欄目:編程語(yǔ)言

說(shuō)在前面

我曾不止一次聽(tīng)說(shuō)過(guò)這句話(huà):

“十個(gè)女人無(wú)法在一個(gè)月內(nèi)生出孩子”

我明白這句話(huà)的意思,用來(lái)形容我們的開(kāi)發(fā)工作需要循序漸進(jìn),沒(méi)有辦法簡(jiǎn)單的增加人員就能加快研發(fā)速度。

這句話(huà)也經(jīng)常被用于反駁產(chǎn)品經(jīng)理或者老板,試圖讓他們明白我們內(nèi)心所表達(dá)的觀點(diǎn),老實(shí)說(shuō)我也說(shuō)過(guò)這樣的話(huà),當(dāng)時(shí)還覺(jué)得挺有道理,現(xiàn)在想來(lái)可能有些一廂情愿了。

沒(méi)錯(cuò),在現(xiàn)實(shí)世界中,當(dāng)然不可能在一個(gè)月內(nèi)生出孩子,但我們畢竟是做產(chǎn)品寫(xiě)代碼的,而不是真的要去生孩子,所以這種說(shuō)法未免有點(diǎn)偷換概念。

我并不是較真,如果只是想讓產(chǎn)品經(jīng)理明白我們所要表達(dá)的觀點(diǎn),我們完全可以用其他的比喻,如實(shí)反饋存在的困難與問(wèn)題即可。

言歸正傳,這句話(huà)與本文有什么關(guān)系呢?本文想要就“并發(fā)”所帶來(lái)的問(wèn)題進(jìn)行探討,相信看完后你會(huì)對(duì)此有一個(gè)感覺(jué)。

與我之前寫(xiě)的幾篇文章一樣,并發(fā)一詞在本文中所表達(dá)的意思是:

“在分布式環(huán)境下,超過(guò)一個(gè)線(xiàn)程同時(shí)對(duì)同一個(gè)狀態(tài)進(jìn)行訪(fǎng)問(wèn)和變更所導(dǎo)致的一致性問(wèn)題和可用性問(wèn)題”

問(wèn)題的根源:狀態(tài)

我無(wú)法給出一個(gè)百分比數(shù)據(jù)用以說(shuō)明到底有多少后端應(yīng)用程序在使用數(shù)據(jù)庫(kù),但我想國(guó)內(nèi)涉及到增刪查改之類(lèi)的各種“管理系統(tǒng)”應(yīng)該不在少數(shù)。

說(shuō)到底,增刪改查是落地,而怎么落地則取決于業(yè)務(wù)的需要,也就是說(shuō),業(yè)務(wù)規(guī)則以及流程表達(dá)了我們的邏輯,但終究離不開(kāi)柴米油鹽(增刪改查)。

那么什么是狀態(tài)?

它可以是文件,也可以是數(shù)據(jù)庫(kù),可以是一個(gè)變量,也可以是緩存,它代表了計(jì)算的結(jié)果或者依賴(lài)(中間結(jié)果),由于它是可變的,并且可以被超過(guò)1個(gè)以上的程序同時(shí)訪(fǎng)問(wèn)或者修改。

所以由此產(chǎn)生了兩個(gè)問(wèn)題:

  • 一致性:確保業(yè)務(wù)代碼的邏輯符合設(shè)計(jì)期望。即:我們?nèi)绾伪WC在并發(fā)的時(shí)候確保狀態(tài)始終處于我們預(yù)期?
  • 可用性:確保系統(tǒng)可以滿(mǎn)足伸縮需求,但同時(shí),也必須要滿(mǎn)足一致性。即:在保持一致性的同時(shí),如何提高系統(tǒng)的負(fù)載能力?

一致性要求是必須的,無(wú)法滿(mǎn)足一致性的情況要么是業(yè)務(wù)邏輯本身有問(wèn)題,要么就是我們?cè)诰幋a過(guò)程中出現(xiàn)了BUG,而如果是我們的編碼出現(xiàn)問(wèn)題,很明顯就不符合驗(yàn)收標(biāo)準(zhǔn)。

可用性要求則取決于運(yùn)營(yíng)的實(shí)際情況,隨著系統(tǒng)使用規(guī)模的上升,我們需要保證系統(tǒng)始終處于用的狀態(tài)下,因?yàn)闃I(yè)務(wù)方不希望服務(wù)被中斷或者超時(shí)。

我來(lái)描述一下完整的邏輯:

  1. 由于我們需要確保系統(tǒng)的設(shè)計(jì)與編碼符合業(yè)務(wù)的流程與規(guī)則,所以我們需要保證一致性。
  2. 由于我們需要為更多的用戶(hù)提供服務(wù),所以我們需要提高系統(tǒng)的可用性。
  3. 由于單臺(tái)服務(wù)器所提供的硬件能力已經(jīng)達(dá)到極限,所以我們不得不使用多臺(tái)服務(wù)器,形成集群同時(shí)服務(wù)業(yè)務(wù)請(qǐng)求。
  4. 由于集群后多個(gè)服務(wù)器可能會(huì)訪(fǎng)問(wèn)和修改同一個(gè)狀態(tài)(狀態(tài)一致性問(wèn)題的產(chǎn)生原因),所以我們必須使用協(xié)調(diào)多個(gè)服務(wù)修改狀態(tài)的機(jī)制(鎖、事務(wù),問(wèn)題的解決方案)。

接下來(lái),我會(huì)分別就狀態(tài)的一致性和可用性進(jìn)行討論。

問(wèn)題:一致性

在上一節(jié)中,我們說(shuō)狀態(tài)一致證明我們最終落地的數(shù)據(jù)是正確的,符合業(yè)務(wù)邏輯的。不一致是由于我們對(duì)業(yè)務(wù)的理解或者編碼出現(xiàn)了BUG,而B(niǎo)UG是我們必須要解決的。

這里有兩個(gè)層面的問(wèn)題,我們分別來(lái)看一下。

業(yè)務(wù)層面

如果在業(yè)務(wù)邏輯的層面上本身就存在悖論,存在漏洞,經(jīng)驗(yàn)豐富的開(kāi)發(fā)人員會(huì)在進(jìn)行系統(tǒng)設(shè)計(jì)或者編碼的時(shí)候就能察覺(jué)出來(lái),道理很簡(jiǎn)單,因?yàn)闊o(wú)法被實(shí)現(xiàn),不管怎么樣都會(huì)存在BUG,而這種BUG是我們技術(shù)人員無(wú)法解決的,我們不能夠去猜業(yè)務(wù)方到底想要什么,因?yàn)檫@極有可能不符合他們的期望,最后仍然有可能會(huì)導(dǎo)致返工,造成成本的上升。

就像我們拿本文開(kāi)頭的那個(gè)例子去懟產(chǎn)品經(jīng)理一樣,很多時(shí)候是由于我們不善表達(dá),沒(méi)有清楚表達(dá)出我們的疑惑,從而造成尷尬的場(chǎng)面。

溝通和管理是困難的,眾口難調(diào)。如何跟業(yè)務(wù)人員進(jìn)行高效的溝通一直以來(lái)都是一個(gè)難題,但我們必須要清楚一點(diǎn)的是:

“只有我們充分洞悉和理解所要實(shí)現(xiàn)的業(yè)務(wù)領(lǐng)域,才能夠使我們更加輕松和增強(qiáng)信心,**因?yàn)橹挥羞@樣,我們才能夠選擇最適合的技術(shù)和模型幫助我們靈活的完成任務(wù)?!?*

我的意思并不是讓咱們都成為該領(lǐng)域的專(zhuān)家,因?yàn)樾g(shù)業(yè)有專(zhuān)攻,分工配合才是重中之重,如果我們沒(méi)有跟業(yè)務(wù)需求方達(dá)成緊密的一致,就有可能造成浪費(fèi)。

有關(guān)這一塊的內(nèi)容,建議大家看一本書(shū),叫做《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》,英文名是《Domain Driven Design》,簡(jiǎn)稱(chēng)DDD。

技術(shù)層面

技術(shù)層面出現(xiàn)不一致的問(wèn)題一般有兩種情況:

  • 我們沒(méi)有理解業(yè)務(wù)的原始需求。
  • 我們完全理解業(yè)務(wù)的需求,但是由于編碼造成了BUG,出現(xiàn)了意外的不一致。

如果是第一種,這個(gè)沒(méi)什么好說(shuō)的,返回業(yè)務(wù)層面與業(yè)務(wù)專(zhuān)家進(jìn)行真誠(chéng)層面的溝通,獲取真正的需求。

如果是第二種,那么我們首先應(yīng)該找出不一致的原因,分析不一致的原因有助于我們加深理解和避免此類(lèi)問(wèn)題。

如果是由于小失誤造成的問(wèn)題我們直接修復(fù)即可,這其實(shí)很常見(jiàn),我們寫(xiě)的代碼或多或少都要經(jīng)過(guò)測(cè)試與修復(fù)。

如果是由于并發(fā)競(jìng)爭(zhēng)造成的問(wèn)題,那我們就需要用到相關(guān)的解決方案了,最常見(jiàn)的是使用數(shù)據(jù)庫(kù)事務(wù)來(lái)保證狀態(tài)落地的時(shí)候不會(huì)產(chǎn)生不一致,因?yàn)椴灰恢聲?huì)導(dǎo)致事務(wù)的回滾。

還有就是使用鎖來(lái)限制資源的訪(fǎng)問(wèn)以及修改,這些都是很常見(jiàn)的技術(shù),鑒于本文的重點(diǎn)是想說(shuō)明產(chǎn)生這些問(wèn)題的原因,所以不會(huì)這些解決方案進(jìn)行詳細(xì)的講述,有興趣的朋友可以翻看一下我之前的文章或者查閱相關(guān)資料文檔。

問(wèn)題:可用性

可用性往往決定了系統(tǒng)架構(gòu)的實(shí)現(xiàn)方式,可用性導(dǎo)致了我們最終將不得不使用分布式集群來(lái)應(yīng)對(duì)大規(guī)模的訪(fǎng)問(wèn)需求。

可以說(shuō),產(chǎn)生并發(fā)問(wèn)題的直接原因就是可用性,因?yàn)樗屛覀儗?duì)狀態(tài)的管理變得十分復(fù)雜。

如果沒(méi)有可用性要求,最簡(jiǎn)單的我們甚至可能都不需要數(shù)據(jù)庫(kù),但現(xiàn)實(shí)中,對(duì)于一款成功的產(chǎn)品,我們不可能告訴我們的老板咱們無(wú)法實(shí)現(xiàn)對(duì)不對(duì)?

“量變導(dǎo)致質(zhì)變,當(dāng)可用性要求越來(lái)越高,系統(tǒng)規(guī)模越來(lái)越大,即便是再簡(jiǎn)單的增刪改查都將不會(huì)再簡(jiǎn)單”

如何在提升可用性的同時(shí)還能保證狀態(tài)的一致性?這真的不是技術(shù)能夠解決的。

先冷靜一下,我的意思是,由于網(wǎng)絡(luò)分區(qū)的存在,狀態(tài)的強(qiáng)一致會(huì)導(dǎo)致可用性降低,而可用性的提高又會(huì)造成分區(qū)狀態(tài)的不一致,從而降低了一致性。

這就是著名CAP定理[1],我們要么取CP,降低系統(tǒng)的可用性,要么取AP,降低狀態(tài)的一致性。

那么我們有沒(méi)有什么辦法來(lái)達(dá)到一個(gè)比較好的平衡呢?

答案是當(dāng)然可以,但是,就如我一開(kāi)始所說(shuō)的,這并不是技術(shù)一個(gè)人就能夠解決的問(wèn)題。

事實(shí)已經(jīng)很明顯了,我們不可能取CP來(lái)降低系統(tǒng)的可用性,那樣就沒(méi)得玩了,所以我們只能夠選擇AP。

“在業(yè)務(wù)可以允許范圍內(nèi),設(shè)計(jì)一種最終一致的中間流程步驟,來(lái)提高系統(tǒng)的可用性,同時(shí),又得以讓業(yè)務(wù)可以正常不受影響,處于預(yù)期的運(yùn)轉(zhuǎn)。”

因此基于BASE理論[2][3]的最終一致更貼近于現(xiàn)實(shí)與業(yè)務(wù),CAP定理只是證明和告訴我們,哪些事情行不通,但是BASE理論告訴我們,上有政策下有對(duì)策,使用柔性事務(wù),反脆弱的系統(tǒng)才能讓我們更加的靈活。

所以我們要怎么做呢?我們要告訴產(chǎn)品經(jīng)理,系統(tǒng)的可用性瓶頸必須要更改業(yè)務(wù)的流程才能得以實(shí)現(xiàn)。

我們要學(xué)會(huì)表達(dá),告訴產(chǎn)品經(jīng)理,這不是能不能做的問(wèn)題,或者我能不能行的問(wèn)題。

而是計(jì)算機(jī)科學(xué)目前的發(fā)展水平就是如此,也會(huì)存在極限,我們必須要學(xué)會(huì)相互適應(yīng),才能保證健康的發(fā)展。

那么事務(wù)怎么辦?我該使用分布式事務(wù)嗎?

盡量避免使用分布式事務(wù),這是由衷的建議,事實(shí)證明分布式事務(wù)不僅不會(huì)提高性能,反而會(huì)拖垮高可用場(chǎng)景的系統(tǒng)。

如果你遇到了這個(gè)問(wèn)題,那么說(shuō)明狀態(tài)分區(qū)隔離以及事務(wù)場(chǎng)景有可能存在不合理的地方。

如果你確實(shí)有這種需求,那么盡量避免使用分布式事務(wù),或者將分布式改為本地事務(wù),也就是說(shuō)不要將它們放到不同的地方進(jìn)行事務(wù)處理。

如果這樣也不行的話(huà),那就必須讓事務(wù)這個(gè)概念被明確包含進(jìn)業(yè)務(wù)范圍,作為一個(gè)獨(dú)立的實(shí)體存在,不要讓它隱藏在技術(shù)細(xì)節(jié)中。

這樣的話(huà),我們就能夠?qū)@個(gè)定義明確的事務(wù)“句柄”或者“鉤子”進(jìn)行補(bǔ)償或者回滾等最終一致冪等操作。

這也是我一直強(qiáng)調(diào)表達(dá)的,不要僅僅從技術(shù)層面來(lái)看待分布式事務(wù),它可能是一個(gè)潛在的業(yè)務(wù)需求,存在生命周期的潛在概念。

就像我們對(duì)接支付寶一樣,根據(jù)訂單號(hào)來(lái)確保冪等,返回明確的信息給支付寶表明處理成功或失敗,實(shí)現(xiàn)最終一致的交易處理。

并行就一定快于串行?

這個(gè)問(wèn)題要從兩個(gè)方面來(lái)看,如果并行運(yùn)行的程序沒(méi)有相互依賴(lài),沒(méi)有狀態(tài)、資源競(jìng)爭(zhēng),那么水平拓展是非常容易的。

比如MapReduce,將大規(guī)模的數(shù)據(jù)分發(fā)并行處理,最后并歸計(jì)算結(jié)果,速度肯定快于串行執(zhí)行。

相反,如果狀態(tài)特征在進(jìn)行并歸的時(shí)候,前后依賴(lài)就產(chǎn)生了耦合,并行處理導(dǎo)致的切換加載開(kāi)銷(xiāo)就變得沒(méi)有意義。

什么意思呢?

比如將一個(gè)個(gè)事件進(jìn)行存儲(chǔ),因?yàn)闋顟B(tài)本質(zhì)上來(lái)講就是就是一系列事件施加計(jì)算后的快照而已(詳見(jiàn)https://www.cnblogs.com/xingxueliao/p/11561263.html#event_and_state)

所以如果我們想要計(jì)算某一個(gè)時(shí)間點(diǎn)上的快照,就需要從頭將事件播放到指定的位置上,事件對(duì)狀態(tài)的影響是嚴(yán)格按照先后順序來(lái)的。

因?yàn)槭录?dǎo)致的狀態(tài)結(jié)果是前后依賴(lài)的關(guān)系,因此并行運(yùn)算并不會(huì)得到什么幫助,反而會(huì)因?yàn)榍袚Q導(dǎo)致無(wú)必要的狀態(tài)加載以及卸載開(kāi)銷(xiāo)。

這種情況下,串行處理是唯一的方式,我們應(yīng)該在這個(gè)上下文中,對(duì)輸入的事件流進(jìn)行持久批量的計(jì)算,而且不用考慮并發(fā)所帶來(lái)的一致性問(wèn)題。

因此,盲目的使用多線(xiàn)程或者多實(shí)例集群不僅不會(huì)讓可用性得以提升,反倒因?yàn)楦?jìng)爭(zhēng)的關(guān)系導(dǎo)致可用性被降低。

對(duì)數(shù)據(jù)特征進(jìn)行分析,如何隔離狀態(tài)才是我們需要關(guān)注的重點(diǎn),因?yàn)橹挥袑](méi)有依賴(lài)關(guān)系的狀態(tài)隔離后我們才有可能提高整個(gè)系統(tǒng)的可用性。

最后

這就完了?好像你沒(méi)有提到任何關(guān)于如何解決這些問(wèn)題“具體方案”。

沒(méi)有具體的方案,因?yàn)檫@超出了本文的范疇,本文只是簡(jiǎn)單的講述問(wèn)題產(chǎn)生的原因,試圖以比較清晰的一個(gè)視角來(lái)發(fā)現(xiàn)和看待問(wèn)題是為什么存在的。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI