冪等一二三
阿新 • • 發佈:2018-10-31
最近開發提現相關的功能,需要考慮冪等性。向社群取了點經,把自己的實現方法寫下來。不會高談闊論什麼是冪等,冪等種類等高深的問題。只是簡單的寫下步驟,題目來源於此。
為什麼需要冪等
分散式環境裡面,網路不可控,計算機不可控,都有失敗風險。先給定兩個角色,server,client,client是請求發起者,server是請求接收者並處理業務邏輯。第一次請求任何地方失敗了就直接告訴客戶處理失敗,這沒有問題,但是可用性不好,體驗差。有什麼辦法提高?答案是有限次的重試,比如重試三次,第一次失敗,還有第二次或者第三次機會。
問題來了,server接受到的請求可能是0個,1個,2個,或者3個。server收到3個重複的提現請求,當然只能最多真的提現一次。冪等解決的就是這個問題,最多處理一次,At Most Once
冪等解決思路
提供請求的身份證號碼,或者叫請求的ID,不同的請求不同的ID,重複的請求共享相同的ID。做的第一件事情是要區別請求相同還是不同。區分開了請求的異同,接下來就是實施,實施的思路很簡單,根據請求ID檢視請求是否處理成功,成功就跳出處理流程,告知已處理,不成功就繼續處理。
具體步驟
提供ID生成服務。client可以呼叫該服務,獲取新的ID。
這一步可以跳過,client自己生成符合規範的唯一ID可行。String getTransactionId()
client端呼叫攜帶請求ID。
String transactionId = transactionService.getTransactionId(); while(int i< 3){ Response response = invokeServer(transactionId, request); if(response.isSuccess()){ break; } i++; }
server端實現
提現涉及金錢,比較敏感,資料庫事務必不可少。所以server端的邏輯依賴資料庫事務。
3.1 建ID池,用table表示
CREATE TABLE `transaction` (
`transaction_id` VARCHAR(64) NOT NULL COMMENT '事務ID',
PRIMARY KEY (`transaction_id`)
)
3.2 事務保證
@Transactional
public class BusinessServiceImpl inplements BusinessService{
@Override
public void doSomething(String transactionId, Request request){
// 向transaction表計入transactionId
transactionDao.insert(new Transaction(transactionId));
// 處理具體的業務邏輯
doBussiness(request);
}
}
- transaction表的插入與業務處理,放到同一個事務,要麼都成功,要麼都失敗。
- 相同的transactionId,由於transaction用transactionId作為主鍵,所以transaction最多有一個插入成功。
所以業務處理也最多隻有一次成功,搞定。
其它
誰發起請求,誰負責transactionId。
能夠接受成功處理0次,但是不接受處理大於1次。