衍生到微服務領域,冪等指的是使用相同的參數屢次調用相同的API,對後端產生的影響是一致的,許多人理解爲屢次調用返回的結果是同樣,這種觀點是錯誤的,連最基本的查詢接口也不多是屢次查詢返回一樣的結果,冪等的側重點是對後端的影響,並不關心返回的數據。冪等是全部客戶端-服務端系統都須要考慮的問題,不管你是C-S仍是B-S模式,但在B-S模式下,這個問題更爲突出,尤爲是近幾年流行的微服務架構下,這是由於在微服務模式下,單個應用簡單,但服務總體更爲複雜,完成一個功能須要走較長的調用鏈,總體鏈路可能由不一樣的語言不一樣框架實現,每一個微服務爲了保證服務的質量,經常會對一些不肯定的因素(如:網絡異常、資源耗盡等)致使的問題進行容錯處理,典型措施就是重試。上圖是互聯網應用中很是精簡的調用流程,應該說許多公司的鏈路遠比這個複雜,流程中的每一個環節均可能出現重試:前端
若是請求只涉及到資源查詢,顯然調用屢次並不會對後端數據發生更改,因此查詢類的API自然就是冪等的,但若是這是一個創單接口,咱們就不得不考慮冪等的問題,創單過程當中會涉及到庫存扣減、餘額扣減、訂單數據入庫、消息通知等等修改後端資源的操做,爲了防止這類請求重複提交到後端,前端頁面一般會在用戶點擊提交後禁用按鈕,後端成功後清空表單跳轉到提示頁面,對於後端服務來說,一般會採用如下方式實現冪等:java
Token機制的核心就是要求客戶端的每次請求裏必須攜帶一個UUID,產生UUID的算法不少,如:雪花算法,ObjectID,經常使用的開發語言也有對應的實現,即便client生成UUID有困難,也能夠調用ID生成器預先生成一批緩存到本地,這裏就不一一展開。有了這個UUID,能夠在多個環節實現攔截,並且這種判斷是很是高效的,幾乎都是O(1)的時間複雜度,遠比數據庫惟一約束判斷快,譬如在nginx裏,咱們可使用lua獲取到請求裏的UUID,將該UUID放入leveldb、redis、memcache,下次請求時判斷該值是否存在,存在直接返回錯誤不然放行,若是不是使用nginx或者實施上述方案有困難,能夠在網關層實現,對於java語言(其餘語言也相似),能夠作到透明化處理:在網關裏註冊Idempotentfilter,該filter提取UUID,一樣經過leveldb、redis、memcache等高速緩存判斷是否能夠放行,顯然token方案能夠儘早發現和攔截訂單,大大下降資源消耗,減小數據庫壓力,對業務也是透明無浸入,但只依賴token機制顯然是有缺陷的:當緩存服務出錯ldb文件丟失,redis數據意外清空,memcache意外重啓等,會致使咱們的UUID標誌丟失,這時就須要數據庫來兜底,數據庫的惟一約束是不可或缺的,當出現這些極端狀況時,即便請求達到DB,也不會形成數據重複。有冪等需求的接口,建議採用token機制實現高效的排除重複請求,固然最終落地式須要結合具體的業務場景.nginx