互聯網快速發展的今天,分佈式應用系統已經見怪不怪,在分佈式系統中,我們需要各種各樣的ID,既然是ID那麼必然是要保證全局唯一,除此之外,不同的業務還需要不同的特性,比如像併發巨大的業務要求ID生成效率高,吞吐大;比如某些銀行類業務,需要按每日日期制定交易流水號;又比如我們希望用戶的ID是隨機的,無序的,純數字的,且位數長度是小於10位的。等等,不同的業務場景需要的ID特性各不一樣,於是,衍生了各種ID生成器。本文講的訂單號就是其中一種業務id,下面結合訂單業務需求,介紹訂單號的生成策略。
特徵:全局唯一,不重複;安全性;性能;id生成效率高。訂單號生策略。
支付中心多臺部署,能夠保證訂單id唯一麼?
業務需求:
1)訂單號不能重複
2)訂單號沒有規則,即編碼規則不能加入任何和公司運營相關的數據,外部人員無法通過訂單ID猜測到訂單量。不能被遍歷。
3)訂單號長度固定,且不能太長
4)易讀,易溝通,不要出現數字字母換亂現象
5)生成耗時(生成效率高低)
關於訂單號的生成,一些比較簡單的方案:
1、數據庫自增長ID
優勢:無需編碼
缺陷:
1)大表不能做水平分表,否則插入刪除時容易出現問題(單表處理,不能分表)。
2)高併發下插入數據需要加入事務機制
3)在業務操作父、子表(關聯表)插入時,先要插入父表,再插入子表;
2、時間戳+隨機數
優勢:編碼簡單
缺陷:隨機數存在重複問題,即使在相同的時間戳下。每次插入數據庫前需要校驗下是否已經存在相同的數值。(每次校驗是否存在該訂單號,不存在才能插入,同一張表)
3、時間戳+會員ID
優勢:同一時間,一個用戶不會存在兩張訂單
缺陷:會員ID也會透露運營數據,雞生蛋,蛋生雞的問題
例如:S+yyMMddHHmmss+Math.abs(memberId.hashCode());[說明memberId爲uuid的,String的hashCode唯一,而hashcode可能爲負數] 哈希值長度不同。
4、UUID
優勢:簡單。劣勢:用戶不友好,索引關聯效率較低。
UUID全稱:Universally Unique Identifier,即通用唯一識別碼。
UUID是由一組32位數的16進制數字所構成,所以理論上UUID的總數爲16^32=2^128,約等於3.4*10^38。也就是說每納秒產生1兆個UUID,要花100億年纔會將所有UUID用完。
UUID的標準形式包含32個16進制數字,以連字號分爲五段,形式爲8-4-4-4-12的32個字符,如:550e8400-e19b-41d4-a716-446655440000。
5、twitter的SnowFlake
Twitter-Snowflake算法產生的背景相當簡單,爲了滿足Twitter每秒上萬條消息的請求,每條消息都必須分配一條唯一的id,這些id還需要一些大致的順序(方便客戶端排序),並且在分佈式系統中不同機器產生的id必須不同.Snowflake算法核心把時間戳,工作機器id,序列號(毫秒級時間41位+機器ID 10位+毫秒內序列12位)組合在一起。
除了最高位bit標記爲不可用以外,其餘三組bit佔位均可浮動,看具體的業務需求而定。默認情況下41bit的時間戳可以支持該算法使用到2082年,10bit的工作機器id可以支持1023臺機器,序列號支持1毫秒產生4095個自增序列id。
時間戳+機器id+序列號。
snowflake算法是一款本地生成的(ID生成過程不依賴任何中間件,無網絡通信),保證ID全局唯一,並且ID總體有序遞增,性能每秒生成300w+。 總體有序遞增。
此方法可能存在id重複的問題,謹慎使用
StringBuilder idBuilder = new StringBuilder();
idBuilder.append(System.currentTimeMillis());
System.out.println(idBuilder.toString());
String userIdStr = "123456789".toString();
if (userIdStr.length() <= 4) {
idBuilder.append(userIdStr);
} else {
idBuilder.append(userIdStr.substring(userIdStr.length() - 4));
}
Random random = new Random();
int randomPart = random.nextInt(99) + 1;
if (randomPart < 10) {
idBuilder.append('0');
}
idBuilder.append(randomPart);
System.out.println( Long.parseLong(idBuilder.toString()));