mybatis-plus雪花算法自動生成機器id原理及源碼
1、雪花算法原理
雪花算法使用一個 64 bit 的 long 型的數字作為全局唯一 id。這 64 個 bit 中,其中 1 個 bit 是不用的,然後用其中的 41 bit 作為毫秒數,用 10 bit 作為工作機器 id,12 bit 作為序列號。
- 1bit,不用,因為二進制中最高位是符號位,1表示負數,0表示正數。生成的id一般都是用整數,所以最高位固定為0。
- 41bit-時間戳,用來記錄時間戳,毫秒級。
- 10bit-工作機器id,用來記錄工作機器id。
- 12bit-序列號,序列號,用來記錄同毫秒內產生的不同id。即可以用0、1、2、3、…4094這4095個數字,來表示同一機器同一時間截(毫秒)內產生的4095個ID序號。
SnowFlake可以保證:
所有生成的id按時間趨勢遞增
整個分佈式系統內不會產生重復id(因為有datacenterId和workerId來做區分)
如上大概瞭解瞭雪花算法的原理,而且也知道機器號對於雪花算法的重要性。如果機器號一樣,可能會出現id重復的情況。
mybatis-plus自3.3.0開始,默認使用雪花算法+UUID(不含中劃線),但是它並沒有強制讓開發者配置機器號。這一點很是疑惑,這樣可能會讓不瞭解雪花算法的人埋下瞭一個坑。
但是這麼強大的一個框架難道真的沒有做優化嗎?帶著問題,查看瞭下mybatis-plus雪花算法源碼com.baomidou.mybatisplus.core.toolkit.Sequence
。最終發現在沒有設置機器號的情況下,會通過當前物理網卡地址和jvm的進程ID自動生成。這真的是一個較好的解決方案。一般在一個集群中,MAC+JVM進程PID
一樣的幾率非常小。
2、自動生成唯一機器號源碼
核心代碼。有兩個構造方法,一個無參構造,一個有參構造。
public Sequence() { //通過當前物理網卡地址獲取datacenterId this.datacenterId = getDatacenterId(maxDatacenterId); //物理網卡地址+jvm進程pi獲取workerId this.workerId = getMaxWorkerId(datacenterId, maxWorkerId); } /** * 有參構造器 * * @param workerId 工作機器 ID * @param datacenterId 序列號 */ public Sequence(long workerId, long datacenterId) { Assert.isFalse(workerId > maxWorkerId || workerId < 0, String.format("worker Id can't be greater than %d or less than 0", maxWorkerId)); Assert.isFalse(datacenterId > maxDatacenterId || datacenterId < 0, String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); this.workerId = workerId; this.datacenterId = datacenterId; }
- 無參構造 開發者沒有設置機器號時
- 有參構造 開發者自行設置機器號
protected static long getDatacenterId(long maxDatacenterId) { long id = 0L; try { //獲取本機(或者服務器ip地址) //DESKTOP-123SDAD/192.168.1.87 InetAddress ip = InetAddress.getLocalHost(); NetworkInterface network = NetworkInterface.getByInetAddress(ip); //一般不是null會進入else if (network == null) { id = 1L; } else { //獲取物理網卡地址 byte[] mac = network.getHardwareAddress(); if (null != mac) { id = ((0x000000FF & (long) mac[mac.length - 2]) | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6; id = id % (maxDatacenterId + 1); } } } catch (Exception e) { logger.warn(" getDatacenterId: " + e.getMessage()); } return id; }
/** * 獲取 maxWorkerId */ protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) { StringBuilder mpid = new StringBuilder(); mpid.append(datacenterId); //獲取jvm進程信息 String name = ManagementFactory.getRuntimeMXBean().getName(); if (StringUtils.isNotBlank(name)) { /* * 獲取進程PID */ mpid.append(name.split(StringPool.AT)[0]); } /* * MAC + PID 的 hashcode 獲取16個低位 */ return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1); }
以上就是mybatis-plus雪花算法自動生成機器id原理的詳細內容,更多關於mybatis plus雪花id的資料請關註WalkonNet其它相關文章!