數學定義
自己給重複運算的結果==自己
f(f(x)) = f(x)
使用者對於同一操作發起多次請求,請求的結果是一致的,不會因為多次點選而產生副作用.
當然網路有異常的場景除外.
主要出現在資料庫的增加和修改場景中.
舉例: 用戶購買好商務後進入支付頁面, 服務收到請求了, 結果返回結果時網路發生異常, 此時錢其實已經扣了; 用戶再次點擊送出支付, 此時若是沒做好冪等性就會進行第二次扣款, 並返回成功結果. 但用戶查詢時, 才發現被多扣款了, 交易紀錄也出現2筆紀錄.
隔天就...準備提頭去請罪了.
服務之間的調用存在3種狀態: 成功、失敗、超時.
通常超時的時候, 對調用方來說是一種未知的狀態, 它不知道到底是成功還失敗,調用方都會發起Retry.
所以被調用方就要考慮冪等性.
如果調用方每次來調用接口時, 能帶上唯一的ID, 那下游服務紀錄這ID相對應數據的狀態.
如果已經存在的ID, 且狀態是成功, 這時候就能把重複的命令給攔截住, 並返回成功結果.
-- MySQL : auto_increment
CREATE DATABASE `Test`;
CREATE TABLE Test.TableA (
id bigint(20) unsigned NOT NULL auto_increment,
value char(10) NOT NULL default '',
PRIMARY KEY (id),
) ENGINE=InnoDB;
-- PostgrSQL : small, serial, bigserial
CREATE TABLE TableA
(
id serial NOT NULL,
alttext text,
imgurl text
)
借助Redis對命令操作都是單線程, INCR又是Atmoic命令, 所以能保證生成的ID唯一且有序
redis > SET unique_id 1
redis > INCR unique_id
2
redis> GET unique_id
2
因為上面兩種方式都有單點故障的風險, 所以通常會建立叢集, 確保基本可用
假設有三台資料庫, 如果三台自增起始點跟步長都一樣, 一定撞號XD
所以就是把三台起始點跟步長錯開.
三台資料庫, 三台的起始點分別就是1,2,3
步長=節點數量=3
set @@auto_increment_offset = 1; -- 設定起點
set @@auto_increment_increment = 3; -- 設定步長
UUID(Universally Unique Identifier), 通常是一組32長度字串.
8f04a79f-0944-4ded-9175-95ede0b66c4c
通過這12bytes, 來生成Unique ID
基本上光前三組的組成, 就能保證同一秒下, 不同機器不同process產生的ObjectID是唯一的了.
PS: 第一組的timestamp精度到秒
SnowFlake是Twitter提出, 為了快速生成全局唯一且總體有序的ID演算法.
生成過程不需要依賴網路或任何中間件, 性能每秒可生成400W+以上的ID.
原碼連結
跟Mongo ObjectID很相似的結構XD
雖然產生Unique ID可以讓操作冪等性.
但也是有可能發生請求帶著一個一定不存在的ID來訪問.
這時候往往會直接去資料庫做索引掃描.如果大量的請求都這樣做, 就可怕了.
哪怕你前面有Redis做快取, 但用的Key就是這ID, 快取查不到, 一樣去資料庫.
這種叫做緩存穿透.
Bloom Filter能協助判別這ID是不是一定不存在.
Redis可以協助實做Bloom Filter, 這有機會再補充介紹了.
ps. SnowFlake可以判斷最末段的timestamp + echo time 有沒有 > 現在時間, 做初步判斷.
給的若是未來時間, 或者是好久以前的, 通常就是無效的了