分佈式服務接口的冪等性如何設計(比如不能重複扣款)?

本博客轉自git項目advancejava

面試官心理分析

一個分佈式系統中的某個接口,該如何保證冪等性?這個事兒其實是你做分佈式系統的時候必須要考慮的一個生產環境的技術問題。啥意思呢?

你看,假如你有個服務提供一個接口,結果這服務部署在了 5 臺機器上,接着有個接口就是付款接口。然後人家用戶在前端上操作的時候,不知道爲啥,總之就是一個訂單不小心發起了兩次支付請求,然後這倆請求分散在了這個服務部署的不同的機器上,好了,結果一個訂單扣款扣兩次。

或者是訂單系統調用支付系統進行支付,結果不小心因爲網絡超時了,然後訂單系統走了前面我們看到的那個重試機制,咔嚓給你重試了一把,好,支付系統收到一個支付請求兩次,而且因爲負載均衡算法落在了不同的機器上,尷尬了。。。

所以你肯定得知道這事兒,否則你做出來的分佈式系統恐怕容易埋坑。

面試題剖析

這個不是技術問題,這個沒有通用的一個方法,這個應該結合業務來保證冪等性。
所謂冪等性,就是說一個接口,多次發起同一個請求,你這個接口得保證結果是準確的,比如不能多扣款、不能多插入一條數據、不能將統計值多加了 1。這就是冪等性。
其實保證冪等性主要是三點:
• 對於每個請求必須有一個唯一的標識,舉個栗子:訂單支付請求,肯定得包含訂單 id,一個訂單 id 最多支付一次,對吧。
• 每次處理完請求之後,必須有一個記錄標識這個請求處理過了。常見的方案是在 mysql 中記錄個狀態啥的,比如支付之前記錄一條這個訂單的支付流水。
• 每次接收請求需要進行判斷,判斷之前是否處理過。比如說,如果有一個訂單已經支付了,就已經有了一條支付流水,那麼如果重複發送這個請求,則此時先插入支付流水,orderId 已經存在了,唯一鍵約束生效,報錯插入不進去的。然後你就不用再扣款了。

實際運作過程中,你要結合自己的業務來,比如說利用 redis,用 orderId 作爲唯一鍵。只有成功插入這個支付流水,纔可以執行實際的支付扣款。
要求是支付一個訂單,必須插入一條支付流水,order_id 建一個唯一鍵 unique key。你在支付一個訂單之前,先插入一條支付流水,order_id 就已經進去了。你就可以寫一個標識到 redis 裏面去,set order_id payed,下一次重複請求過來了,先查 redis 的 order_id 對應的 value,如果是 payed 就說明已經支付過了,你就別重複支付了。

發佈了107 篇原創文章 · 獲贊 15 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章