欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Java代碼實現(xiàn)游戲服務(wù)器生成全局唯一ID的方法匯總

 更新時間:2016年10月28日 09:10:27   作者:游戲技術(shù)網(wǎng)  
我們在做服務(wù)器系統(tǒng)開發(fā)的時候,為了適應(yīng)數(shù)據(jù)大并發(fā)的請求,需要插入數(shù)據(jù)庫之前生成一個全局的唯一id,糾結(jié)全局唯一id怎么生成呢?下面小編給大家分享Java代碼實現(xiàn)游戲服務(wù)器生成全局唯一ID的方法匯總,涉及到優(yōu)劣勢方面的知識點,對此感興趣的朋友一起看看吧

在服務(wù)器系統(tǒng)開發(fā)時,為了適應(yīng)數(shù)據(jù)大并發(fā)的請求,我們往往需要對數(shù)據(jù)進行異步存儲,特別是在做分布式系統(tǒng)時,這個時候就不能等待插入數(shù)據(jù)庫返回了取自動id了,而是需要在插入數(shù)據(jù)庫之前生成一個全局的唯一id,使用全局的唯一id,在游戲服務(wù)器中,全局唯一的id可以用于將來合服方便,不會出現(xiàn)鍵沖突。也可以將來在業(yè)務(wù)增長的情況下,實現(xiàn)分庫分表,比如某一個用戶的物品要放在同一個分片內(nèi),而這個分片段可能是根據(jù)用戶id的范圍值來確定的,比如用戶id大于1000小于100000的用戶在一個分片內(nèi)。目前常用的有以下幾種:

1,Java 自帶的UUID.

UUID.randomUUID().toString(),可以通過服務(wù)程序本地產(chǎn)生,ID的生成不依賴數(shù)據(jù)庫的實現(xiàn)。

優(yōu)勢:

本地生成ID,不需要進行遠程調(diào)用。

全局唯一不重復(fù)。

水平擴展能力非常好。

劣勢:

ID有128 bits,占用的空間較大,需要存成字符串類型,索引效率極低。

生成的ID中沒有帶Timestamp,無法保證趨勢遞增,數(shù)據(jù)庫分庫分表時不好依賴

2,基于Redis的incr方法

Redis本身是單線程操作的,而incr更保證了一種原子遞增的操作。而且支持設(shè)置遞增步長。

優(yōu)勢:

部署方便,使用簡單,只需要調(diào)用一個redis的api即可。

可以多個服務(wù)器共享一個redis服務(wù),減少共享數(shù)據(jù)的開發(fā)時間。

Redis可以群集部署,解決單點故障的問題。

劣勢:

如果系統(tǒng)太龐大的話,n多個服務(wù)同時向redis請求,會造成性能瓶頸。

3,來自Flicker的解決方案

這個解決方法是基于數(shù)據(jù)庫自增id的,它使用一個單獨的數(shù)據(jù)庫專門用于生成id。詳細的大家可以網(wǎng)上找找,個人覺得使用挺麻煩的,不建議使用。

4,Twitter Snowflake

snowflake是twitter開源的分布式ID生成算法,其核心思想是:產(chǎn)生一個long型的ID,使用其中41bit作為毫秒數(shù),10bit作為機器編號,12bit作為毫秒內(nèi)序列號。這個算法單機每秒內(nèi)理論上最多可以生成1000*(2^12)個,也就是大約400W的ID,完全能滿足業(yè)務(wù)的需求。

根據(jù)snowflake算法的思想,我們可以根據(jù)自己的業(yè)務(wù)場景,產(chǎn)生自己的全局唯一ID。因為Java中l(wèi)ong類型的長度是64bits,所以我們設(shè)計的ID需要控制在64bits。

優(yōu)點:高性能,低延遲;獨立的應(yīng)用;按時間有序。

缺點:需要獨立的開發(fā)和部署。

比如我們設(shè)計的ID包含以下信息:

| 41 bits: Timestamp | 3 bits: 區(qū)域 | 10 bits: 機器編號 | 10 bits: 序列號 |

產(chǎn)生唯一ID的Java代碼:

/**
* 自定義 ID 生成器
* ID 生成規(guī)則: ID長達 64 bits
*
* | 41 bits: Timestamp (毫秒) | 3 bits: 區(qū)域(機房) | 10 bits: 機器編號 | 10 bits: 序列號 |
*/
public class GameUUID{
// 基準(zhǔn)時間
private long twepoch = 1288834974657L; //Thu, 04 Nov 2010 01:42:54 GMT
// 區(qū)域標(biāo)志位數(shù)
private final static long regionIdBits = 3L;
// 機器標(biāo)識位數(shù)
private final static long workerIdBits = 10L;
// 序列號識位數(shù)
private final static long sequenceBits = 10L;
// 區(qū)域標(biāo)志ID最大值
private final static long maxRegionId = -1L ^ (-1L << regionIdBits);
// 機器ID最大值
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 序列號ID最大值
private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
// 機器ID偏左移10位
private final static long workerIdShift = sequenceBits;
// 業(yè)務(wù)ID偏左移20位
private final static long regionIdShift = sequenceBits + workerIdBits;
// 時間毫秒左移23位
private final static long timestampLeftShift = sequenceBits + workerIdBits + regionIdBits;
private static long lastTimestamp = -1L;
private long sequence = 0L;
private final long workerId;
private final long regionId;
public GameUUID(long workerId, long regionId) {
// 如果超出范圍就拋出異常
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException("worker Id can't be greater than %d or less than 0");
}
if (regionId > maxRegionId || regionId < 0) {
throw new IllegalArgumentException("datacenter Id can't be greater than %d or less than 0");
}
this.workerId = workerId;
this.regionId = regionId;
}
public GameUUID(long workerId) {
// 如果超出范圍就拋出異常
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException("worker Id can't be greater than %d or less than 0");
}
this.workerId = workerId;
this.regionId = 0;
}
public long generate() {
return this.nextId(false, 0);
}
/**
* 實際產(chǎn)生代碼的
*
* @param isPadding
* @param busId
* @return
*/
private synchronized long nextId(boolean isPadding, long busId) {
long timestamp = timeGen();
long paddingnum = regionId;
if (isPadding) {
paddingnum = busId;
}
if (timestamp < lastTimestamp) {
try {
throw new Exception("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds");
} catch (Exception e) {
e.printStackTrace();
}
}
//如果上次生成時間和當(dāng)前時間相同,在同一毫秒內(nèi)
if (lastTimestamp == timestamp) {
//sequence自增,因為sequence只有10bit,所以和sequenceMask相與一下,去掉高位
sequence = (sequence + 1) & sequenceMask;
//判斷是否溢出,也就是每毫秒內(nèi)超過1024,當(dāng)為1024時,與sequenceMask相與,sequence就等于0
if (sequence == 0) {
//自旋等待到下一毫秒
timestamp = tailNextMillis(lastTimestamp);
}
} else {
// 如果和上次生成時間不同,重置sequence,就是下一毫秒開始,sequence計數(shù)重新從0開始累加,
// 為了保證尾數(shù)隨機性更大一些,最后一位設(shè)置一個隨機數(shù)
sequence = new SecureRandom().nextInt(10);
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) | (paddingnum << regionIdShift) | (workerId << workerIdShift) | sequence;
}
// 防止產(chǎn)生的時間比之前的時間還要小(由于NTP回撥等問題),保持增量的趨勢.
private long tailNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
// 獲取當(dāng)前的時間戳
protected long timeGen() {
return System.currentTimeMillis();
}
}

使用自定義的這種方法需要注意的幾點:

為了保持增長的趨勢,要避免有些服務(wù)器的時間早,有些服務(wù)器的時間晚,需要控制好所有服務(wù)器的時間,而且要避免NTP時間服務(wù)器回撥服務(wù)器的時間;在跨毫秒時,序列號總是歸0,會使得序列號為0的ID比較多,導(dǎo)致生成的ID取模后不均勻,所以序列號不是每次都歸0,而是歸一個0到9的隨機數(shù)。

上面說的這幾種方式我們可以根據(jù)自己的需要去選擇。在游戲服務(wù)器開發(fā)中,根據(jù)自己的游戲類型選擇,比如手機游戲,可以使用簡單的redis方式,簡單不容易出錯,由于這種游戲單服并發(fā)新建id量并不太大,完全可以滿足需要。而對于大型的世界游戲服務(wù)器,它本身就是以分布式為主的,所以可以使用snowflake的方式,上面的snowflake代碼只是一個例子,需要自己根據(jù)自己的需求去定制,所以有額外的開發(fā)量,而且要注意上述所說的注意事項。

以上所述是小編給大家介紹的基于Java代碼實現(xiàn)游戲服務(wù)器生成全局唯一ID的方法匯總,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java?SE使用for?each循環(huán)遍歷數(shù)組的方法代碼

    Java?SE使用for?each循環(huán)遍歷數(shù)組的方法代碼

    在Java?SE開發(fā)中,數(shù)組是最常見的數(shù)據(jù)結(jié)構(gòu)之一,Java提供了多種遍歷數(shù)組的方式,其中for循環(huán)是最常用的方式之一,本文將介紹如何使用for?each循環(huán)遍歷數(shù)組,接下來,我們將通過一個簡單的代碼示例來展示如何使用for?each循環(huán)遍歷數(shù)組,需要的朋友可以參考下
    2023-11-11
  • Java處理多API請求的方法詳解

    Java處理多API請求的方法詳解

    Java?中的并發(fā)是指語言并行運行多個線程的能力,允許同時執(zhí)行多個任務(wù),
    2023-10-10
  • Java使用正則表達式(regex)匹配中文實例代碼

    Java使用正則表達式(regex)匹配中文實例代碼

    本文給大家分享java使用正則表達式匹配中文的實例代碼,以及java中要匹配中文的正則表達式兩種寫法,感興趣的朋友通過本文一起看看吧
    2016-12-12
  • Java編程實現(xiàn)對象克?。◤?fù)制)代碼詳解

    Java編程實現(xiàn)對象克?。◤?fù)制)代碼詳解

    這篇文章主要介紹了Java編程實現(xiàn)對象克隆(復(fù)制)代碼詳解,涉及了克隆的原因,如何實現(xiàn)克隆,克隆的一般步驟,深克隆與淺克隆的介紹等相關(guān)內(nèi)容,具有一定借鑒價值,需要的朋友可以參考下。
    2017-11-11
  • 使用spring的websocket創(chuàng)建通信服務(wù)的示例代碼

    使用spring的websocket創(chuàng)建通信服務(wù)的示例代碼

    這篇文章主要介紹了使用spring的websocket創(chuàng)建通信服務(wù)的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • Intellij?IDEA根據(jù)maven依賴名查找它是哪個pom.xml引入的(圖文詳解)

    Intellij?IDEA根據(jù)maven依賴名查找它是哪個pom.xml引入的(圖文詳解)

    這篇文章主要介紹了Intellij?IDEA根據(jù)maven依賴名查找它是哪個pom.xml引入的,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-08-08
  • Spring測試基本的控制器實戰(zhàn)示例

    Spring測試基本的控制器實戰(zhàn)示例

    這篇文章主要為大家介紹了Spring測試基本的控制器實戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • 解決Maven項目本地公共common包緩存問題

    解決Maven項目本地公共common包緩存問題

    這篇文章主要介紹了解決Maven項目本地公共common包緩存問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • JAVA?String類中的一些常用方法示例詳解

    JAVA?String類中的一些常用方法示例詳解

    在我們的工作中,常常要對一個字符串進行一些操作,這里提供一些常用的方法,常常需要這些方法進行組合處理字符串,這篇文章主要給大家介紹了關(guān)于JAVA?String類中的一些常用方法,需要的朋友可以參考下
    2023-10-10
  • idea?http?request無法識別環(huán)境變量的解決步驟

    idea?http?request無法識別環(huán)境變量的解決步驟

    AlibabaCloudToolkit插件安裝后在?Editor->File?Types增加?AlibabaCloudROStemplates(JSON)項且會配置為解析*.json?文件,導(dǎo)致http?client無法正確解析http-client.env.json文件而無法讀取環(huán)境變量,本文介紹idea?http?request無法識別環(huán)境變量問題,需要的朋友可以參考下
    2023-08-08

最新評論