面試題
分布式服務(wù)接口的冪等性如何設(shè)計(比如不能重復(fù)扣款)痒芝?
面試官心理分析
從這個問題開始坝撑,面試官就已經(jīng)進(jìn)入了實(shí)際的生產(chǎn)問題的面試了静秆。
一個分布式系統(tǒng)中的某個接口,該如何保證冪等性巡李?這個事兒其實(shí)是你做分布式系統(tǒng)的時候必須要考慮的一個生產(chǎn)環(huán)境的技術(shù)問題抚笔。啥意思呢?
你看侨拦,假如你有個服務(wù)提供一個接口殊橙,結(jié)果這服務(wù)部署在了 5 臺機(jī)器上,接著有個接口就是付款接口狱从。然后人家用戶在前端上操作的時候膨蛮,不知道為啥,總之就是一個訂單不小心發(fā)起了兩次支付請求矫夯,然后這倆請求分散在了這個服務(wù)部署的不同的機(jī)器上鸽疾,好了,結(jié)果一個訂單扣款扣兩次训貌。
或者是訂單系統(tǒng)調(diào)用支付系統(tǒng)進(jìn)行支付制肮,結(jié)果不小心因?yàn)?strong>網(wǎng)絡(luò)超時了,然后訂單系統(tǒng)走了前面我們看到的那個重試機(jī)制递沪,咔嚓給你重試了一把豺鼻,好,支付系統(tǒng)收到一個支付請求兩次款慨,而且因?yàn)樨?fù)載均衡算法落在了不同的機(jī)器上儒飒,尷尬了。檩奠。桩了。
所以你肯定得知道這事兒,否則你做出來的分布式系統(tǒng)恐怕容易埋坑埠戳。
面試題剖析
這個不是技術(shù)問題井誉,這個沒有通用的一個方法,這個應(yīng)該結(jié)合業(yè)務(wù)來保證冪等性整胃。
所謂冪等性颗圣,就是說一個接口,多次發(fā)起同一個請求,你這個接口得保證結(jié)果是準(zhǔn)確的在岂,比如不能多扣款奔则、不能多插入一條數(shù)據(jù)、不能將統(tǒng)計值多加了 1蔽午。這就是冪等性易茬。
其實(shí)保證冪等性主要是三點(diǎn):
- 對于每個請求必須有一個唯一的標(biāo)識,舉個栗子:訂單支付請求祠丝,肯定得包含訂單 id疾呻,一個訂單 id 最多支付一次,對吧写半。
- 每次處理完請求之后,必須有一個記錄標(biāo)識這個請求處理過了尉咕。常見的方案是在 mysql 中記錄個狀態(tài)啥的叠蝇,比如支付之前記錄一條這個訂單的支付流水。
- 每次接收請求需要進(jìn)行判斷年缎,判斷之前是否處理過悔捶。比如說,如果有一個訂單已經(jīng)支付了单芜,就已經(jīng)有了一條支付流水蜕该,那么如果重復(fù)發(fā)送這個請求,則此時先插入支付流水洲鸠,orderId 已經(jīng)存在了堂淡,唯一鍵約束生效,報錯插入不進(jìn)去的扒腕。然后你就不用再扣款了绢淀。
實(shí)際運(yùn)作過程中,你要結(jié)合自己的業(yè)務(wù)來瘾腰,比如說利用 redis皆的,用 orderId 作為唯一鍵。只有成功插入這個支付流水蹋盆,才可以執(zhí)行實(shí)際的支付扣款费薄。
要求是支付一個訂單,必須插入一條支付流水栖雾,order_id 建一個唯一鍵 unique key
楞抡。你在支付一個訂單之前,先插入一條支付流水岩灭,order_id 就已經(jīng)進(jìn)去了拌倍。你就可以寫一個標(biāo)識到 redis 里面去,set order_id payed
,下一次重復(fù)請求過來了柱恤,先查 redis 的 order_id 對應(yīng)的 value数初,如果是 payed
就說明已經(jīng)支付過了,你就別重復(fù)支付了梗顺。