Twitter-Snowflake算法產生的背景至關簡單,爲了知足Twitter每秒上萬條消息的請求,每條消息都必須分配一條惟一的id,這些id還須要一些大體的順序(方便客戶端排序),而且在分佈式系統中不一樣機器產生的id必須不一樣。html
把時間戳,工做機器id,序列號組合在一塊兒。linux
除了最高位bit標記爲不可用之外,其他三組bit佔位都可浮動,看具體的業務需求而定。默認狀況下41bit的時間戳能夠支持該算法使用到2082年,10bit的工做機器id能夠支持1023臺機器,序列號支持1毫秒產生4095個自增序列id。下文會具體分析。git
這裏時間戳的細度是毫秒級,具體代碼以下,建議使用64位linux系統機器,由於有vdso,gettimeofday()在用戶態就能夠完成操做,減小了進入內核態的損耗。github
1算法 2sql 3服務器 4多線程 5分佈式 6ui |
|
默認狀況下有41個bit能夠供使用,那麼一共有T(1llu << 41)毫秒供你使用分配,年份 = T / (3600 * 24 * 365 * 1000) = 69.7年。若是你只給時間戳分配39個bit使用,那麼根據一樣的算法最後年份 = 17.4年。
嚴格意義上來講這個bit段的使用能夠是進程級,機器級的話你可使用MAC地址來惟一標示工做機器,工做進程級可使用IP+Path來區分工做進程。若是工做機器比較少,可使用配置文件來設置這個id是一個不錯的選擇,若是機器過多配置文件的維護是一個災難性的事情。
這裏的解決方案是須要一個工做id分配的進程,可使用本身編寫一個簡單進程來記錄分配id,或者利用Mysql auto_increment機制也能夠達到效果。
工做進程與工做id分配器只是在工做進程啓動的時候交互一次,而後工做進程能夠自行將分配的id數據落文件,下一次啓動直接讀取文件裏的id使用。
PS:這個工做機器id的bit段也能夠進一步拆分,好比用前5個bit標記進程id,後5個bit標記線程id之類:D
序列號就是一系列的自增id(多線程建議使用atomic),爲了處理在同一毫秒內須要給多條消息分配id,若同一毫秒把序列號用完了,則「等待至下一毫秒」。
1 2 3 4 5 6 7 8 |
|
整體來講,是一個很高效很方便的GUID產生算法,一個int64_t字段就能夠勝任,不像如今主流128bit的GUID算法,即便沒法保證嚴格的id序列性,可是對於特定的業務,好比用作遊戲服務器端的GUID產生會很方便。另外,在多線程的環境下,序列號使用atomic能夠在代碼實現上有效減小鎖的密度。