### 冪等定義
定義:服務調用一次和重復調用多次產生的結果相同,即服務具有冪等性
### 冪等設計
1. 防止表單重復提交
2. 新增數據主鍵\(聯合唯一索引\)去重
3. 分布式鎖
4. 狀態機或狀態檢查
5. 版本號控制
6. bigLog增加流水日志;
7. 冪等框架\(美團GTIS\)
### 冪等性定義
冪等性是指對同一個系統使用同樣的條件,一次請求和重復的多次請求對系統資源的影響是一致的;
那么我們為什么需要接口具有冪等性呢?設想一下以下情形:
* 在App中下訂單的時候,點擊確認之后,沒反應,就又點擊了幾次。在這種情況下,如果無法保證該接口的冪等性,那么將會出現重復下單問題。
* 在接收消息的時候,消息推送重復。如果處理消息的接口無法保證冪等,那么重復消費消息產生的影響可能會非常大
分布式環境中,有些接口是天然保證冪等性的,如查詢操作。有些對數據的修改是一個常量,并且無其他記錄和操作,那也可以說是具有冪等性的。其他情況下,所有涉及對數據的修改、狀態的變更就都有必要防止重復性操作的發生。通過間接的實現接口的冪等性來防止重復操作所帶來的影響,成為了一種有效的解決方案。
### HTTP的冪等性
* **HTTP GET方法用于獲取資源,不應有副作用,所以是冪等的。**
比如:GET [http://www.bank.com/account/123456,不會改變資源的狀態,不論調用一次還是N次都沒有副作用。請注意,這里強調的是一次和N次具有相同的副作用,而不是每次GET的結果相同。GET](http://www.bank.com/account/123456,不會改變資源的狀態,不論調用一次還是N次都沒有副作用。請注意,這里強調的是一次和N次具有相同的副作用,而不是每次GET的結果相同。GET) [http://www.news.com/latest-news這個HTTP請求可能會每次得到不同的結果,但它本身并沒有產生任何副作用,因而是滿足冪等性的](http://www.news.com/latest-news這個HTTP請求可能會每次得到不同的結果,但它本身并沒有產生任何副作用,因而是滿足冪等性的)
* **HTTP DELETE方法用于刪除資源,有副作用,但它應該滿足冪等性。**
比如:DELETE [http://www.forum.com/article/4231,調用一次和N次對系統產生的副作用是相同的,即刪掉id為4231的帖子;因此,調用者可以多次調用或刷新頁面而不必擔心引起錯誤](http://www.forum.com/article/4231,調用一次和N次對系統產生的副作用是相同的,即刪掉id為4231的帖子;因此,調用者可以多次調用或刷新頁面而不必擔心引起錯誤)
* **HTTP POST方法用于創建資源,所對應的URI并非創建的資源本身,而是去執行創建動作的操作者,有副作用,不滿足冪等性。**
比如:POST [http://www.forum.com/articles的語義是在http://www.forum.com/articles下創建一篇帖子,HTTP響應中應包含帖子的創建狀態以及帖子的URI。兩次相同的POST請求會在服務器端創建兩份資源,它們具有不同的URI;所以,POST方法不具備冪等性](http://www.forum.com/articles的語義是在http://www.forum.com/articles下創建一篇帖子,HTTP響應中應包含帖子的創建狀態以及帖子的URI。兩次相同的POST請求會在服務器端創建兩份資源,它們具有不同的URI;所以,POST方法不具備冪等性)
* **HTTP PUT方法用于創建或更新操作,所對應的URI是要創建或更新的資源本身,有副作用,它應該滿足冪等性。**
比如:PUT [http://www.forum/articles/4231的語義是創建或更新ID為4231的帖子。對同一URI進行多次PUT的副作用和一次PUT是相同的;因此,PUT方法具有冪等性](http://www.forum/articles/4231的語義是創建或更新ID為4231的帖子。對同一URI進行多次PUT的副作用和一次PUT是相同的;因此,PUT方法具有冪等性)
### 冪等解決方案
#### 1. MVCC
多版本并發控制,樂觀鎖的一種實現,在數據更新時需要去比較持有數據的版本號,版本號不一致的操作無法成功。例如博客點贊次數自動+1的接口:
```
public
boolean
addCount
(Long id, Long version)
;
```
```
update blogTable
set
count= count+1,version=version+1
where
id=321 and version=123
```
每一個version只有一次執行成功的機會,一旦失敗必須重新獲取。
#### 2. 去重表:
利用數據庫表單的特性來實現冪等,常用的一個思路是在表上構建唯一性索引,保證某一類數據一旦執行完畢,后續同樣的請求再也無法成功寫入。
例子還是上述的博客點贊問題,要想防止一個人重復點贊,可以設計一張表,將博客id與用戶id綁定建立唯一索引,每當用戶點贊時就往表中寫入一條數據,這樣重復點贊的數據就無法寫入。
#### 3. TOKEN機制:
這種機制就比較重要了,適用范圍較廣,有多種不同的實現方式。其核心思想是為每一次操作生成一個唯一性的憑證,也就是token。一個token在操作的每一個階段只有一次執行權,一旦執行成功則保存執行結果。對重復的請求,返回同一個結果。
以電商平臺為例子,電商平臺上的訂單id就是最適合的token。當用戶下單時,會經歷多個環節,比如生成訂單,減庫存,減優惠券等等。
每一個環節執行時都先檢測一下該訂單id是否已經執行過這一步驟,對未執行的請求,執行操作并緩存結果,而對已經執行過的id,則直接返回之前的執行結果,不做任何操作。這樣可以在最大程度上避免操作的重復執行問題,緩存起來的執行結果也能用于事務的控制等。
* **多版本控制**
這種方法適合在更新的場景中,比如我們要更新商品的名字,這時我們就可以在更新的接口中增加一個版本號,來做冪等
```
boolean updateGoodsName(int id,String newName,int version);
```
在實現時可以如下
```
update goods set name=#{newName},version=#{version} where id=#{id} and version<${version}
```
_**參考資料**_
[https://tech.meituan.com/distributed-system-mutually-exclusive-idempotence-cerberus-gtis.html](https://tech.meituan.com/distributed-system-mutually-exclusive-idempotence-cerberus-gtis.html)
- 概述
- CAP理論
- BASE理論
- ACID
- 分布式系統相關技術
- 主流數據庫連接池
- 基礎
- 系統單點
- 負載均衡
- HTTP重定向負載均衡
- DNS域名解析負載均衡
- 反向代理負載均衡
- IP負載均衡
- 數據鏈路層負載均衡
- 負載均衡算法
- 輪詢法(Round Robin)
- 加權輪詢(Weight Round Robin)
- 隨機算法(Random)
- 源地址Hash算法
- 加權隨機法(Weight Random)
- 最小連接數法(Least Connections)
- 接入層負載均衡
- 軟件架構
- 性能
- 性能測試指標
- 響應時間
- 并發數
- 吞吐量
- 性能計數器
- 性能測試方法
- 性能測試報告
- 性能優化
- Web前端性能優化
- 應用服務器性能優化
- 可用性
- 服務降級
- 伸縮性
- 擴展性
- 事件驅動架構
- 安全性
- 信息加密技術
- 分布式系統概述
- 自動化
- 分布式唯一ID
- 冪等設計
- 分布式鎖
- 腦裂
- 一致性原理
- Paxos
- Zab
- Raft
- 分布式遠程服務調用
- RMI
- Spring RMI
- WebService
- SOA服務架構
- 微服務架構
- 微服務的九大特性
- 服務注冊和發現
- 解決方案及組件
- 分布式網關
- 注冊中心
- Zookeeper
- ZNode
- Watch接口
- 持久節點-配置中心實現原理
- 臨時節點-注冊中心
- Zookeeper選舉
- Zookeeper角色
- ZooKeeper工作原理
- 選主流程
- 同步流程
- Leader工作流程
- Follower工作流程
- 常見限流算法
- 計數器算法
- 漏桶算法
- 令牌桶算法
- 滑動窗口
- 計數器&滑動窗口
- 斷路器
- 大流量高并發高可用
- 高可用
- 高并發/大流量
- 分布式緩存系統
- 基本概念
- 緩存命中率
- 緩存最大元素
- 緩存回收策略
- 回收算法
- 緩存穿透與緩存雪崩
- CDN緩存
- 緩存分類
- memcached
- 客戶端路由原理
- 內存管理機制
- Redis
- Redis數據模型
- redisObject/Redis type/Redis encoding
- 命令的類型檢查和多態
- skiplist跳躍表
- 為什么使用跳躍表
- redis-內存管理機制
- Redis淘汰策略
- Redis持久化策略
- Redis并發競爭
- redis主從復制
- Redis集群實現方案
- Redis Cluster
- redis事務
- Redis-Sentinel
- Redis適用場景
- Redis客戶端
- redis rehash原理
- dict數據結構
- 觸發rehash的條件
- 漸進式rehash
- 漸進式rehash過程
- Redis多線程版本
- 緩存實際應用
- 堆緩存-Guava Cache
- 主要參數
- Caffeine
- Spring注解緩存
- 分布式存儲
- Database
- AUTOCOMMIT
- 臟讀&幻讀&不可重復讀
- 子查詢
- 連接
- 內連接
- 自連接
- 自然連接
- 外連接
- 組合查詢
- 隔離級別
- 數據庫范式
- 索引實現機制
- 數據庫拆分
- 表分區
- 分庫
- 分表
- MySQL
- MySQL基礎架構
- 鎖分類
- 排它鎖&獨占鎖
- 共享鎖
- 間隙鎖
- 表級鎖
- 存儲引擎
- 磁盤IO
- 磁盤結構圖
- 磁盤數據讀寫原理
- MySQL索引原理
- B+樹索引
- 局部性原理
- 索引數據結構
- 聯合索引
- 最左前綴匹配原則
- 建索引的幾大原則
- 數據文件和索引文件
- 執行計劃explain
- 常見問題
- 數據頁
- MYSQL單表存儲量計算
- 回表
- 索引覆蓋
- 索引下推
- 頁分裂和頁合并
- InnoDB
- innodb索引
- Innodb引擎的底層實現
- MyISAM
- MyISAM引擎的底層實現
- MVCC
- Next-Key Locks
- MySQL索引類型
- MYSQL復制
- 主從復制
- 讀寫分離
- MySQL Dual-Master
- 分庫分表實現方案
- MySQL事務實現原理
- MYSQL調優
- 性能優化
- HBase
- 不停機分庫分表遷移
- RDBMS&NoSQL
- 分布式事務
- 協議或事務模型
- X/Open XA協議
- 分布式事務編程接口規范JTA
- TCC模型
- 解決方案
- 兩階段提交2PC
- 三階段提交3PC
- Seata
- 分布式事務Seata產品模塊
- AT模式
- TCC模式
- Saga模式
- XA模式
- 基于消息中間件的最終一致性事務方案
- 消息隊列
- AMQP
- JMS
- ActiveMQ
- RabbitMQ
- RocketMQ
- RocketMQ基本概念
- 主要特性
- 分區順序消息
- 全局順序消息
- 消息可靠性
- 定時消息
- 消息重試
- 死信隊列
- 分布式事務消息
- RocketMQ架構
- Producer
- Consumer
- NameServer
- Broker
- RocketMQ設計
- 消息存儲
- 頁緩存與內存映射
- 消息刷盤
- 通信機制
- console控制臺
- RocketMQ部署架構
- Kafka
- Pulsar
- MQ消息重復消費與丟失
- 主流消息隊列比較
- 分布式調度系統
- 分布式搜索
- 分布式計算
- 架構案例
- 秒殺業務
- 秒殺整體架構
- 常見的監控系統
- 小米手機搶購秒殺方案
- 架構師領導藝術
- 架構師箴言
- 技術leader核心職責
- WEB服務器
- Servlet
- Servlet實現
- Servlet生命周期
- Servlet容器工作模式
- Servlet工作原理
- servlet線程安全
- CGI&FastCGI
- CGI
- FastCGI
- FastCGI與CGI特點
- CGI與Servlet比較
- HTTP Server
- Nginx
- Apache
- Nginx與Apache比較
- Application Server
- Tomcat
- Tomcat總體架構
- Connector
- 連接器核心功能
- ProtocolHandler
- EndPoint
- Processor
- Adapter
- Container
- 請求定位Servlet的過程
- Lifecycle生命周期
- Tomcat模塊設計
- Tomcat實例
- Tomcat運行原理
- spring & servlet
- Tomcat啟動流程
- Tomcat支持的I/O模型
- Tomcat應用層協議
- Tomcat類加載機制
- Tomcat類加載器
- Tomcat類加載器層次
- Apache+Tomcat
- 序列化
- XML&JSON
- JSON
- JAVA原生序列化
- hessian
- 常見中間件
- Canal
- Databus
- ELK日志套件
- 數據庫連接池
- spring狀態機
- 常見解決方案
- 二維碼掃碼登錄原理
- 前沿技術
- Saas服務
- 服務網格(Service Mesh)
- 云原生
- 常見面試問題
- Redis持久化的幾種方式
- Redis的緩存失效策略
- 附錄
- 二將軍問題
- 常見問題定位步驟
- 如何快速熟悉新系統
- 制定技術方案套路
- NUMA陷阱