日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

利用mysql實現(xiàn)的雪花算法案例

瀏覽:65日期:2023-10-12 16:19:04

一、為何要用雪花算法

1、問題產(chǎn)生的背景

現(xiàn)如今越來越多的公司都在用分布式、微服務,那么對應的就會針對不同的服務進行數(shù)據(jù)庫拆分,然后當數(shù)據(jù)量上來的時候也會進行分表,那么隨之而來的就是分表以后id的問題。

例如之前單體項目中一個表中的數(shù)據(jù)主鍵id都是自增的,mysql是利用autoincrement來實現(xiàn)自增,而oracle是利用序列來實現(xiàn)的,但是當單表數(shù)據(jù)量上來以后就要進行水平分表,阿里java開發(fā)建議是單表大于500w的時候就要分表,但是具體還是得看業(yè)務,如果索引用的號的話,單表千萬的數(shù)據(jù)也是可以的。水平分表就是將一張表的數(shù)據(jù)分成多張表,那么問題就來了如果還是按照以前的自增來做主鍵id,那么就會出現(xiàn)id重復,這個時候就得考慮用什么方案來解決分布式id的問題了。

2、解決方案

2.1、數(shù)據(jù)庫表

可以在某個庫中專門維護一張表,然后每次無論哪個表需要自增id的時候都去查這個表的記錄,然后用for update鎖表,然后取到的值加一,然后返回以后把再把值記錄到表中,但是這個方法適合并發(fā)量比較小的項目,因此每次都得鎖表。

2.2、redis

因為redis是單線程的,可以在redis中維護一個鍵值對,然后哪個表需要直接去redis中取值然后加一,但是這個跟上面一樣由于單線程都是對高并發(fā)的支持不高,只適合并發(fā)量小的項目。

2.3、uuid

可以使用uuid作為不重復主鍵id,但是uuid有個問題就是其是無序的字符串,如果使用uuid當做主鍵,那么主鍵索引就會失效。

2.4、雪花算法

雪花算法是解決分布式id的一個高效的方案,大部分互聯(lián)網(wǎng)公司都在使用雪花算法,當然還有公司自己實現(xiàn)其他的方案。

二、雪花算法

1、原理

利用mysql實現(xiàn)的雪花算法案例

雪花算法就是使用64位long類型的數(shù)據(jù)存儲id,最高位一位存儲0或者1,0代表整數(shù),1代表負數(shù),一般都是0,所以最高位不變,41位存儲毫秒級時間戳,10位存儲機器碼(包括5位datacenterId和5位workerId),12存儲序列號。這樣最大2的10次方的機器,也就是1024臺機器,最多每毫秒每臺機器產(chǎn)生2的12次方也就是4096個id。(下面有代碼實現(xiàn))

但是一般我們沒有那么多臺機器,所以我們也可以使用53位來存儲id。為什么要用53位?

因為我們幾乎都是跟web頁面打交道,就需要跟js打交道,js支持最大的整型范圍為53位,超過這個范圍就會丟失精度,53之內(nèi)可以直接由js讀取,超過53位就需要轉(zhuǎn)換成字符串才能保證js處理正確。53存儲的話,32位存儲秒級時間戳,5位存儲機器碼,16位存儲序列化,這樣每臺機器每秒可以生產(chǎn)65536個不重復的id。

2、缺點

由于雪花算法嚴重依賴時間,所以當發(fā)生服務器時鐘回撥的問題是會導致可能產(chǎn)生重復的id。當然幾乎沒有公司會修改服務器時間,修改以后會導致各種問題,公司寧愿新加一臺服務器也不愿意修改服務器時間,但是不排除特殊情況。

如何解決時鐘回撥的問題?可以對序列化的初始值設置步長,每次觸發(fā)時鐘回撥事件,則其初始步長就加1w,可以在下面代碼的第85行來實現(xiàn),將sequence的初始值設置為10000。

三、代碼實現(xiàn)

64位的代碼實現(xiàn):

package com.yl.common;/** * Twitter_Snowflake<br> * SnowFlake的結構如下(每部分用-分開):<br> * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br> * 1位標識,由于long基本類型在Java中是帶符號的,最高位是符號位,正數(shù)是0,負數(shù)是1,所以id一般是正數(shù),最高位是0<br> * 41位時間截(毫秒級),注意,41位時間截不是存儲當前時間的時間截,而是存儲時間截的差值(當前時間截 - 開始時間截) * 得到的值),這里的的開始時間截,一般是我們的id生成器開始使用的時間,由我們程序來指定的(如下下面程序IdWorker類的startTime屬性)。41位的時間截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br> * 10位的數(shù)據(jù)機器位,可以部署在1024個節(jié)點,包括5位datacenterId和5位workerId<br> * 12位序列,毫秒內(nèi)的計數(shù),12位的計數(shù)順序號支持每個節(jié)點每毫秒(同一機器,同一時間截)產(chǎn)生4096個ID序號<br> * 加起來剛好64位,為一個Long型。<br> * SnowFlake的優(yōu)點是,整體上按照時間自增排序,并且整個分布式系統(tǒng)內(nèi)不會產(chǎn)生ID碰撞(由數(shù)據(jù)中心ID和機器ID作區(qū)分),并且效率較高,經(jīng)測試,SnowFlake每秒能夠產(chǎn)生26萬ID左右。 */public class SnowflakeIdWorker { // ==============================Fields=========================================== /** 開始時間截 (2020-01-01) */ private final long twepoch = 1577808000000L; /** 機器id所占的位數(shù) */ private final long workerIdBits = 5L; /** 數(shù)據(jù)標識id所占的位數(shù) */ private final long datacenterIdBits = 5L; /** 支持的最大機器id,結果是31 (這個移位算法可以很快的計算出幾位二進制數(shù)所能表示的最大十進制數(shù)) */ private final long maxWorkerId = -1L ^ (-1L << workerIdBits); /** 支持的最大數(shù)據(jù)標識id,結果是31 */ private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); /** 序列在id中占的位數(shù) */ private final long sequenceBits = 12L; /** 機器ID向左移12位 */ private final long workerIdShift = sequenceBits; /** 數(shù)據(jù)標識id向左移17位(12+5) */ private final long datacenterIdShift = sequenceBits + workerIdBits; /** 時間截向左移22位(5+5+12) */ private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; /** 生成序列的掩碼,這里為4095 (0b111111111111=0xfff=4095) */ private final long sequenceMask = -1L ^ (-1L << sequenceBits); /** 工作機器ID(0~31) */ private long workerId; /** 數(shù)據(jù)中心ID(0~31) */ private long datacenterId; /** 毫秒內(nèi)序列(0~4095) */ private long sequence = 0L; /** 上次生成ID的時間截 */ private long lastTimestamp = -1L; //==============================Constructors===================================== /** * 構造函數(shù) * @param workerId 工作ID (0~31) * @param datacenterId 數(shù)據(jù)中心ID (0~31) */ public SnowflakeIdWorker(long workerId, long datacenterId) { if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException(String.format('worker Id can’t be greater than %d or less than 0', maxWorkerId)); } if (datacenterId > maxDatacenterId || datacenterId < 0) { throw new IllegalArgumentException(String.format('datacenter Id can’t be greater than %d or less than 0', maxDatacenterId)); } this.workerId = workerId; this.datacenterId = datacenterId; } // ==============================Methods========================================== /** * 獲得下一個ID (該方法是線程安全的) * @return SnowflakeId */ public synchronized long nextId() { long timestamp = timeGen(); //如果當前時間小于上一次ID生成的時間戳,說明系統(tǒng)時鐘回退過這個時候應當拋出異常 if (timestamp < lastTimestamp) { throw new RuntimeException( String.format('Clock moved backwards. Refusing to generate id for %d milliseconds', lastTimestamp - timestamp)); } //如果是同一時間生成的,則進行毫秒內(nèi)序列 if (lastTimestamp == timestamp) { sequence = (sequence + 1) & sequenceMask; //毫秒內(nèi)序列溢出 if (sequence == 0) { //阻塞到下一個毫秒,獲得新的時間戳 timestamp = tilNextMillis(lastTimestamp); } } //時間戳改變,毫秒內(nèi)序列重置 else { sequence = 0L; } //上次生成ID的時間截 lastTimestamp = timestamp; //移位并通過或運算拼到一起組成64位的ID return ((timestamp - twepoch) << timestampLeftShift) // | (datacenterId << datacenterIdShift) // | (workerId << workerIdShift) // | sequence; } /** * 阻塞到下一個毫秒,直到獲得新的時間戳 * @param lastTimestamp 上次生成ID的時間截 * @return 當前時間戳 */ protected long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } /** * 返回以毫秒為單位的當前時間 * @return 當前時間(毫秒) */ protected long timeGen() { return System.currentTimeMillis(); } //==============================Test============================================= /** 測試 */ public static void main(String[] args) { SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0); for (int i = 0; i < 100; i++) { long id = idWorker.nextId(); System.out.println(id); } }}

補充知識:雪花算法實現(xiàn)分布式自增長ID

我就廢話不多說了,大家還是直接看代碼吧~

/** * <p>名稱:IdWorker.java</p> * <p>描述:分布式自增長ID</p> * <pre> * Twitter的 Snowflake JAVA實現(xiàn)方案 * </pre> * 核心代碼為其IdWorker這個類實現(xiàn),其原理結構如下,我分別用一個0表示一位,用—分割開部分的作用: * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000 * 在上面的字符串中,第一位為未使用(實際上也可作為long的符號位),接下來的41位為毫秒級時間, * 然后5位datacenter標識位,5位機器ID(并不算標識符,實際是為線程標識), * 然后12位該毫秒內(nèi)的當前毫秒內(nèi)的計數(shù),加起來剛好64位,為一個Long型。 * 這樣的好處是,整體上按照時間自增排序,并且整個分布式系統(tǒng)內(nèi)不會產(chǎn)生ID碰撞(由datacenter和機器ID作區(qū)分), * 并且效率較高,經(jīng)測試,snowflake每秒能夠產(chǎn)生26萬ID左右,完全滿足需要。 * <p> * 64位ID (42(毫秒)+5(機器ID)+5(業(yè)務編碼)+12(重復累加)) * * @author Polim */public class IdWorker { // 時間起始標記點,作為基準,一般取系統(tǒng)的最近時間(一旦確定不能變動) private final static long twepoch = 1288834974657L; // 機器標識位數(shù) private final static long workerIdBits = 5L; // 數(shù)據(jù)中心標識位數(shù) private final static long datacenterIdBits = 5L; // 機器ID最大值 private final static long maxWorkerId = -1L ^ (-1L << workerIdBits); // 數(shù)據(jù)中心ID最大值 private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); // 毫秒內(nèi)自增位 private final static long sequenceBits = 12L; // 機器ID偏左移12位 private final static long workerIdShift = sequenceBits; // 數(shù)據(jù)中心ID左移17位 private final static long datacenterIdShift = sequenceBits + workerIdBits; // 時間毫秒左移22位 private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; private final static long sequenceMask = -1L ^ (-1L << sequenceBits); /* 上次生產(chǎn)id時間戳 */ private static long lastTimestamp = -1L; // 0,并發(fā)控制 private long sequence = 0L; private final long workerId; // 數(shù)據(jù)標識id部分 private final long datacenterId; public IdWorker(){ this.datacenterId = getDatacenterId(maxDatacenterId); this.workerId = getMaxWorkerId(datacenterId, maxWorkerId); } /** * @param workerId * 工作機器ID * @param datacenterId * 序列號 */ public IdWorker(long workerId, long datacenterId) { if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException(String.format('worker Id can’t be greater than %d or less than 0', maxWorkerId)); } if (datacenterId > maxDatacenterId || datacenterId < 0) { throw new IllegalArgumentException(String.format('datacenter Id can’t be greater than %d or less than 0', maxDatacenterId)); } this.workerId = workerId; this.datacenterId = datacenterId; } /** * 獲取下一個ID * * @return */ public synchronized long nextId() { long timestamp = timeGen(); if (timestamp < lastTimestamp) { throw new RuntimeException(String.format('Clock moved backwards. Refusing to generate id for %d milliseconds', lastTimestamp - timestamp)); } if (lastTimestamp == timestamp) { // 當前毫秒內(nèi),則+1 sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { // 當前毫秒內(nèi)計數(shù)滿了,則等待下一秒 timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; // ID偏移組合生成最終的ID,并返回ID long nextId = ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; return nextId; } private long tilNextMillis(final long lastTimestamp) { long timestamp = this.timeGen(); while (timestamp <= lastTimestamp) { timestamp = this.timeGen(); } return timestamp; } private long timeGen() { return System.currentTimeMillis(); } /** * <p> * 獲取 maxWorkerId * </p> */ protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) { StringBuffer mpid = new StringBuffer(); mpid.append(datacenterId); String name = ManagementFactory.getRuntimeMXBean().getName(); if (!name.isEmpty()) { /* * GET jvmPid */ mpid.append(name.split('@')[0]); } /* * MAC + PID 的 hashcode 獲取16個低位 */ return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1); } /** * <p> * 數(shù)據(jù)標識id部分 * </p> */ protected static long getDatacenterId(long maxDatacenterId) { long id = 0L; try { InetAddress ip = InetAddress.getLocalHost(); NetworkInterface network = NetworkInterface.getByInetAddress(ip); if (network == null) { id = 1L; } else { byte[] mac = network.getHardwareAddress(); id = ((0x000000FF & (long) mac[mac.length - 1]) | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6; id = id % (maxDatacenterId + 1); } } catch (Exception e) { System.out.println(' getDatacenterId: ' + e.getMessage()); } return id; }}

以上這篇利用mysql實現(xiàn)的雪花算法案例就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持好吧啦網(wǎng)。

相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产欧美高清| 日韩精品专区| 久久久久久久久99精品大| 老色鬼精品视频在线观看播放| 日韩精品视频一区二区三区| 午夜性色一区二区三区免费视频| 亚洲开心激情| 日韩精品一区二区三区中文在线| 综合一区在线| 亚州欧美在线| 国产毛片久久久| 精品国产亚洲一区二区三区在线| 久久影院资源站| 成人午夜毛片| 日韩欧美国产精品综合嫩v| 欧美sss在线视频| 日韩国产网站| 婷婷丁香综合| 日韩中文字幕亚洲一区二区va在线| 亚洲一区欧美二区| 蜜桃av一区二区三区电影| 日韩一区二区三区精品| 国产美女亚洲精品7777| 国产成人精品一区二区三区免费 | 日韩视频久久| 影音先锋久久| 日韩高清一区| 欧美专区一区| 成人午夜在线| 久久在线视频免费观看| 日韩精品一卡二卡三卡四卡无卡 | 亚洲激情黄色| 人人精品久久| 精品视频在线观看网站| 欧美日韩在线网站| 美国三级日本三级久久99| 国产一精品一av一免费爽爽| 国产精品二区不卡| 亚洲在线一区| 国产色噜噜噜91在线精品| 国产精品1区| 欧美亚洲国产激情| 亚洲精品欧洲| 日本а中文在线天堂| 亚洲一区免费| 欧美成人aaa| 欧美日韩精品免费观看视频完整| 日韩精品电影一区亚洲| 九九久久国产| 午夜在线播放视频欧美| 国产极品模特精品一二| 国产主播一区| 国产日韩欧美一区二区三区在线观看| 久久久久久色| 精品久久免费| 免费观看久久av| 日韩欧美激情| 日韩精品午夜| 国产欧美日韩一区二区三区四区| 色吊丝一区二区| 亚洲人成亚洲精品| 麻豆视频在线看| 亚洲欧洲美洲国产香蕉| 国模大尺度视频一区二区| 国产一级一区二区| 麻豆国产精品一区二区三区| 国产精品男女| 亚洲激情偷拍| 精品视频一区二区三区四区五区| 丝袜美腿成人在线| 久久精品色播| 免费观看久久久4p| 中文字幕在线看片| 欧美久久香蕉| 亚洲男人在线| 91精品国产调教在线观看| 日韩高清三区| 亚洲黄页一区| xxxxx性欧美特大| 国产欧美日韩在线观看视频 | 亚洲免费播放| 91偷拍一区二区三区精品| 亚洲人成网77777色在线播放 | 亚洲专区欧美专区| 国产中文欧美日韩在线| 日本一区二区中文字幕| 久久中文字幕av| 麻豆国产欧美一区二区三区 | 99久久激情| 国产成人精品一区二区三区免费| 亚洲欧美在线综合| 亚洲激情av| 久久亚洲在线| 乱一区二区av| 日韩精品1区2区3区| 欧美在线网站| 热三久草你在线| 精品一区二区三区在线观看视频| 五月国产精品| 99在线|亚洲一区二区| 91看片一区| 成人在线视频区| 欧美国产免费| 91精品麻豆| 日本中文字幕视频一区| 蜜桃久久av| 噜噜噜久久亚洲精品国产品小说| 欧美中文字幕一区二区| 国产91在线播放精品| 国产欧美一区二区三区精品观看| 在线免费观看亚洲| 9国产精品视频| 久久精品国产大片免费观看| 日本精品不卡| 日韩一区二区中文| 高清一区二区三区av| 欧美激情麻豆| 久久免费福利| 国产精品日本一区二区不卡视频| 日本午夜精品久久久久| 日韩激情中文字幕| 影音先锋久久精品| 亚洲一区二区三区久久久| 久久中文字幕二区| 久久精品亚洲人成影院| 色老板在线视频一区二区| 亚洲成人va| 国精品一区二区| 美女亚洲一区| 9久re热视频在线精品| 国产精品普通话对白| 日韩一区二区免费看| 丝袜美腿亚洲一区二区图片| 丝袜亚洲另类欧美| 午夜久久av | 免费视频一区三区| 美女少妇全过程你懂的久久| 91成人精品| 欧美午夜不卡| 婷婷六月综合| 亚洲一区二区日韩| 欧美在线日韩| 久久精品免视看国产成人| 国产aa精品| 久久狠狠婷婷| 国产91一区| 亚洲综合三区| 日本不卡高清| 精品黄色一级片| av在线日韩| 视频精品一区二区| 国产图片一区| 成人亚洲欧美| 日韩午夜精品| 欧美专区一区| 日韩成人精品一区二区| jiujiure精品视频播放| 亚洲人www| 美女视频网站久久| 激情欧美一区二区三区| 免费的成人av| 国产精品66| 亚洲天堂久久| 日本一区二区三区视频在线看| 久久av偷拍| 999国产精品999久久久久久| 国产综合亚洲精品一区二| 免费人成在线不卡| 在线精品小视频| 亚洲精品激情| 国产欧美日韩一区二区三区在线| 麻豆理论在线观看| 亚洲一级少妇| 午夜欧美理论片| 中文无码日韩欧| 欧美一级一区| 开心激情综合| 亚洲一级少妇| 日韩中文字幕不卡| 精品国产精品国产偷麻豆| 日韩不卡在线| 亚洲尤物av| 精品三级在线| 久久久久国产精品一区三寸| 亚洲在线免费| 国产精品香蕉| 久久天堂成人| 国产伦精品一区二区三区视频 | 激情欧美国产欧美| 亚洲色图网站| 久久精品女人| 欧美亚洲国产激情| 国产亚洲精品美女久久| 日韩在线高清| 亚洲欧美在线专区| 97国产成人高清在线观看| 日韩激情精品| 日韩久久一区二区三区| 亚洲激情国产| 免费观看亚洲天堂|