業務增長驅動分庫分表,Sharding Key 必須全局唯一。本文從 DBA 視角,深度剖析四大主流全局 ID 生成方案:CAS 模式、分布式鎖、Redis+DB 混合模式、Flicker 方案,對比優劣與適用場景。
sequence 表讀取當前最大 ID(gid)+1 得到新 IDUPDATE sequence SET gid = 新ID WHERE name = 'xxx' AND gid < 新IDCREATE TABLE `SEQUENCE` ( `name` VARCHAR(30) NOT NULL COMMENT '分表表名', `gid` BIGINT(20) NOT NULL COMMENT '最大全局ID', PRIMARY KEY (`name`) ) ENGINE=InnoDB;
public long nextIdDb(String name) {
SequenceDao dao = SequenceDao.getInstance();
int threshold = 100;
for (int i = 0; i < threshold; i++) {
long lastId = dao.getSeqId(name);
long id = lastId + 1;
if (dao.setSeqId(name, id)) return id;
}
throw new RuntimeException("ID生成失敗");
}
SETNX (Redis) 或 add (Memcached) 嘗試獲取鎖INCR 生成 ID → 寫回 DB → 釋放鎖public long nextIdRedis(String name) {
// 嘗試獲取鎖
while (true) {
if (redis.setnx("sequence_" + name + "_flag", timestamp)) break;
if (超時或重試上限) break;
}
// 生成 ID
long id = redis.incr("sequence_" + name);
if (id == 1 || id == false) { // 首次或失效,從 DB 回載
long lastId = dao.getSeqId(name);
redis.set("sequence_" + name, lastId);
id = redis.incr("sequence_" + name);
}
dao.setSeqId(name, id); // 持久化到 DB
redis.del("sequence_" + name + "_flag"); // 釋放鎖
return id;
}
public long nextId(String name) {
try {
return nextIdRedis(name);
} catch (Exception e) {
log.warn("Redis不可用,降級DB模式", e);
return nextIdDb(name);
}
}
結合兩者優點:平時走 Redis 高性能,故障自動降級 DB 保可用。
auto_increment_increment=2,offset=1/2 產生奇/偶 ID| 維度 | CAS/DB | 分布式鎖 | Redis+DB混合 | Flicker雙主 |
|---|---|---|---|---|
| 性能 | 中 | 高 | 高 | 高 |
| 可用性 | 依賴DB架構 | 依賴Redis集群 | 高(自動降級) | 極高(雙主) |
| 實現複雜度 | 低 | 中 | 中高 | 中 |
| ID有序性 | 有序 | 有序 | 有序 | 有序(間隔) |
| 運維成本 | 低 | 中 | 中高 | 高 |
| 推薦場景 | 中小併發、簡單架構 | 高併發、有Redis | 核心業務、追求高可用 | 頂級核心、資源充足 |