iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 9
1
Software Development

服務開發雜談系列 第 9

分散式系統中的冪等性 & Unique ID

  • 分享至 

  • xImage
  •  

冪等性

數學定義

自己給重複運算的結果==自己
f(f(x)) = f(x)

使用者對於同一操作發起多次請求,請求的結果是一致的,不會因為多次點選而產生副作用.
當然網路有異常的場景除外.
主要出現在資料庫的增加和修改場景中.

舉例: 用戶購買好商務後進入支付頁面, 服務收到請求了, 結果返回結果時網路發生異常, 此時錢其實已經扣了; 用戶再次點擊送出支付, 此時若是沒做好冪等性就會進行第二次扣款, 並返回成功結果. 但用戶查詢時, 才發現被多扣款了, 交易紀錄也出現2筆紀錄.
隔天就...準備提頭去請罪了.

服務之間的調用存在3種狀態: 成功失敗超時.
通常超時的時候, 對調用方來說是一種未知的狀態, 它不知道到底是成功還失敗,調用方都會發起Retry.
所以被調用方就要考慮冪等性.

如果調用方每次來調用接口時, 能帶上唯一的ID, 那下游服務紀錄這ID相對應數據的狀態.
如果已經存在的ID, 且狀態是成功, 這時候就能把重複的命令給攔截住, 並返回成功結果.

Unique ID

  1. 資料庫的自增主鍵
  2. Redis生成ID
  3. UUID
  4. MongoDB Object ID
  5. SnowFlake 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
)

pros

  1. 實現簡單
  2. 嚴格遞增

cons

  1. 不同資料庫實現不同, 當遷移資料庫時需要處理
  2. 只有在Master庫可以生成, 有單點故障的風險
  3. 分庫分表會有麻煩

Redis生成ID

借助Redis對命令操作都是單線程, INCR又是Atmoic命令, 所以能保證生成的ID唯一且有序

redis > SET unique_id 1
redis > INCR unique_id
2
redis> GET unique_id
2

pros

  1. 實現簡單
  2. 嚴格遞增

cons

  1. 有單點故障的風險

資料庫或Redis叢集的ID生成

因為上面兩種方式都有單點故障的風險, 所以通常會建立叢集, 確保基本可用
假設有三台資料庫, 如果三台自增起始點跟步長都一樣, 一定撞號XD
所以就是把三台起始點跟步長錯開.
三台資料庫, 三台的起始點分別就是1,2,3
步長=節點數量=3

set @@auto_increment_offset = 1;  -- 設定起點   
set @@auto_increment_increment = 3;  -- 設定步長

UUID

UUID(Universally Unique Identifier), 通常是一組32長度字串.

8f04a79f-0944-4ded-9175-95ede0b66c4c

pros

  1. 實現簡單
  2. 本地生成
  3. 適合用來生成token

cons

  1. 無序, 沒嚴格遞增(可能是優點?)
  2. 在MySQL下, 看字元集, 通常一個字需要3-4Bytes, 當成PK, 海量資料時, 對索引數的成本相對明顯; 儲存空間相對大
  3. 本身沒業務含意

MongoDB Object ID


通過這12bytes, 來生成Unique ID
基本上光前三組的組成, 就能保證同一秒下, 不同機器不同process產生的ObjectID是唯一的了.
PS: 第一組的timestamp精度到秒

pros

  1. 實現簡單

cons

  1. 本身沒業務含意

SnowFlake ID

SnowFlake是Twitter提出, 為了快速生成全局唯一且總體有序的ID演算法.
生成過程不需要依賴網路或任何中間件, 性能每秒可生成400W+以上的ID.
原碼連結


跟Mongo ObjectID很相似的結構XD

pros

  1. 因為毫秒數在高位, 自增序列號在低位, 所以ID總體趨勢遞增
  2. 可以以服務的方式獨立部屬, 達成叢集高可用
  3. 可以自己根據業務所需, 調整bit長度

cons

  1. 非常依賴系統時間, 要是系統時間往回退了, 就會產出重複的號碼

Bloom Filter

雖然產生Unique ID可以讓操作冪等性.
但也是有可能發生請求帶著一個一定不存在的ID來訪問.
這時候往往會直接去資料庫做索引掃描.如果大量的請求都這樣做, 就可怕了.
哪怕你前面有Redis做快取, 但用的Key就是這ID, 快取查不到, 一樣去資料庫.
這種叫做緩存穿透.

Bloom Filter能協助判別這ID是不是一定不存在.

Redis可以協助實做Bloom Filter, 這有機會再補充介紹了.

ps. SnowFlake可以判斷最末段的timestamp + echo time 有沒有 > 現在時間, 做初步判斷.
給的若是未來時間, 或者是好久以前的, 通常就是無效的了


上一篇
微服務瞎談(8) Saga, Choreography vs Orchestration
下一篇
CQRS亂談
系列文
服務開發雜談33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言