方法一:基於數據庫生成
A庫、B庫、C庫支持同時寫入
A庫初始值為1,自增為3,獲取的值一次是1、4、7
B庫初始值為2,自增為3,獲取的值一次是2、5、8
C庫初始值為3,自增為3,獲取的值一次是6、6、9
獲取ID時可從三庫輪詢獲取
優點
此方法使用數據庫原有的功能,所以相對簡單
能夠保證唯一性
能夠保證遞增性
id 之間的步長是固定且可自定義的
缺點
數據庫的寫壓力依然很大,每次生成ID都要訪問數據庫
喪失了ID生成的“絕對遞增性”:先訪問DB 01生成0,3,再訪問DB 02生成1,可能導致在非常短的時間內,ID生成不是絕對遞增的
方法二:單點批量ID生成服務
數據庫使用雙master保證可用性,數據庫中只存儲當前ID的最大值
ID生成服務假設每次從數據庫批量拉取5個ID,並將當前ID的最大值修改為5,這樣應用訪問ID生成服務索要ID,ID生成服務不需要每次訪問數據庫,就能依次派發1,2,3,4,5這些ID了;當ID生成服務用完了已拉取的ID之后,再去數據庫拉取5個ID,然后將數據庫中存儲的最大值改為10,這樣數據庫的壓力就降低到原來的1/6。
ID生成服務做成集群,從數據庫獲取來的id可放入緩存(redis),當需要從數據庫獲取新的ID時,使用分布式鎖來控制,只需要其中一台服務去數據庫獲取
優點:
保證了ID生成的絕對遞增有序
大大的降低了數據庫的壓力,ID生成可以做到每秒生成幾萬幾十萬個
缺點:
ID生成服務如果掛了,服務重啟起來之后,繼續生成ID可能會不連續
雖然每秒可以生成幾萬幾十萬個ID,但畢竟還是有性能上限,無法進行水平擴展
方法三:UUID
優點
本地生成ID,不需要進行遠程調用,時延低
擴展性好,基本可以認為沒有性能上限
缺點
無法保證趨勢遞增
UUID過長,往往用字符串表示,作為主鍵建立索引查詢效率低,常見優化方案為轉化為兩個uint64整數存儲或者折半存儲
方法四:取當前毫秒數
優點
本地生成ID,不需要進行遠程調用,時延低
生成的ID趨勢遞增
生成的ID是整數,建立索引后查詢效率高
缺點
如果並發量超過1000,會生成重復的ID
方法五:使用 Redis 來生成 id
當使用數據庫來生成ID性能不夠要求的時候,我們可以嘗試使用Redis來生成ID。這主要依賴於Redis是單線程的,所以也可以用生成全局唯一的ID。可以用Redis的原子操作 INCR 和 INCRBY 來實現。
優點
依賴於數據庫,靈活方便,且性能優於數據庫。
數字ID天然排序,對分頁或者需要排序的結果很有幫助。
缺點
需要編碼和配置的工作量比較大。
方法六:Twitter 開源的 Snowflake 算法
snowflake的結構如下(每部分用-分開)
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
第一位為未使用,接下來的41位為毫秒級時間(41位的長度可以使用69年),然后是5位datacenterId和5位workerId(10位的長度最多支持部署1024個節點) ,最后12位是毫秒內的計數(12位的計數順序號支持每個節點每毫秒產生4096個ID序號)
一共加起來剛好64位,為一個Long型。(轉換成字符串后長度最多19)
snowflake生成的ID整體上按照時間自增排序,並且整個分布式系統內不會產生ID碰撞(由datacenter和workerId作區分),並且效率較高。經測試snowflake每秒能夠產生26萬個ID。
方法七:基於分布式集群協調器生成
以強一致性為目標的:ZooKeeper為代表
以最終一致性為目標的:Consul為代表
