1. 程式人生 > >【JAVA】系統唯一ID生成方案討論

【JAVA】系統唯一ID生成方案討論

這種文章,網上應該很多了,不過自己不寫一遍,總是不會印象太深刻,所以今天為了再度加深印象,自己也寫一遍。

現在的網際網路專案,使用者數越來越多,系統基本都是分散式部署,所以基於資料庫的自增id這裡就不說了。

1、UUID

這個東西是JAVA原生API提供的,它的確能保證唯一,但是有個弊端,它是一個字串,字母數字組合,對於分散式系統中資料庫主鍵的生成就不行了,資料庫主鍵大家都是用整型型別來定義的,字母數字組合這種肯定不行了。

但是非資料庫主鍵生成的場景倒是可以用用,必須訊息唯一性這種,它是本地生成,沒有遠端呼叫,不存在網路時間,效率高;如果用它來建索引,效率是很低的。

2、獨立的ID生成服務

這個應該比較多見,專門搭建一個系統用來給各個接入系統分配唯一ID,每個系統每次來請求的時候返回一段ID,系統拿到自己用,用完後,再來申請,再次分配下一區段的,以此類推。

這種方法,如果ID生成服務出現故障,那對其它所有系統來說都是災難,可靠性要求太高了,效能效率方面倒是沒有什麼問題,區間分配,效率很高。

3、時間戳

直接取當前毫秒時間戳,效率高,也是整型數字,但是對併發量要求高的就不行了,無法保證唯一,1秒最多隻能生成1000個嘛,因為是毫秒時間戳,小規模系統可以用用的,簡單高效。

4、snowflake演算法

這是twitter的一個id生成演算法

Twitter-Snowflake演算法產生的背景相當簡單,為了滿足Twitter每秒上萬條訊息的請求,每條訊息都必須分配一條唯一的id,這些id還需要一些大致的順序(方便客戶端排序),並且在分散式系統中不同機器產生的id必須不同。


首先我們需要一個long型別的變數來儲存這個生成的id,第一位固定為0,因為id都是正數嘛,還剩63位,用x位表示毫秒時間戳,用y位表示程序id,用z位表示同一個時間戳下的序列號,x+y+z=63。我們直接看程式碼


package id.test;

import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.Set;

/**
 * ClassName:IdGenerator <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date: 2017年2月17日 下午3:08:34 <br/>
 * 
 * @author chiwei
 * @version
 * @since JDK 1.6
 * @see
 */
public class IdGenerator {
	/**
	 * SnowFlake演算法 64位Long型別生成唯一ID 第一位0,表明正數 2-42,41位,表示毫秒時間戳差值,起始值自定義
	 * 43-52,10位,機器編號,5位資料中心編號,5位程序編號 53-64,12位,毫秒內計數器 本機記憶體生成,效能高
	 * 
	 * 主要就是三部分: 時間戳,程序id,序列號 時間戳41,id10位,序列號12位
	 * 
	 * @author chiwei
	 * @param args
	 * @since JDK 1.6
	 */

	private final static long beginTs = 1483200000000L;

	private long lastTs = 0L;

	private long processId;
	private int processIdBits = 10;

	private long sequence = 0L;
	private int sequenceBits = 12;

	// 10位程序ID標識
	public IdGenerator(long processId) {
		if (processId > ((1 << processIdBits) - 1)) {
			throw new RuntimeException("程序ID超出範圍,設定位數" + processIdBits + ",最大"
					+ ((1 << processIdBits) - 1));
		}
		this.processId = processId;
	}

	protected long timeGen() {
		return System.currentTimeMillis();
	}

	public synchronized long nextId() {
		long ts = timeGen();
		if (ts < lastTs) {// 剛剛生成的時間戳比上次的時間戳還小,出錯
			throw new RuntimeException("時間戳順序錯誤");
		}
		if (ts == lastTs) {// 剛剛生成的時間戳跟上次的時間戳一樣,則需要生成一個sequence序列號
			// sequence迴圈自增
			sequence = (sequence + 1) & ((1 << sequenceBits) - 1);
			// 如果sequence=0則需要重新生成時間戳
			if (sequence == 0) {
				// 且必須保證時間戳序列往後
				ts = nextTs(lastTs);
			}
		} else {// 如果ts>lastTs,時間戳序列已經不同了,此時可以不必生成sequence了,直接取0
			sequence = 0L;
		}
		lastTs = ts;// 更新lastTs時間戳
		return ((ts - beginTs) << (processIdBits + sequenceBits)) | (processId << sequenceBits)
				| sequence;
	}

	protected long nextTs(long lastTs) {
		long ts = timeGen();
		while (ts <= lastTs) {
			ts = timeGen();
		}
		return ts;
	}

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		IdGenerator ig = new IdGenerator(1023);
		String str = "20170101";
		System.out.println(new SimpleDateFormat("YYYYMMDD").parse(str).getTime());
		Set<Long> set = new HashSet<Long>();
		long begin = System.nanoTime();
		for (int i = 0; i < 10; i++) {
			set.add(ig.nextId());
		}
		System.out.println("time=" + (System.nanoTime() - begin)/1000.0 + " us");
		System.out.println(set.size());
		System.out.println(set);
	}
}
41的時間戳,儲存當前時間戳與開始時間戳的差值,大概可以用69年,當然x,y,z可以自己根據情況分配,不是固定的。

此方法同樣是本地生成,效率非常高,唯一性滿足度很高,只需要以上一個類就行了,每個程序啟動時,分配不同的processId即可。

相關推薦

JAVA系統唯一ID生成方案討論

這種文章,網上應該很多了,不過自己不寫一遍,總是不會印象太深刻,所以今天為了再度加深印象,自己也寫一遍。 現在的網際網路專案,使用者數越來越多,系統基本都是分散式部署,所以基於資料庫的自增id這裡就不說了。 1、UUID 這個東西是JAVA原生API提供的,它的確能保證唯一

系統設計分散式唯一ID生成方案總結

目錄 分散式系統中唯一ID生成方案 1. 唯一ID簡介 2. 全域性ID常見生成方案 2.1 UUID生成 2.2 資料庫生成 2.3 Redis生成 2.4

分布式系統唯一ID生成方案匯總

gen 傳輸數據 lee sleep gui 有效 很難 sha 調整 系統唯一ID是我們在設計一個系統的時候常常會遇見的問題,也常常為這個問題而糾結。生成ID的方法有很多,適應不同的場景、需求以及性能要求。所以有些比較復雜的系統會有多個ID生成的策略。下面就介紹一些常見的

分散式系統唯一ID生成方案彙總

系統唯一ID是我們在設計一個系統的時候常常會遇見的問題,也常常為這個問題而糾結。生成ID的方法有很多,適應不同的場景、需求以及效能要求。所以有些比較複雜的系統會有多個ID生成的策略。下面就介紹一些常見的ID生成策略。 1. 資料庫自增長序列或欄位 最常見的方式。利用資

Javaitext根據模板生成pdf(包括圖片和表格)

金額 res report als fields positions 創建模板 bst open() 1、導入需要的jar包:itext-asian-5.2.0.jar itextpdf-5.5.11.jar。 2、新建word文檔,創建模板,將文件另存為pdf,並用Ado

全域性唯一ID生成方案對比 • cenalulu's Tech Blog

彙總了各大公司的全域性唯一ID生成方案,並做了一個簡單的優劣比較 背景:在實現大型分散式程式時,通常會有全域性唯一ID(也成GUID)生成的需求,用來對每一個物件標識一個代號。本文就列舉了博主收集的各種全域性唯一ID生成的方案,做一個簡單的類比和備忘。 GUID的基本需求 一

Java使用Apache POI生成和解析Excel檔案

概述   Excel是我們平時工作中比較常用的用於儲存二維表資料的,JAVA也可以直接對Excel進行操作,分別有jxl和poi,2種方式。 程式碼   要使用poi,必須引入poi的jar包,maven依賴如下(最新包可參考mvn資訊): <

python--Python中生成唯一ID的庫——UUID

原文連結https://www.douban.com/note/69073375/ 本來是要給例項新增唯一標識,想了一個偽隨機的方法: # 我想的偽隨機辦法 # 用時間戳和隨機數來生成唯一數字id import scipy

Java得到當前系統時間,精確到毫秒

logs out println -1 gettime system public pan time import java.text.SimpleDateFormat; import java.util.Date; import java.util.Calenda

javajava反射機制,動態獲取對象的屬性和對應的參數值,並屬性按照字典序排序,Field.setAccessible()方法的說明可用於微信支付 簽名生成

modifier 直接 this 字段值 1-1 讓我 toupper ima play 方法1:通過get()方法獲取屬性值 package com.sxd.test.controller; public class FirstCa{ private

javagoogle的zxing架包生成二維碼和讀取二維碼可帶文字和logo

oms cga dispose framework 增加 span 記錄 ora obj 承接RC4生成不重復字符串的需求之後,因為優惠碼要方便用戶使用的緣故,所以思來想去,覺得還是直接生成二維碼給用戶直接掃比較實用,也不用用戶專門記錄冗長的優惠碼編號。 =========

Java 劍指offer(56-2) 陣列中唯一隻出現一次的數字 《劍指Offer》Java實現合集 56-1) 陣列中只出現一次的兩個數字 《劍指Offer》Java實現合集

  本文參考自《劍指offer》一書,程式碼採用Java語言。 更多:《劍指Offer》Java實現合集   題目   在一個數組中除了一個數字只出現一次之外,其他數字都出現了三次。請找出那個只出現一次的數字。 思路   這道題中數字出現了三次,無法像56-1) 陣列

分散式系統ID生成方案彙總

/** * Twitter_Snowflake<br> * SnowFlake的結構如下(每部分用-分開):<br> * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 0000000000

JavaJava開發整合 Swagger UI生成可檢視的API文件(詳細圖解)

目前幾乎所有的開放平臺都是把API以文件的形式放在網站上,如下: 不知道有沒有開發人員和我一樣,有時對一些API說明的理解比較模糊,總想著能直接驗證一下自己的理解就好了,而不是需要去專案

java賣票系統

第二種正確的程式碼,可以進一步理解synchronized限定符: package thread_1; class SaleTickets implements Runnable{ privat

JAVA使用ZXing生成巢狀圖片的二維碼

1.先下載zxing開發包,這裡用到的只是core那個jar包 2.使用zxing開發還需要一個類,程式碼如下 package com.sudytech.zxing; import java.awt.Color; import java.awt.Graphics2D;

JAVA使用ZXing生成二維碼

1.先下載zxing開發包,這裡用到的只是core那個jar包  2.使用zxing開發還需要一個類,程式碼如下 package com.sudytech.zxing; import java.awt.image.BufferedImage; import java.i

JAVA獲取系統當前時間

/** * 可以格式化的時間 * @return */ private static String getTime1(){ Date nowTime = new Date(); SimpleDateFormat

JavaSpringMVC專案正式環境測試環境切換方案

之前同事在專案裡面正式環境測試環境配置檔案都放在一起,每次釋出都得註釋一部分,讓另一部分啟用,隨著配置檔案內容的越來越多,很容易在釋出時候出錯,我摸索了半天實驗出來一個方案,可供大家參考。本方案基於maven的spring.profiles.active功能,用的最簡單粗暴方

JAVA科研資訊管理系統

一、前言 本學期學習了JAVA語言,在學期的結束,寫一個有操作介面,與資料庫關聯的管理系統,用來鞏固自己本學習所學的知識。 用到的知識:JAVA基礎,JAVA介面設計(GUI),Oracle資料庫(需要掌握資料庫的基本操作語句),連結資料庫。 使用的開發工