首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 全域唯一 ID 生成方案深度對比:CAS、分散式鎖、Flicker 方案與資料庫擴展

     編輯:MySQL 綜合教學

分庫分表必面對的問題:Sharding Key 如何全域唯一?

業務增長到單表/單庫瓶頸時,Sharding 勢在必行。若 Sharding Key 需全域唯一(如訂單號、商品 ID),ID 生成策略直接決定系統擴展性與可用性。本文從 DBA 視角,剖析 4 類主流方案優劣。

方案一:CAS 樂觀鎖思想(資料庫序列表)

核心邏輯

建立序列表 SEQUENCE(name PK, gid),每次取 ID:

UPDATE sequence SET gid = @new_id WHERE name = 'users' AND gid < @new_id;
  • AND gid < @new_id 保證並發下只增不減
  • 影響行數=0 表示並發衝突,重試(設閾值如 100 次)

PHP 實現片段

function next_id_db($name) {
  for ($i=0; $i<100; $i++) {
    $last = $dao->get_seq_id($name);
    $id = $last + 1;
    if ($dao->set_seq_id($name, $id)) return $id;
  }
  return false;
}

優缺點

  • ✅ 簡單、無額外中間件依賴
  • ❌ 高並發下重試開銷大、資料庫成為瓶頸、單點故障

方案二:分散式鎖(Redis/Memcached)

核心邏輯

  • 利用 SETNX (Redis) / add (Memcached) 實現分散式鎖
  • 獲鎖成功 → INCR 生成 ID → 寫回 DB 序列表 → 釋放鎖
  • 鎖超時保護(如 1 秒)防死鎖

Redis 實現關鍵碼

$redis->setnx("sequence_{$name}_flag", time());  // 加鎖
$id = $redis->incr("sequence_{$name}");          // 生成 ID
if ($id === 1 || $id === false) {                // Redis 重啟丟失
  $last = $dao->get_seq_id($name);
  $redis->set("sequence_{$name}", $last);
  $id = $redis->incr("sequence_{$name}");
}
$dao->set_seq_id($name, $id);  // 持久化
$redis->delete("sequence_{$name}_flag");         // 釋放鎖

優缺點

  • ✅ 高效能、低延遲、支援集群
  • ❌ Redis 掛掉需降級、雙寫一致性需自行保障、運維複雜度升高

方案三:Redis + DB 雙模式降級

function next_id($name) {
  try { return $this->next_id_redis($name); }
  catch (Exception $e) { return $this->next_id_db($name); }
}

結合方案一二優點,Redis 正常時高效能,故障時自動降級 DB CAS,可用性大幅提升。

方案四:Flicker 方案(MySQL Auto_Increment + Replace Into + MyISAM)

單節點版

CREATE TABLE Tickets64 (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  stub CHAR(1) NOT NULL DEFAULT '',
  PRIMARY KEY (id), UNIQUE KEY stub (stub)
) ENGINE=MyISAM;

REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();  -- 獲取新 ID

每次 REPLACE 刪除舊行插入新行,stub 唯一鍵保證表永遠只有一行,ID 單調遞增。

高可用雙主版:奇偶數分離

-- Server 1
auto_increment_increment = 2
auto_increment_offset = 1   -- 產生 1,3,5,7...

-- Server 2
auto_increment_increment = 2
auto_increment_offset = 2   -- 產生 2,4,6,8...

客戶端輪詢兩台獲取 ID,單點故障自動切換。

優缺點

  • ✅ 借用資料庫原生機制、ID 有序、高可靠
  • ❌ 佔用 2 獨立 MySQL 實例、資源浪費、MyISAM 不支援事務

方案對比總結表

方案效能可用性複雜度ID 有序適用場景
DB CAS低低(單點)低是低並發、簡單業務
Redis 鎖高中(需哨兵/集群)高是高並發、有 Redis 運維能力
Redis+DB 降級高高高是核心業務、強一致要求
Flicker 雙主中高中是(奇偶)傳統架構、不想引入新中間件

現代替代方案提示

  • Snowflake 演算法:Twitter 開源,64bit (時間戳+機器ID+序列),無協調、高效能、趨勢有序
  • UUID v1/v7:全域唯一、無中心、但無序、佔空間大
  • 資料庫原生序列:PostgreSQL SEQUENCE、Oracle SEQUENCE、MySQL 8.0 AUTO_INCREMENT 持久化改進

選型建議:新架構首選 Snowflake 或類似演算法;存量 MySQL 架構可用 Flicker 或 Redis+DB 降級平滑過渡。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved