摘要:解決冪等問題的三部曲,也是作者的思考框架。這是解決冪等問題的第二部曲列出并減少副作用的分析維度。所以在并發(fā)執(zhí)行的維度,將并發(fā)重復(fù)執(zhí)行變成串行重復(fù)執(zhí)行是最好的冪等解決方案。
綱要
文章目的:本文旨在提煉一套分布式冪等問題的思考框架,而非解決某個(gè)具體的分布式冪等問題。在這個(gè)框架體系內(nèi),會(huì)有一些方案舉例說明。
文章目標(biāo):希望讀者能通過這套思考框架設(shè)計(jì)出符合自己業(yè)務(wù)的完備的冪等解決方案。
文章內(nèi)容:
(1)背景介紹,為什么會(huì)有冪等。
(2)什么是冪等,這個(gè)定義非常重要,決定了整個(gè)思考框架。
(3)解決冪等問題的三部曲,也是作者的思考框架。
(4)總結(jié)
分布式系統(tǒng)由眾多微服務(wù)組成,微服務(wù)之間必然存在大量的網(wǎng)絡(luò)調(diào)用。下圖是一個(gè)服務(wù)間調(diào)用異常的例子,用戶提交訂單之后,請(qǐng)求到A服務(wù),A服務(wù)落單之后,開始調(diào)用B服務(wù),但是在A調(diào)用B的過程中,存在很多不確定性,例如B服務(wù)執(zhí)行超時(shí)了,RPC直接返回A請(qǐng)求超時(shí)了,然后A返回給用戶一些錯(cuò)誤提示,但實(shí)際情況是B有可能執(zhí)行是成功的,只是執(zhí)行時(shí)間過長而已。
用戶看到錯(cuò)誤提示之后,往往會(huì)選擇在界面上重復(fù)點(diǎn)擊,導(dǎo)致重復(fù)調(diào)用,如果B是個(gè)支付服務(wù)的話,用戶重復(fù)點(diǎn)擊可能導(dǎo)致同一個(gè)訂單被扣多次錢。不僅僅是用戶可能觸發(fā)重復(fù)調(diào)用,定時(shí)任務(wù)、消息投遞和機(jī)器重新啟動(dòng)都可能會(huì)出現(xiàn)重復(fù)執(zhí)行的情況。在分布式系統(tǒng)里,服務(wù)調(diào)用出現(xiàn)各種異常的情況是很常見的,這些異常情況往往會(huì)使得系統(tǒng)間的狀態(tài)不一致,所以需要容錯(cuò)補(bǔ)償設(shè)計(jì),最常見的方法就是調(diào)用方實(shí)現(xiàn)合理的重試策略,被調(diào)用方實(shí)現(xiàn)應(yīng)對(duì)重試的冪等策略。
二 什么是冪等對(duì)于冪等,有一個(gè)很常見的描述是:對(duì)于相同的請(qǐng)求應(yīng)該返回相同的結(jié)果,所以查詢類接口是天然的冪等性接口。舉個(gè)例子:如果有一個(gè)查詢接口是查詢訂單的狀態(tài),狀態(tài)是會(huì)隨著時(shí)間發(fā)生變化的,那么在兩次不同時(shí)間的查詢請(qǐng)求中,可能返回不一樣的訂單狀態(tài),這個(gè)查詢接口還是冪等接口嗎?
冪等的定義直接決定了我們?nèi)绾稳ピO(shè)計(jì)冪等方案,如果冪等的含義是相同請(qǐng)求返回相同結(jié)果,那實(shí)際上只需要緩存第一次的返回結(jié)果,即可在后續(xù)重復(fù)請(qǐng)求時(shí)實(shí)現(xiàn)冪等了。但問題真的有這么簡單嗎?
筆者更贊同這種定義:冪等指的是相同請(qǐng)求(identical request)執(zhí)行一次或者多次所帶來的副作用(side-effects)是一樣的。
引自:https://developer.mozilla.org...
An HTTP method is idempotent if an identical request can be made once or several times in a row with the same effect while leaving the server in the same state. In other words, an idempotent method should not have any side-effects (except for keeping statistics).
這個(gè)定義有一定的抽象,概括性比較強(qiáng),在設(shè)計(jì)冪等方案時(shí),其實(shí)就是將抽象部分具化。例如:什么是相同的請(qǐng)求?哪些情況會(huì)有副作用?該如何避免副作用?且看三部曲。
三 解決方案三部曲不少關(guān)于冪等的文章都稱自己的方案是通用解決方案,但筆者卻認(rèn)為,不同的業(yè)務(wù)場(chǎng)景下,相同請(qǐng)求和副作用都是有差異性的,不同的副作用需要不同的方案來解決,不存在完全通用的解決方案。而三部曲旨在提煉出一種思考模式,并舉例說明,在該思考模式下,更容易設(shè)計(jì)出符合業(yè)務(wù)場(chǎng)景的冪等解決方案。
第一部曲:識(shí)別相同請(qǐng)求冪等是為了解決重復(fù)執(zhí)行同一請(qǐng)求的問題,那如何識(shí)別一個(gè)請(qǐng)求有沒有和之前的請(qǐng)求重復(fù)呢?有的方案是通過請(qǐng)求中的某個(gè)流水號(hào)字段來識(shí)別的,同一個(gè)流水號(hào)表示同一個(gè)請(qǐng)求。也有的方案是通過請(qǐng)求中某幾個(gè)字段甚至全部字段進(jìn)行比較,從而來識(shí)別是否為同一個(gè)請(qǐng)求。所以在方案設(shè)計(jì)時(shí),明確定義具體業(yè)務(wù)場(chǎng)景下什么是相同請(qǐng)求,這是第一部曲。
方案舉例:token機(jī)制識(shí)別前端重復(fù)請(qǐng)求在一條調(diào)用鏈路的后端系統(tǒng)中,一般都可以通過上游系統(tǒng)傳遞的reqNo+source來識(shí)別是否是為重復(fù)的請(qǐng)求。如下圖,B系統(tǒng)是依賴于A系統(tǒng)傳遞的reqNo+source來識(shí)別相同請(qǐng)求的,但是A系統(tǒng)是直接和前端頁面交互的系統(tǒng),如何識(shí)別用戶發(fā)起的請(qǐng)求是相同的呢?比如用戶在支付界面上點(diǎn)擊了多次,A系統(tǒng)怎么識(shí)別這是一次重復(fù)操作呢?
前端可以在第一次點(diǎn)擊完成時(shí),將按鈕設(shè)置為disable,這樣用戶無法在界面上重復(fù)點(diǎn)擊第二次,但這只是提升體驗(yàn)的前端解決方案,不是真正安全的解決方案。
常見的服務(wù)端解決方案是采用token機(jī)制來實(shí)現(xiàn)防重復(fù)提交。如下圖,
(1)當(dāng)用戶進(jìn)入到表單頁面的時(shí)候,前端會(huì)從服務(wù)端申請(qǐng)到一個(gè)token,并保存在前端。
(2)當(dāng)用戶第一次點(diǎn)擊提交的時(shí)候,會(huì)將該token和表單數(shù)據(jù)一并提交到服務(wù)端,服務(wù)端判斷該token是否存在,如果存在則執(zhí)行業(yè)務(wù)邏輯。
(3)當(dāng)用戶第二次點(diǎn)擊提交的時(shí)候,會(huì)將該token和表單數(shù)據(jù)一并提交到服務(wù)端,服務(wù)端判斷該token是否存在,如果不存在則返回錯(cuò)誤,前端顯示提交失敗。
這個(gè)方案結(jié)合前后端,從前端視角,這是用于防止重復(fù)請(qǐng)求,從服務(wù)端視角,這個(gè)用于識(shí)別前端相同請(qǐng)求。服務(wù)端往往基于類似于redis之類的分布式緩存來實(shí)現(xiàn),保證生成token的唯一性和操作token時(shí)的原子性即可。核心邏輯如下。
// SETNX keyName value: 如果key存在,則返回0,如果不存在,則返回1 // step1. 申請(qǐng)token String token = generateUniqueToken(); // step2. 校驗(yàn)token是否存在 if(redis.setNx(token, 1) == 1){ // do business } else { // 冪等邏輯 }第二部曲:列出并減少副作用的分析維度
相同的請(qǐng)求重復(fù)執(zhí)行業(yè)務(wù)邏輯,如果處理不當(dāng),會(huì)給系統(tǒng)帶來副作用。那什么是副作用?從技術(shù)的角度理解就是返回結(jié)果后還導(dǎo)致某些“系統(tǒng)狀態(tài)”發(fā)生變化,無副作用的函數(shù)稱之為純函數(shù),體現(xiàn)到業(yè)務(wù)的角度就是業(yè)務(wù)無法接受的非預(yù)期結(jié)果。最常見的有重復(fù)入庫、數(shù)據(jù)被錯(cuò)誤變更等,大多數(shù)冪等方案就是圍繞解決這類問題來設(shè)計(jì)的。而系統(tǒng)往往可能在多個(gè)維度都存在副作用,例如:
(1)調(diào)用下游維度:重復(fù)調(diào)用下游會(huì)怎樣?如果下游沒有冪等,重復(fù)調(diào)用會(huì)帶來什么副作用?
(2)返回上游維度:例如第一次返回上游異常,第二次返回上游被冪等了?會(huì)給上游帶來什么副作用?
(3)并發(fā)執(zhí)行維度:并發(fā)重復(fù)執(zhí)行會(huì)怎樣?會(huì)有什么副作用?
(4)分布式鎖維度:引入分布式鎖來防止并發(fā)執(zhí)行?但是如果鎖出現(xiàn)不一致性,會(huì)有什么副作用?
(5)交互時(shí)序維度:有沒有異步交互,是否存在時(shí)序問題?會(huì)有什么副作用?
(6)客戶體驗(yàn)維度:從數(shù)據(jù)不一致到最終一致,必須在多少時(shí)間內(nèi)完成?如果該時(shí)間內(nèi)沒有完成,會(huì)有什么副作用?例如大量客訴(秉承客戶第一的原則,在支付寶,客訴量太大會(huì)定級(jí)為生產(chǎn)環(huán)境故障)。
(7)業(yè)務(wù)核對(duì)維度:重復(fù)調(diào)用是否存在覆蓋核對(duì)標(biāo)識(shí)的情況,帶來無法正常核對(duì)的副作用?在金融系統(tǒng)中,資金鏈路無法核對(duì)是無法接受的。
(8)數(shù)據(jù)質(zhì)量維度:是否存在重復(fù)記錄?如果存在會(huì)有什么副作用?
上面是一些常見的分析維度,不同行業(yè)的系統(tǒng)中會(huì)存在不一樣的維度,盡可能地總結(jié)出這些維度,并列入系統(tǒng)分析時(shí)的checklist中,能夠更好地完善冪等解決方案。沒有副作用才算是完備的冪等解決方案,但是副作用的維度太多,會(huì)提高冪等方案的復(fù)雜度。所以在能夠達(dá)成業(yè)務(wù)的前提下,減少一些分析維度,能夠使得冪等方案實(shí)現(xiàn)起來更加經(jīng)濟(jì)有效。例如:如果有專門的冪等表存儲(chǔ)返回給上游的冪等結(jié)果,第(2)維度不用考慮了,如果用鎖來防止并發(fā),第(3)個(gè)維度不考慮了,如果用單機(jī)鎖代替分布式鎖,第(4)個(gè)維度不考慮了。
這是解決冪等問題的第二部曲:列出并減少副作用的分析維度。在這部曲中,涉及的解決方案往往是解決某一個(gè)維度的副作用問題,適合以通用組件的形式存在,作為團(tuán)隊(duì)內(nèi)部的一個(gè)公共技術(shù)套路。
方案舉例:加鎖避免并發(fā)重復(fù)執(zhí)行很多冪等解決方案都和防并發(fā)有關(guān),那么冪等和并發(fā)到底有什么關(guān)聯(lián)呢?兩者的聯(lián)系是:冪等解決的是重復(fù)執(zhí)行的問題,重復(fù)執(zhí)行既有串行重復(fù)執(zhí)行(例如定時(shí)任務(wù)),也有并發(fā)重復(fù)執(zhí)行。如果重復(fù)執(zhí)行的業(yè)務(wù)邏輯沒有共享變量和數(shù)據(jù)變更操作時(shí),并發(fā)重復(fù)執(zhí)行是沒有副作用的,可以不考慮并發(fā)的問題。對(duì)于包含共享變量、涉及變更操作的服務(wù)(實(shí)際上這類服務(wù)居多),并發(fā)問題可能導(dǎo)致亂序讀寫共享變量,重復(fù)插入數(shù)據(jù)等問題。特別是并發(fā)讀寫共享變量,往往都是發(fā)生生產(chǎn)故障后才被感知到。
所以在并發(fā)執(zhí)行的維度,將并發(fā)重復(fù)執(zhí)行變成串行重復(fù)執(zhí)行是最好的冪等解決方案。支付寶最常見的方法就是:一鎖二判三更新,如下圖。當(dāng)一個(gè)請(qǐng)求過來之后:一鎖,鎖住要操作的資源;二判,識(shí)別是否為重復(fù)請(qǐng)求(第一部曲要定義的問題)、判斷業(yè)務(wù)狀態(tài)是否正常;三更新:執(zhí)行業(yè)務(wù)邏輯。
Q&A
小A:鎖可能造成性能影響,先判后鎖再執(zhí)行,可以提升效能。
大明:這樣可能會(huì)失去防并發(fā)的效果。還記得double check實(shí)現(xiàn)單例模式嗎?在加鎖前判斷了下,那加鎖后為啥還要判斷下?實(shí)際上第二次check才是必須的。想想看?
小A畫圖思考中...
小A:明白了,一鎖二判三更新,鎖和判的順序是不能變的,如果鎖沖突比較高,可以在鎖之前判斷下,提高效率,所以稱之為double check。
大明:是的,聰明。這兩個(gè)場(chǎng)景不一樣,但并發(fā)思路是一樣的。
private volatile static Girl theOnlyGirl; // 實(shí)現(xiàn)單例時(shí)做了 double check public static Girl getTheOnlyGirl() { if (theOnlyGirl == null) { // 加鎖前check synchronized (Girl.class) { if (theOnlyGirl == null) { // 加鎖后check theOnlyGirl = new Girl(); // 變更執(zhí)行 } } } return theOnlyGirl; }
鎖的實(shí)現(xiàn)可以是分布式鎖,也是可以是數(shù)據(jù)庫鎖。分布式鎖本身會(huì)帶來鎖的一致性問題,需要根據(jù)業(yè)務(wù)對(duì)系統(tǒng)穩(wěn)定性的要求來考量。支付寶的很多系統(tǒng)是通過在業(yè)務(wù)數(shù)據(jù)庫中新建一個(gè)鎖記錄表來實(shí)現(xiàn)業(yè)務(wù)鎖組件,其分表邏輯和業(yè)務(wù)表的分表邏輯一致,就可以實(shí)現(xiàn)單機(jī)數(shù)據(jù)庫鎖。如果沒有鎖組件,悲觀鎖鎖住業(yè)務(wù)單據(jù)也是可以滿足條件的,悲觀鎖要在事務(wù)中用select for update來實(shí)現(xiàn),要注意死鎖問題,且where條件中必須命中索引,否則會(huì)鎖表,不鎖記錄。
并發(fā)維度幾乎是一個(gè)分布式冪等的通用分析維度,所以一個(gè)通用的鎖組件是很有必要的。但這也只是解決了并發(fā)這一個(gè)維度的副作用。雖然沒有了并發(fā)重復(fù)執(zhí)行的情況,但串行重復(fù)執(zhí)行的情況依舊存在,重復(fù)執(zhí)行才是冪等核心要解決的問題,重復(fù)執(zhí)行如果還存在其它副作用,冪等問題就是沒有解決掉。
加鎖后業(yè)務(wù)的性能會(huì)降低,這個(gè)怎么解決?筆者認(rèn)為,大多數(shù)情況下架構(gòu)的穩(wěn)定性比系統(tǒng)性能的優(yōu)先級(jí)更高,況且對(duì)于性能的優(yōu)化有太多地方可以去實(shí)現(xiàn),減少壞代碼、去除慢SQL、優(yōu)化業(yè)務(wù)架構(gòu)、水平擴(kuò)展數(shù)據(jù)庫資源等方式。通過系統(tǒng)壓測(cè)來實(shí)現(xiàn)一個(gè)滿足SLA的服務(wù)才是評(píng)估全鏈路性能的正確方法。
第三部:識(shí)別細(xì)粒度副作用,針對(duì)性設(shè)計(jì)解決方案在解決了部分維度的副作用之后,就需要針對(duì)剩余維度存在的細(xì)粒度副作用進(jìn)行逐一識(shí)別并解決了。在數(shù)據(jù)質(zhì)量維度上,最大的一個(gè)副作用是重復(fù)數(shù)據(jù)。在交互維度上,最大的一個(gè)副作用是業(yè)務(wù)亂序執(zhí)行。一般這類問題不設(shè)計(jì)成通用組件,可以開發(fā)人員自由發(fā)揮。本節(jié)用兩個(gè)常見方案做為例子。
方案舉例1:唯一性約束避免重復(fù)落庫在數(shù)據(jù)表設(shè)計(jì)時(shí),設(shè)計(jì)兩個(gè)字段:source、reqNo,source表示調(diào)用方,seqNo表示調(diào)用方發(fā)送過來的請(qǐng)求號(hào)。source和reqNo設(shè)置為組合唯一索引,保證單據(jù)不會(huì)重復(fù)落兩次。如果調(diào)用方?jīng)]有source和reqNo這兩個(gè)字段,可以根據(jù)業(yè)務(wù)實(shí)際情況將請(qǐng)求中的某幾個(gè)業(yè)務(wù)參數(shù)生成一個(gè)md5作為唯一性字段落到唯一性字段中來避免重復(fù)落庫。
核心邏輯如下:
try { dao.insert(entity); // do business } catch (DuplicateKeyException e) { dao.select(param); // 冪等返回 }
這里直接insert單據(jù),若果成功則表示沒請(qǐng)求過,舉行執(zhí)行業(yè)務(wù)邏輯,如果拋出DuplicateKeyException異常,則表示已經(jīng)執(zhí)行過,做冪等返回,簡單的服務(wù)通過這種方式也可以識(shí)別是否為重復(fù)請(qǐng)求(第一部曲)。
利用數(shù)據(jù)庫唯一索引來避免重復(fù)記錄,需要注意以下幾個(gè)問題:
(1)因?yàn)榇嬖谧x寫分離的設(shè)計(jì),有可能insert操作的是主庫,但select查詢的卻是從庫,如果主備同步不及時(shí),有可能select查出來也是空的。
(2)在數(shù)據(jù)庫有Failover機(jī)制的情況下,如果一個(gè)城市出現(xiàn)自然災(zāi)害,很可能切換到另外一個(gè)城市的備用庫,那么唯一性約束可能就會(huì)出現(xiàn)失效的情況,比如并發(fā)場(chǎng)景下第一次insert是在杭州的庫,然后此時(shí)failover將庫切到上海了,再一次同樣的請(qǐng)求insert也是成功的。
(3)數(shù)據(jù)庫擴(kuò)容場(chǎng)景下,因?yàn)榉謳煲?guī)則發(fā)生變化,有可能第一次insert操作是在A庫,第二次insert操作是在B庫,唯一索引同樣不起作用。
(4)有的系統(tǒng)catch的是SQLIntegrityConstraintViolationException,這個(gè)是完整性約束,包含了唯一性約束,如果未給一個(gè)必填字段設(shè)值,也會(huì)拋這個(gè)異常,所以應(yīng)該catch鍵重復(fù)異常DuplicateKeyException。
對(duì)于第(1)個(gè)問題,將insert 和select放在同一個(gè)事務(wù)中即可解決,對(duì)于(2)和(3),支付寶內(nèi)部為了應(yīng)對(duì)容量暴漲和FO,設(shè)計(jì)了一套基于數(shù)據(jù)復(fù)制技術(shù)的分布式數(shù)據(jù)平臺(tái),這個(gè)case筆者了解不深,后續(xù)有機(jī)會(huì)再討論。
小A:如果我用唯一性約束來保證不會(huì)落重復(fù)數(shù)據(jù),是不是可以不加鎖防并發(fā)了?方案舉例2:狀態(tài)機(jī)約束解決亂序問題
大明:兩者沒有直接關(guān)系,加鎖防并發(fā)解決的是并發(fā)維度的副作用問題,唯一性約束只是解決重復(fù)數(shù)據(jù)這單個(gè)副作用的問題。如果沒有唯一性約束,串行重復(fù)執(zhí)行也會(huì)導(dǎo)致insert重復(fù)落數(shù)據(jù)的問題,唯一性約束本質(zhì)上解決的是重復(fù)數(shù)據(jù)問題,不是并發(fā)問題。
一個(gè)業(yè)務(wù)的生命周期往往存在不同的狀態(tài),用狀態(tài)機(jī)來控制業(yè)務(wù)流程中的狀態(tài)轉(zhuǎn)換是不二之選。在實(shí)際業(yè)務(wù)中單向的狀態(tài)機(jī)是比較常用的,當(dāng)狀態(tài)機(jī)處于下一個(gè)狀態(tài)時(shí),是不能回到前面的狀態(tài)的。以下場(chǎng)景經(jīng)常會(huì)用到狀態(tài)機(jī)做校驗(yàn):
(1)調(diào)用方調(diào)用超時(shí)重試。
(2)消息投遞超時(shí)重試。
(3)業(yè)務(wù)系統(tǒng)發(fā)起多個(gè)任務(wù),但是期待按照發(fā)起順序有序返回。
對(duì)于這種類問題,一般是在處理前先判斷狀態(tài)是否符合預(yù)期,如果符合預(yù)期再執(zhí)行業(yè)務(wù)。當(dāng)業(yè)務(wù)執(zhí)行完成后,變更狀態(tài)時(shí)還會(huì)采取類似于于樂觀鎖的方式兜底校驗(yàn),例如,M狀態(tài)只能從N狀態(tài)轉(zhuǎn)換而來,那么更新單據(jù)時(shí),會(huì)在sql中做狀態(tài)校驗(yàn)。
update apply set status = "M" where status = "N"
如果狀態(tài)被設(shè)計(jì)成可逆的,就有可能產(chǎn)生ABA問題。即在update之前,狀態(tài)有可能做過這樣的變更:N -> M -> N。所以狀態(tài)機(jī)設(shè)成單向流轉(zhuǎn)是比較合理的。
四 總結(jié)本文首先引出了冪等的定義:相同請(qǐng)求無副作用,然后提出了設(shè)計(jì)冪等方案的三部曲,并舉例說明。設(shè)計(jì)者要能夠清晰地定義相同請(qǐng)求,并且采用通用組件減少一些副作用的分析維度,再針對(duì)具體的副作用設(shè)計(jì)相應(yīng)的解決方案,直至沒有任何副作用,才是真正完備的冪等解決方案。在實(shí)際業(yè)務(wù)中,實(shí)現(xiàn)三部曲不一定是嚴(yán)格的先后順序,但只要按照這三部曲來構(gòu)思方案,必能開拓思路,化繁為簡。
公眾號(hào)簡介:作者是螞蟻金服的一線開發(fā),分享自己的成長和思考之路。內(nèi)容涉及數(shù)據(jù)、工程、算法。
注:轉(zhuǎn)載請(qǐng)注明出處。本文提到的分布式鎖、業(yè)務(wù)鎖,悲觀鎖和樂觀鎖的選型,以及基于鎖的冪等組件的實(shí)現(xiàn),將另起文章介紹,若感興趣可以關(guān)注公眾號(hào),歡迎交流。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/76035.html
摘要:分布式系統(tǒng)錯(cuò)綜復(fù)雜,今天,我們著重對(duì)分布式系統(tǒng)的互斥性與冪等性進(jìn)行分析與解決。阻塞鎖與自旋鎖。公平鎖與非公平鎖。實(shí)現(xiàn)今天重點(diǎn)講解使用實(shí)現(xiàn)分布式鎖。個(gè)人感覺是最適合實(shí)現(xiàn)分布式鎖。如以上流程,接口無法冪等,可能導(dǎo)致重復(fù)扣款。 背景 隨著數(shù)據(jù)量的增大,用戶的增多,系統(tǒng)的并發(fā)訪問越來越大,傳統(tǒng)的單機(jī)已經(jīng)滿足不了需求,分布式系統(tǒng)成為一種必然的趨勢(shì)。分布式系統(tǒng)錯(cuò)綜復(fù)雜,今天,我們著重對(duì)分布式系統(tǒng)的...
摘要:問題是,重復(fù)請(qǐng)求導(dǎo)致的數(shù)據(jù)重復(fù)插入。這問題造成的后果很明顯數(shù)據(jù)冗余,可能不單單多一條有些業(yè)務(wù)需求不能有多余數(shù)據(jù),造成服務(wù)問題問題如圖所示解決方式如何將同請(qǐng)求,不執(zhí)行插入,而是讀取前一個(gè)請(qǐng)求插入的數(shù)據(jù)并返回。那么使用分布式鎖的解決方案。 摘要: 原創(chuàng)出處 https://www.bysocket.com 「公眾號(hào):泥瓦匠BYSocket 」歡迎關(guān)注和轉(zhuǎn)載,保留摘要,謝謝!目錄 為啥要解...
摘要:然而在微服務(wù)化之前,建議先進(jìn)行容器化,在容器化之前,建議先無狀態(tài)化,當(dāng)整個(gè)流程容器化了,以后的微服務(wù)拆分才會(huì)水到渠成。 此文已由作者劉超授權(quán)網(wǎng)易云社區(qū)發(fā)布。 歡迎訪問網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營經(jīng)驗(yàn)。 一、為什么要做無狀態(tài)化和容器化 很多應(yīng)用拆分成微服務(wù),是為了承載高并發(fā),往往一個(gè)進(jìn)程扛不住這么大的量,因而需要拆分成多組進(jìn)程,每組進(jìn)程承載特定的工作,根據(jù)并發(fā)的壓力用多個(gè)副本公共...
摘要:總結(jié)的時(shí)間復(fù)雜度是,是空間是使用輔助棧來存儲(chǔ)最小值。項(xiàng)目就是為了解決配置繁瑣的問題,最大化的實(shí)現(xiàn)約定大于配置。 前言 只有光頭才能變強(qiáng) Redis目前還在看,今天來分享一下我在秋招看過(遇到)的一些面試題(相對(duì)比較常見的) 0、final關(guān)鍵字 簡要說一下final關(guān)鍵字,final可以用來修飾什么? 這題我是在真實(shí)的面試中遇到的,當(dāng)時(shí)答得不太好,現(xiàn)在來整理一下吧。 final可以修飾...
閱讀 2124·2021-10-12 10:12
閱讀 832·2021-09-24 09:47
閱讀 1247·2021-08-19 11:12
閱讀 3539·2019-08-29 13:06
閱讀 748·2019-08-26 11:43
閱讀 2642·2019-08-23 17:20
閱讀 1201·2019-08-23 16:52
閱讀 2664·2019-08-23 14:27