乙個唯一 id 在乙個分布式系統中是非常重要的乙個業務屬性,其中包括一些如訂單 id,訊息 id ,會話 id,他們都有一些共有的特性:
全域性唯一很好理解,目的就是唯一標識某個次請求,某個業務。
通常有以下幾種方案:
可以利用mysql
中的自增屬性auto_increment
來生成全域性唯一 id,也能保證趨勢遞增。 但這種方式太依賴 db,如果資料庫掛了那就非常容易出問題。
但也有改進空間,可以將資料庫水平拆分,如果拆為了兩個庫 a 庫和 b 庫。 a 庫的遞增方式可以是0 ,2 ,4 ,6
。b 庫則是1 ,3 ,5 ,7
。這樣的方式可以提高系統可用性,並且 id 也是趨勢遞增的。
還可以採用uuid
的方式生成唯一 id,由於是在本地生成沒有了網路之類的消耗,所有效率非常高。
但也有以下幾個問題:
這種做法非常簡單,可以利用本地的毫秒數加上一些業務 id 來生成唯一id,這樣可以做到趨勢遞增,並且是在本地生成效率也很高。
但有乙個致命的缺點:當併發量足夠高的時候唯一性就不能保證了。
可以基於 twitter 的 snowflake 演算法來實現。它主要是一種劃分命名空間的演算法,將生成的 id 按照機器、時間等來進行標誌。
首先乙個twitter演算法生成的id為乙個long長度,8位元組64位
snowflake的結構s如下(每部分用-分開):
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)
這裡還需要解釋一下,41位毫秒級時間不是當前毫秒時間而是現在與開始的差,這個id生成器開始執行時會產生乙個毫秒時間這個儲存下來,然後每生成乙個id號,會把當前時間的毫秒值和這個之前儲存的相減。即是這個41位的值
10位的資料機器碼值,區分分布式環境下不同機器和不同業務資料所用沒啥太多解釋
最後12位,代表是在41位毫秒值相同情況下,進行排序,即一毫秒可以產生4096個序列號
snowflake生成的id整體上按照時間自增排序,並且整個分布式系統內不會產生id碰撞(由datacenter和workerid作區分),並且效率較高。經測試snowflake每秒能夠產生26萬個id。
MySQL分布式實現ID自增
由於資料量以及io效率的因素,很多專案對資料支援的資料庫會採取分庫分表的方式。使用了分庫分表之後需要解決的乙個問題就是主鍵的生成。多個表之間的主鍵就不能用資料庫本身的自增主鍵來支援,因為不同表之間生成的主鍵會重複。所以需要其他的方式獲取主鍵id。一般來說解決方案主要有三種 oracle sequen...
分布式自增ID演算法snowflake的JAVA實現
分布式系統中,有一些需要使用全域性唯一id的場景,這種時候為了防止id衝突可以使用36位的uuid,但是uuid有一些缺點,首先他相對比較長,另外uuid一般是無序的。有些時候我們希望能使用一種簡單一些的id,並且希望id能夠按照時間有序生成。而twitter的snowflake解決了這種需求,最初...
分布式唯一ID自增(雪花演算法)
public class idworker if datacenterid maxdatacenterid datacenterid 0 this.workerid workerid this.datacenterid datacenterid methods 獲得下乙個id 該方法是執行緒安全的 ...