1. 程式人生 > >高併發下ID生成方案

高併發下ID生成方案

  1. 需求

    • 生成全域性唯一的ID
    • 趨近有序(例如:1 3 4 6 9 18)
  2. 解決方案(涉及到資料以MySql為例)

    • 方案一:使用原生資料庫的 auto_increment 來生成全域性唯一ID
      • 優點:
        • 原生資料庫簡單快捷
        • 保證可靠唯一性
        • 步長有序固定
      • 缺點:
        • 不能保證高可用性,資料庫常見的架構:一主多從(master+slave),本問題寫居多,master庫掛了就玩完了
        • 擴充套件性差,效能依賴master庫寫入的效能
      • 優化方案:
        • 新增master、避免單點寫入
        • 資料水平切分,保證每個庫生成的ID 不重複
        • 見下圖:
          這裡寫圖片描述
        • 1庫平行擴充套件為4個庫,分攤了寫入的壓力
        • Mysql 這邊需要自行設定auto_increment_offset 確定AUTO_INCREMENT列值的起點,也就是初始值。auto_increment_increment控制列中的值的增量值,也就是步長。
        • [email protected][kevin]> set session auto_increment_offset=1;
        • [email protected][kevin]> set session auto_increment_increment=4;
        • 不足之處:相對保持ID遞增,不過一般專案足矣
    • 方案二:單點生成ID服務,預生成id
      • 詳解:資料庫裡記錄最後一次分配的最大id,初始為max_id=1,假如第一生成 6個ID,第一步:generate-server 先獲取資料庫的max-id=0,第二步:然後更新 max_id=(0+6),generate-server 拿到初始max-id和本次拉取id個數生成ID,max_id < 生成ID集合 < (max_id+N)
      • 示意圖:
        這裡寫圖片描述
      • 單點服務+shadow 服務保證高可用性
      • 批量生成ID大大降低了資料庫壓力,且能保證ID 相對遞增
      • 每秒生成10W級的ID
    • 方案三:本地生成 ID策略,依賴演算法

      • 下面講解snowflake演算法,下面提供 PHP snowflake 的擴充套件
      • Twitter-Snowflake演算法產生的背景相當簡單,為了滿足Twitter每秒上萬條訊息的請求,每條訊息都必須分配一條唯一的id,這些id還需要一些大致的順序(方便客戶端排序),並且在分散式系統中不同機器產生的id必須不同。
      • Snowflake演算法核心,把時間戳,工作機器id,序列號組合在一起。
      • Snowflake演算法核心
      • 除了最高位bit標記為不可用以外,其餘三組bit佔位均可浮動,看具體的業務需求而定。預設情況下41bit的時間戳可以支援該演算法使用到2082年,10bit的工作機器id可以支援1023臺機器,序列號支援1毫秒產生4095個自增序列id。下文會具體分析。
      • Snowflake – 時間戳
        這裡時間戳的細度是毫秒級,具體程式碼如下,建議使用64位linux系統機器,因為有vdso,gettimeofday()在使用者態就可以完成操作,減少了進入核心態的損耗。

        uint64_t generateStamp()
        {
            timeval tv;
            gettimeofday(&tv, 0);
            return (uint64_t)tv.tv_sec * 1000 + (uint64_t)tv.tv_usec / 1000;
        }

        預設情況下有41個bit可以供使用,那麼一共有T(1llu << 41)毫秒供你使用分配,年份 = T / (3600 * 24 * 365 * 1000) = 69.7年。如果你只給時間戳分配39個bit使用,那麼根據同樣的演算法最後年份 = 17.4年。

      • Snowflake – 工作機器id
        嚴格意義上來說這個bit段的使用可以是程序級,機器級的話你可以使用MAC地址來唯一標示工作機器,工作程序級可以使用IP+Path來區分工作程序。如果工作機器比較少,可以使用配置檔案來設定這個id是一個不錯的選擇,如果機器過多配置檔案的維護是一個災難性的事情。
        這裡的解決方案是需要一個工作id分配的程序,可以使用自己編寫一個簡單程序來記錄分配id,或者利用Mysql auto_increment機制也可以達到效果。

      • snowflake - 工作id
        工作程序與工作id分配器只是在工作程序啟動的時候互動一次,然後工作程序可以自行將分配的id資料落檔案,下一次啟動直接讀取檔案裡的id使用。

        PS:這個工作機器id的bit段也可以進一步拆分,比如用前5個bit標記程序id,後5個bit標記執行緒id之類:D

      • Snowflake – 序列號
        序列號就是一系列的自增id(多執行緒建議使用atomic),為了處理在同一毫秒內需要給多條訊息分配id,若同一毫秒把序列號用完了,則“等待至下一毫秒”。

        
        uint64_t waitNextMs(uint64_t lastStamp)
        {
            uint64_t cur = 0;
            do {
                cur = generateStamp();
            } while (cur <= lastStamp);
            return cur;
        }

        總體來說,是一個很高效很方便的GUID產生演算法,一個int64_t欄位就可以勝任,不像現在主流128bit的GUID演算法,即使無法保證嚴格的id序列性,但是對於特定的業務,比如用做遊戲伺服器端的GUID產生會很方便。另外,在多執行緒的環境下,序列號使用atomic可以在程式碼實現上有效減少鎖的密度。

相關推薦

併發ID生成方案

需求 生成全域性唯一的ID 趨近有序(例如:1 3 4 6 9 18) 解決方案(涉及到資料以MySql為例) 方案一:使用原生資料庫的 auto_increment 來生成全域性唯一ID 優點

java併發-靜態頁面生成方案(3)

前面2章我們已經講解了 java網頁靜態化的原理和最簡單的實現,大家可以通過下面的文章連結進行檢視       java高併發-靜態頁面生成方案(1)如何讓使用者遵守訪問方式        在第二篇文章我們已經通過程式碼講解,使用者訪問 xx_pageNumber_1.sht

併發怎樣生成唯一的訂單號

方案一: 如果沒有併發,訂單號只在一個執行緒內產生,那麼由於程式是順序執行的,不同訂單的生成時間戳正常不同,因此用時間戳+隨機數(或自增數)就可以區分各個訂單。 如果存在併發,且訂單號是由一個程序中的多個執行緒產生的,那麼只要把執行緒ID新增到序列號中就可以保證訂單號唯一。

併發使用Redis生成唯一id

最近使用spirngcloud來搭建分散式專案,遇到插入重複問題,決定用redis生成唯一ID來解決。 /** * 獲取唯一Id * @param key *

java web系統在併發如何實現訂單號生成唯一?

java web系統在高併發下如何實現訂單號生成唯一? 系統訂單號規則:XXXX(固定字元)+年(後兩位)月日+流水號。流水號每天重新從1開始。 系統訂單號產生唯一的方案有哪幾種?由於訂單號規則已經確定,無法使用時間戳及隨機數,有哪些方案可以使用? 注:資料庫mysql,訂單號不是訂單表的主鍵

深入理解併發分散式事務的方案

編輯推薦: 本文主要從分散式的原因,事務特性,和解決方案中深入理解了分散式事務,希望對您的學習有所幫助。 1、什麼是分散式事務 分散式事務就是指事務的參與者、支援事務的伺服器、資源伺服器以及事務管理器分別位於不同的分散式系統的不同節點之上。以上是百度百科的解釋,

深入理解併發分散式事務的解決方案

1、什麼是分散式事務 分散式事務就是指事務的參與者、支援事務的伺服器、資源伺服器以及事務管理器分別位於不同的分散式系統的不同節點之上。以上是百度百科的解釋,簡單的說,就是一次大的操作由不同的小操作組成,這些小的操作分佈在不同的伺服器上,且屬於不同的應用,分散式事務需要保證這

深入理解分散式事務,併發分散式事務的解決方案

1、什麼是分散式事務 分散式事務就是指事務的參與者、支援事務的伺服器、資源伺服器以及事務管理器分別位於不同的分散式系統的不同節點之上。以上是百度百科的解釋,簡單的說,就是一次大的操作由不同的小操作組成,這些小的操作分佈在不同的伺服器上,且屬於不同的應用,分散式事務需要保證這

併發生成自定義規則的訂單號

目錄 背景 規則 問題 分析 思路 資料庫 執行緒鎖 方案 討論 背景 半年以前做的一個流程相關的專案,近期在做效能測試;之前的功能測試已經做完了,都沒有什麼問題。    專案採用的springmvc框架,生成訂單號以及儲存訂單號都是在activ

關於tomcat8在windows2008併發問題的解決方案

因為客戶伺服器特殊的環境問題,只能使用windows2008r2伺服器,然而配置過後,網站的高訪問量很快就出現了各種問題,以下是解決的問題彙總。 伺服器環境:windows2008R2+jdk8.0+tomcat8.0.21+sqlserver2008r2(以上軟體環境均是

redis學習系列--Redis 併發的,快取穿透問題解決方案

下面這段程式碼 如果1W個人同時訪問的話,  從redis 拿 allUser 時, userList為空時,那麼1W個人都要進入if判斷語句,查詢資料庫,資料庫壓力承受不住 package com.

MySQL分庫分表環境全域性ID生成方案

摘要 介紹來自flicker和twitter的兩種解決分散式環境下全域性ID生成方案。 在大型網際網路應用中,隨著使用者數的增加,為了提高應用的效能,我們經常需要對資料庫進行分庫分表操作。在單表時代,我們可以完全依賴於資料庫的自增ID來唯一標識一個使用者或資料物件。但是

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

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

併發的訂單與庫存的處理

問題:一件商品只有100個庫存,現在有1000或者更多的使用者來購買,每個使用者計劃同時購買1個到幾個不等商品。如何保證庫存在高併發的場景下是安全的。 1.不多發 2.不少發 下單涉及的一些步驟 1.下單 2.下單同時預佔庫存 3.支付 4.支付成功真正減扣庫存 5.取消訂

HttpClient併發效能優化-http連線池

首先,明確兩點: 1.http連線池不是萬能的,過多的長連線會佔用伺服器資源,導致其他服務受阻 2.http連線池只適用於請求是經常訪問同一主機(或同一個介面)的情況下 3.併發數不高的情況下資源利用率低下 那麼,當你的業務符合上面3點,那麼你可以考慮使用http連線池來提高伺服器效能

spring cache redis 併發返回null

在使用springdata操作快取中,當訪問量比較大時,有可能返回null導致資料不準確,發生機率在0.01%或以下,雖然已經低於壓測標準,但是還是會影響部分使用者,經過一番篩查,發現原因如下: RedisCache 類中 有get方法,存在明顯的邏輯錯誤 “先判斷是否存在,再去get”,程

併發量網站解決方案、效能優化

一個小型的網站,可以使用最簡單的html靜態頁面就實現了,配合一些圖片達到美化效果,所有的頁面均存放在一個目錄下,這樣的網站對系統架構、效能的要求都很簡單。隨著網際網路業務的不斷豐富,網站相關的技術經過這些年的發展,已經細分到很細的方方面面,尤其對於大型網站來說,所採用的技術更是涉及面非常廣,從硬體

分析一個在併發的財務支付鎖的問題

在工作專案中,會遇到一些php併發訪問去修改一個數據問題,如果這個資料不加鎖,就會造成資料的錯誤。下面將分析一個財務支付鎖的問題。希望對大家有所幫助。   1,在沒有應用鎖機制的情況下 1.1 財務支付簡化版本程式碼 <!--?php  /** 

併發防止商品超賣的Redis實現

@RestController @RequestMapping("/rushbuy") @Slf4j public class RushbuyController { @Autowired private RedisTemplate redisTemplate; //釋出

MySQL 在併發的 訂單撮合 系統使用 共享鎖 與 排他鎖 保證資料一致性

作者:林冠巨集 / 指尖下的幽靈 掘金:juejin.im/user/587f0d… 部落格:www.cnblogs.com/linguanh/ GitHub : github.com/af913337456… 騰訊雲專欄: cloud.tencent.c