Mybatis工具(五) 雪花演算法

2022-02-23 00:53:02 字數 2945 閱讀 7637

snowflake 演算法,是 twitter 開源的分布式 id 生成演算法。其核心思想就是:使用乙個 64 bit 的 long 型的數字作為全域性唯一 id ,在分布式系統中的應用十分廣泛。

給大家舉個例子吧,比如下面這個 64 bit 的 long 型數字,就是由雪花演算法生成的id。

①1 bit:是不用的,為啥呢?

因為二進位制裡第乙個 bit 為如果是 1,那麼都是負數,但是我們生成的 id 都是正數,所以第乙個 bit 統一都是 0。

②41 bit:表示的是時間戳,單位是毫秒。

41 bit 可以表示的數字多達 2^41 - 1,也就是可以標識 2 ^ 41 - 1 個毫秒值,換算成年就是表示 69 年的時間。

③10 bit:記錄工作機器 id,代表的是這個服務最多可以部署在 2^10 臺機器上,也就是 1024 臺機器。但是 10 bit 裡 5 個 bit 代表機房 id,5 個 bit 代表機器 id。意思就是最多代表 2 ^ 5 個機房(32 個機房),每個機房裡可以代表 2 ^ 5 個機器(32 臺機器),也可以根據自己公司的實際情況確定。

④12 bit:這個是用來記錄同乙個毫秒內產生的不同 id。

12 bit 可以代表的最大正整數是 2 ^ 12 - 1 = 4096,也就是說可以用這個 12 bit 代表的數字來區分同乙個毫秒內的 4096 個不同的 id。

簡單來說,你的某個服務假設要生成乙個全域性唯一 id,那麼就可以傳送乙個請求給部署了 snowflake 演算法的系統,由這個 snowflake 演算法系統來生成唯一 id。這個 snowflake 演算法系統首先肯定是知道自己所在的機房和機器的,比如機房 id = 17,機器 id = 12。接著 snowflake 演算法系統接收到這個請求之後,首先就會用二進位制位運算的方式生成乙個 64 bit 的 long 型 id,64 個 bit 中的第乙個 bit 是無意義的。接著 41 個 bit,就可以用當前時間戳(單位到毫秒),然後接著 5 個 bit 設定上這個機房 id,還有 5 個 bit 設定上機器 id。最後再判斷一下,當前這台機房的這台機器上這一毫秒內,這是第幾個請求,給這次生成 id 的請求累加乙個序號,作為最後的 12 個 bit。最終乙個 64 個 bit 的 id 就出來了。

這個演算法可以保證說,乙個機房的一台機器上,在同一毫秒內,生成了乙個唯一的 id。可能乙個毫秒內會生成多個 id,但是有最後 12 個 bit 的序號來區分開來。下面我們簡單看看這個 snowflake 演算法的乙個**實現,這就是個示例,大家如果理解了這個意思之後,以後可以自己嘗試改造這個演算法。總之就是用乙個 64 bit 的數字中各個 bit 位來設定不同的標誌位,區分每乙個 id。

public class idworker 

public long getdatacenterid()

public long gettimestamp()

public idworker(long workerid, long datacenterid, long sequence)

if (datacenterid > maxdatacenterid || datacenterid < 0)

this.workerid = workerid;

this.datacenterid = datacenterid;

this.sequence = sequence;

}// 這個是核心方法,通過呼叫nextid()方法,讓當前這台機器上的snowflake演算法程式生成乙個全域性唯一的id

public synchronized long nextid()

// 下面是說假設在同乙個毫秒內,又傳送了乙個請求生成乙個id

// 這個時候就得把seqence序號給遞增1,最多就是4096

if (lasttimestamp == timestamp)

} else

// 這兒記錄一下最近一次生成id的時間戳,單位是毫秒

lasttimestamp = timestamp;

// 這兒就是最核心的二進位制位運算操作,生成乙個64bit的id

// 先將當前時間戳左移,放到41 bit那兒;將機房id左移放到5 bit那兒;將機器id左移放到5 bit那兒;將序號放最後12 bit

// 最後拼接起來成乙個64 bit的二進位制數字,轉換成10進製就是個long型

return ((timestamp - twepoch) << timestampleftshift) |

(datacenterid << datacenteridshift) |

(workerid << workeridshift) | sequence;

}/**

* 當某一毫秒的時間,產生的id數 超過4095,系統會進入等待,直到下一毫秒,系統繼續產生id

* @param lasttimestamp

* @return

*/private long tilnextmillis(long lasttimestamp)

return timestamp;

}//獲取當前時間戳

private long timegen()

/*** main 測試類

* @param args

*/public static void main(string args) }}

snowflake演算法的優點

(1)高效能高可用:生成時不依賴於資料庫,完全在記憶體中生成。

(2)容量大:每秒中能生成數百萬的自增id。

(3)id自增:存入資料庫中,索引效率高。

snowflake演算法的缺點:

(1)依賴與系統時間的一致性,如果系統時間被**,或者改變,可能會造成id衝突或者重複。

實際中我們的機房並沒有那麼多,我們可以改進改演算法,將10bit的機器id優化,成業務表或者和我們系統相關的業務。

雪花演算法工具類

package com.baizhi.zcn.util public class snowflake if datacenterid maxdatacenterid datacenterid 0 this.workerid workerid this.datacenterid datacenteri...

SpringBoot 雪花演算法工具類

多用於生成訂單號 eg 779281037489340416 package com.ldh.util public class snowflake if datacenterid maxdatacenterid datacenterid 0 this workerid workerid this ...

《演算法競賽高階指南》 雪花雪花雪花

有n片雪花,每片雪花由六個角組成,每個角都有長度。第i片雪花六個角的長度從某個角開始順時針依次記為ai,1,ai,2,ai,6。因為雪花的形狀是封閉的環形,所以從任何乙個角開始順時針或逆時針往後記錄長度,得到的六元組都代表形狀相同的雪花。例如ai,1,ai,2,ai,6和ai,2,ai,3,ai,6...