日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

【案例分析】分布式系统的接口幂等性设计!

發布時間:2024/2/28 windows 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【案例分析】分布式系统的接口幂等性设计! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概念

冪等性, Idempotence, 這個詞來源自數學領域, 百科 上一元運算的冪等性解釋如下:設 f 為一由 {x} 映射至 {x} 的一元運算, 則 f 為冪等的, 當對于所有在 {x} 內的 x: ?f(f(x)) = f(x) 。特別的是,恒等函數一定是冪等的,且任一常數函數也都是冪等的。

冪等性衍生到軟件工程中, 它的語義是指: 函數/接口可以使用相同的參數重復執行, 不應該影響系統狀態, 也不會對系統造成改變 .

一個簡答的例子:?查詢接口 GetFoo(), 不管調用多少次, 都不會破壞當前的系統/內存, 這就是一個冪等操作. 當然, 系統內部產生的日志這些細節不要在意.

在 HTTP/1.1 規范中, 冪等性有類似的明確定義: ?Methods can also have the property of “idempotence” in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.

從語義上不難看出, HTTP GET 是一個清晰的冪等操作, HTTP DELETE/POST 是非冪等的, HTTP PUT 也是冪等的, 因為對同一個 URI 進行多次 PUT 的 side-effetcs 是一致的.

在分布式系統中, 由于分布式天然特性的時序問題, 以及網絡的不可靠性(機器、機架、機房故障, 電纜被挖斷等等), 重復請求很常見, 接口冪等性設計就顯得尤為重要 .

案例分析

舉一個游戲領域中的案例:

玩家 Jack 花費點券購買道具, 調用后端 shop_svr 集群的 rpc 接口 buy_commodity(commodity_id) .?

由于網絡延遲, 或者系統負載比較高, shop_svr 沒來得及返回, 總之, 第一次調用超時了沒返回.?

Jack 見一直木有反映, 又點了一次購買按鈕.?

網絡恢復了, shop_svr 連續收到兩次 buy_commodity(commodity_id) 請求.?

好吧, Jack 本來只想花 100 點券買個小喇叭, 系統硬是讓他買了倆, 難怪都說 XX 游戲坑錢了……?

上面錯誤的示例只是扯個蛋, 咳咳…… 從這個問題中可以折射出幾點系統設計的問題:

buy_commodity() 接口不符合冪等性 , 當重復操作時, 對整個系統產生了影響, 玩家 A 被多扣了點券, 在網游業務中, 一旦涉及到錢這種敏感數據, 往往就不妙了.

shop_svr 的消息處理做的不夠完善, 當它收到延遲了許久的消息時, 應該及早拒絕, 返回失敗, 不僅是為了避免重復調用, 更重要的是保證 shop_svr 不會過載而導致整個系統雪崩 (不過這又是另外個話題, 不在此贅述).

那么,怎么完善 buy_commodity() 接口的冪等性呢?

借鑒銀行等金融系統的做法, 引入 票據 (token) 是個不錯的主意:

Jack 花費點券購買道具, 先到 shop_svr 中去申請交易票據 token.?

shop_svr 生成唯一 token, 并記錄到 DB.?

Jack 拿到 token, 調用接口 buy_commodity(token, commodity_id) 購買.?

由于網絡延遲, 或者系統負載比較高, shop_svr 沒來得及返回, 總之, 第一次調用超時了沒返回.?

Jack 重試購買, 仍然調用接口 buy_commodity(token, commodity_id) .?

shop_svr 收到第一次 buy_commodity() 請求, 驗證 token 之后完成購買行為,再將 token 標記為已執行, 這是個 原子行為 .?

shop_svr 收到第二次 buy_commodity() 請求, 驗證 token 失敗, 丟棄消息.?

票據 (token) 機制, 保證了 buy_commodity() 接口的冪等性 , 同樣的請求, 并不會對系統造成額外的 side-effects, 即多次調用預期保持一致, 問題解決!

PS: 按照上面的描述, DB 層保證 “驗證 token”, “加道具扣點券”, “標記 token” 這三步操作的原子性, 這并不是一個很容易的事情

所以實際中往往妥協為: 先 “驗證并標記 token” , 再 “加道具扣點券” 這兩步操作:

第一步操作可以通過 SQL 的條件更新, 或者帶版本號寫(部分 NoSQL 支持)來實現, 這是冪等性操作.?

如果第一步成功, 第二步失敗, 可以直接認為操作失敗, 但并不會破壞接口的冪等性.?

大部分的網游服務器, 是極其注重數據強一致性的, 但能容忍一定的可用性缺失.?

例如: 玩家能接受每周的例行停服維護時間, 能接受某次點擊服務器返回失敗, 但是很難接受數據被篡改乃至回檔, 這也是上面 DB 操作可以妥協的根本原因.

擴展

But, 問題真的完美解決了么?

再擴展一下上面的例子, 現在游戲火了, 為了響應迅速增大的并發請求, 游戲服務都做了擴展, 無狀態的 shop_svr 也平行擴展為一個集群

玩家的每次 buy_commodity() 請求都被負載均衡器路由到不同的 shop_svr 處理, 以 平攤系統負載 , 一切都看上去很好.

Jack 吃了一個禮拜泡面終于攢了 20000 點券, 準備買個”趙云-子龍”的皮膚, Jack 滿心期待的點下了”購買”按鈕, 額, 居然又沒反應… 點了幾下都如此

納悶兒的 Jack 順手點了下隔壁的”閉月之顏-貂蟬”皮膚, 彈窗提示:”購買成功”, 這…… Jack 哭了.

我們來回顧一下, 應該是如此的流程: 托分布式系統的福, 第二個請求 buy_commodity(token_2, “閉月之顏-貂蟬”) 后發而先至, 被優先處理

當第一個請求 buy_commodity(pay_token_1, “趙云-子龍”) 在之后到達時, Jack 的點券已經被扣完了,扣完了……

這個問題跟冪等性本身無關, 從系統的行為來看, 也是符合強一致性 的, 只是在時序上沒能符合 Jack 的預期, 帶來了體驗上的心理落差.

解決之道:?

  • 配置 shop_svr 集群前端的 負載均衡器 , 通過一定的 路由算法 保證 Jack 的請求消息路由到固定某個 shop_svr_j 上處理.

  • 同時, 請求消息的傳遞通過 消息隊列 (TCP 也是個樸素的實現) 來 保證順序 , 這樣, Jack 先發的請求 request 1 一定在后發的請求 request 2 之前到達, 并被處理, 從而避免時序的影響.

  • 總結

    以上是生活随笔為你收集整理的【案例分析】分布式系统的接口幂等性设计!的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。