在當前的互聯網類產品中,如何高效可用的生成的一個全局自增ID,是一個比較有挑戰性的工作。我見過的一般的做法其實就是時間戳再加固定長度的隨機 字符串。這個方案其實有兩個問題,一個是生成的自增ID的可讀性,另外就是隨機,并不是真正的唯一,它是一個碰撞概率的。其它方案,如依賴數據的自增 ID,如果多個庫,可以通過不同的步長來實現可讀的序列。不過,這其實性能上肯定不可能很高。另外,會有單點的問題。所以,果斷放棄。在查看了目前比較成 熟的snowfake方案之后,感覺不錯。下圖是它的算法核心
分3段進行詳細說明:
Snowflake – 時間戳
這里時間戳的細度是毫秒級。
Snowflake – 工作機器id
嚴格意義上來說這個bit段的使用可以是進程級,機器級的話你可以使用MAC地址來唯一標示工作機器,工作進程級可以使用IP+Path來區分工作進程。如果工作機器比較少,可以使用配置文件來設置這個id是一個不錯的選擇,如果機器過多配置文件的維護是一個災難性的事情。
Snowflake – 序列號
序列號就是一系列的自增id(多線程建議使用atomic),為了處理在同一毫秒內需要給多條消息分配id,若同一毫秒把序列號用完了,則“等待至下一毫秒”。
原理其實不復雜,下面我們結合Hazelcast(高可用的分布式內存框架)來進行實現。
snowcase,基于hazelcast的自增實現。GITHUB地址https://github.com/noctarius/snowcast
為什么選用hazelcast
1 基于內存計算,速度得到了保證
2 數據可以持久化,服務重啟之后,數據還可以讀取。
3 每秒的并發可以支持W級別
代碼示例
1 首先需要添加依賴
目前hazelcast的版本是3.5.5
2 在容器里面注入服務
這個是例用hazelcast的spi接口,封裝了自增的一個服務類
3 簡單使用例子
snowcase客戶端:
自增ID服務:
參照前面的原理說明,這里只傳遞了一個參數,就是時間戳。工作機器與序列號是使用的默認值 。其中工作機器的最大值是8129,最小值是128,序列號是hazelcast依據分布式自動生成的.至于seqName只是給這個自增ID取了別名。
CASE測試:
報告輸出:
唯的一點缺陷就是因為它的長度是41BIT,這個方法的使用年限差不多是69年。
具體是這樣算的:默認情況下有41個bit可以供使用,那么一共有T(1llu << 41)毫秒供你使用分配,年份 = T / (3600 * 24 * 365 * 1000) = 69.7年。
其中有一段,我還沒有弄明白,T(1llu << 41),希望知道的同學提示,多謝。
我的微信公眾號,歡迎溝通學習。
posted on 2016-04-26 09:22
alexcai 閱讀(2143)
評論(0) 編輯 收藏