<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          搞定了 6 種分布式ID,分庫分表哪個適合做主鍵?

          共 20181字,需瀏覽 41分鐘

           ·

          2024-04-18 08:40

          大家好,我是小富~


          本文是《ShardingSphere5.x分庫分表原理與實戰(zhàn)》系列的第篇,目前系列的前幾篇制作成了PDF,需要的可以在文末獲取下載方式,持續(xù)更新中。

          今天咱們繼續(xù)一起來探究下,分布式ID在分庫分表中起到的作用以及如何使用,ShardingSphere-jdbc中已經(jīng)為我們提供了多種分布式主鍵ID生成策略。接下來將分別介紹這些策略的優(yōu)缺點,看看它們在實際應(yīng)用中的場景和效果。

          小富技術(shù)站:https://xiaofucode.com

          為什么用分布式主鍵ID

          在傳統(tǒng)的單庫單表結(jié)構(gòu)時,通常可以使用自增主鍵來保證數(shù)據(jù)的唯一性。但在分庫分表的情況下,每個表的默認自增步長為1,這導(dǎo)致了各個庫、表之間可能存在重疊的主鍵范圍,從而使得主鍵字段失去了其唯一性的意義。

          為了解決這一問題,我們需要引入專門的分布式 ID 生成器來生成全局唯一的ID,并將其作為每條記錄的主鍵,以確保全局唯一性。通過這種方式,我們能夠有效地避免數(shù)據(jù)沖突和重復(fù)插入的問題,從而保障系統(tǒng)的正常運行。

          除了滿足唯一性的基本要求外,作為主鍵 ID,我們還需要關(guān)注主鍵字段的數(shù)據(jù)類型、長度對性能的影響。因為主鍵字段的數(shù)據(jù)類型長度直接影響著數(shù)據(jù)庫的查詢效率和整體系統(tǒng)性能表現(xiàn),這一點也是我們在選方案時需要考慮的因素。

          內(nèi)置算法

          ShardingSphere 5.X版本后進一步豐富了其框架內(nèi)部的主鍵生成策略方案。此前僅提供了UUIDSnowflake兩種策略,現(xiàn)在又陸續(xù)提供了NanoIDCosIdCosId-Snowflake三種策略。下面我們將逐個的過一下。

          注意SQL中不要主動拼接主鍵字段(包括持久化工具自動拼接的)否則一律走默認的Snowflake策略!!!

          ShardingSphere中為分片表設(shè)置主鍵生成策略后,執(zhí)行插入操作時,會自動在SQL中拼接配置的主鍵字段和生成的分布式ID值。所以,在創(chuàng)建分片表時主鍵字段無需再設(shè)置 自增 AUTO_INCREMENT。同時,在插入數(shù)據(jù)時應(yīng)避免為主鍵字段賦值,否則會覆蓋主鍵策略生成的ID。

          CREATE TABLE `t_order` (
            `id` bigint NOT NULL,
            `order_id` bigint NOT NULL,
            `user_id` bigint NOT NULL,
            `order_number` varchar(255COLLATE utf8mb4_general_ci NOT NULL,
            `customer_id` bigint NOT NULL,
            `order_date` datetime DEFAULT NULL,
            `interval_value` varchar(125COLLATE utf8mb4_general_ci DEFAULT NULL,
            `total_amount` decimal(10,2NOT NULL,
            PRIMARY KEY (`order_id`) USING BTREE
          ) ;

          UUID

          想要獲得一個具有唯一性的ID,大概率會先想到UUID,因為它不僅具有全球唯一的特性使用還簡單。但并不推薦將其作為主鍵ID。

          • ? UUID的無序性。在插入新行數(shù)據(jù)后,InnoDB無法像插入有序數(shù)據(jù)那樣直接將新行追加到表尾,而是需要為新行尋找合適的位置來分配空間。由于ID無序,頁分裂操作變得不可避免,導(dǎo)致大量數(shù)據(jù)的移動。頻繁的頁分裂會導(dǎo)致數(shù)據(jù)碎片化(即數(shù)據(jù)在物理存儲上分散分布)。這種隨機的ID分配過程需要大量的額外操作,導(dǎo)致頻繁的對數(shù)據(jù)進行無序的訪問,導(dǎo)致磁盤尋道時間增加。數(shù)據(jù)的無序性進一步加劇了數(shù)據(jù)碎片化,降低了數(shù)據(jù)訪問效率。

          • ? UUID字符串類型。字符串比數(shù)字類型占用更多的存儲空間,對存儲和查詢性能造成較大的消耗;字符串類型的長度可變,可變長度的數(shù)據(jù)行會破壞索引的連續(xù)性,導(dǎo)致索引查找性能下降。

          算法類型:UUID

          spring:
            shardingsphere:
              rules:
                sharding:
                  key-generators:  # 分布式序列算法配置
                    # UUID生成算法
                    uu-id-gen:
                      type: UUID
                  tables:
                    t_order:  # 邏輯表名稱
                      actual-data-nodes: db$->{0..1}.t_order_${0..2} # 數(shù)據(jù)節(jié)點:數(shù)據(jù)庫.分片表
                      database-strategy:  # 分庫策略
                        standard:
                          sharding-column: order_id
                          sharding-algorithm-name: t_order_database_mod
                      table-strategy: # 分表策略
                        standard:
                          sharding-column: order_id
                          sharding-algorithm-name: t_order_table_mod
                      key-generate-strategy: # 分布式主鍵生成策略
                        column: id
                        keyGeneratorName: uu-id-gen

          NanoID

          或許很多人都不熟悉 NanoID,它是一款用類似 UUID 生成唯一標識符的輕量級庫。不過,與 UUID 不同的是 NanoID 生成的字符串ID長度較短,僅為21位。但仍然不推薦將它作為主鍵ID,理由和UUID一樣。

          算法類型:NANOID

          spring:
            shardingsphere:
              rules:
                sharding:
                  key-generators:  # 分布式序列算法配置
                    # nanoid生成算法
                    nanoid-gen:
                      type: NANOID
                  tables:
                    t_order:  # 邏輯表名稱
                      actual-data-nodes: db$->{0..1}.t_order_${0..2} # 數(shù)據(jù)節(jié)點:數(shù)據(jù)庫.分片表
                      key-generate-strategy: # 分布式主鍵生成策略
                        column: id
                        keyGeneratorName: nanoid-gen

          定制雪花算法

          雪花算法是比較主流的分布式ID生成方案,在 ShardingSphere 中的Snowflake算法生成的是 Long 類型的 ID,通常作為默認的主鍵生成策略使用。

          內(nèi)置的雪花算法生成的ID主要由時間戳、工作機器IDworkId、序列號sequence三部分組成。

          @Override
            public synchronized Long generateKey() {
                ..........
                return ((currentMilliseconds - EPOCH) << TIMESTAMP_LEFT_SHIFT_BITS) | (getWorkerId() << WORKER_ID_LEFT_SHIFT_BITS) | sequence;
            }

          定制 Snowflake 算法有三個可配置的屬性:

          worker-id:工作機器唯一標識,單機模式下會直接取此屬性值計算ID,默認是0;集群模式下則由系統(tǒng)自動生成,此屬性無效

          max-vibration-offset:最大抖動上限值,范圍[0, 4096),默認是1。那么如何理解這個屬性呢?這個屬性是用來控制上邊生成雪花ID中的sequence。通過限制抖動范圍,同一毫秒內(nèi)生成的ID中引入微小的變化,讓數(shù)據(jù)更均勻地分散到不同的分片上。

          private void vibrateSequenceOffset() {
              sequenceOffset = sequenceOffset >= maxVibrationOffset ? 0 : sequenceOffset + 1;
          }

          若使用此算法生成值作分片值,建議配置此屬性。此算法在不同毫秒內(nèi)所生成的 key 取模 2^n (2^n一般為分庫或分表數(shù)) 之后結(jié)果總為 0 或 1。為防止上述分片問題,建議將此屬性值配置為 (2^n)-1

          max-tolerate-time-difference-milliseconds:最大容忍時鐘回退時間(毫秒)。服務(wù)器在校對時間時可能會發(fā)生時鐘回撥的情況(當前時間回退),由于根據(jù)時間戳參與計算ID,這可能導(dǎo)致生成相同的ID,而這對系統(tǒng)來說是不可接受的。

          ShardingSphere 雪花算法針對時鐘回撥場景進行了處理,記錄最后一次生成ID的時間 lastMilliseconds,并與回撥后的當前時間 currentMilliseconds 進行比對。如果時間差超過了設(shè)置的最大容忍時鐘回退時間,系統(tǒng)將直接拋出異常;如果未超過,則系統(tǒng)會休眠等待兩者時間差的時長,核心原則確保不會發(fā)放重復(fù)的ID

          @SneakyThrows(InterruptedException.class)
          private boolean waitTolerateTimeDifferenceIfNeed(final long currentMilliseconds) {
              if (lastMilliseconds <= currentMilliseconds) {
                  return false;
              }
              long timeDifferenceMilliseconds = lastMilliseconds - currentMilliseconds;
              Preconditions.checkState(timeDifferenceMilliseconds < maxTolerateTimeDifferenceMilliseconds,
                      "Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds", lastMilliseconds, currentMilliseconds);
              Thread.sleep(timeDifferenceMilliseconds);
              return true;
          }

          算法類型:SNOWFLAKE

          spring:
            shardingsphere:
              rules:
                sharding:
                  key-generators:  # 分布式序列算法配置
                    # 雪花ID生成算法
                    snowflake-gen:
                      type: SNOWFLAKE
                      props:
                        worker-id: # 工作機器唯一標識
                        max-vibration-offset: 1024 # 最大抖動上限值,范圍[0, 4096)。注:若使用此算法生成值作分片值,建議配置此屬性。此算法在不同毫秒內(nèi)所生成的 key 取模 2^n (2^n一般為分庫或分表數(shù)) 之后結(jié)果總為 0 或 1。為防止上述分片問題,建議將此屬性值配置為 (2^n)-1
                        max-tolerate-time-difference-milliseconds: 10 # 最大容忍時鐘回退時間,單位:毫秒
                  tables:
                    t_order:  # 邏輯表名稱
                      actual-data-nodes: db$->{0..1}.t_order_${0..2} # 數(shù)據(jù)節(jié)點:數(shù)據(jù)庫.分片表
                      key-generate-strategy: # 分布式主鍵生成策略
                        column: id
                        keyGeneratorName: snowflake-gen

          CosId

          CosId 是一個高性能的分布式ID生成器框架,Shardingsphere 將其引入到自身的框架內(nèi),只簡單的使用了 CosId 算法。但目前親測 5.2.0版本該算法處于不可用狀態(tài)!!!我已經(jīng)給官方提了issue,看看他們咋回復(fù)吧

          CosId 框架內(nèi)提供了 3 種算法:

          • SnowflakeId: 單機 TPS 性能:409W/s , 主要解決時鐘回撥問題 、機器號分配問題并且提供更加友好、靈活的使用體驗。

          • SegmentId: 每次獲取一段 (Step) ID,來降低號段分發(fā)器的網(wǎng)絡(luò)IO請求頻次提升性能,提供多種存儲后端:關(guān)系型數(shù)據(jù)庫、Redis、Zookeeper 供用戶選擇。

          • SegmentChainId(推薦): SegmentChainId (lock-free) 是對 SegmentId 的增強。性能可達到近似 AtomicLong 的 TPS 性能 12743W+/s。

          該算法使用對外提供了兩個屬性:

          • id-name:ID 生成器名稱。

          • as-string:是否生成字符串類型ID,將 long 類型 ID 轉(zhuǎn)換成 62 進制 String 類型(Long.MAX_VALUE 最大字符串長度11位),并保證字符串 ID 有序性。

          算法類型:COSID

          spring:
            shardingsphere:
              rules:
                sharding:
                  key-generators:  # 分布式序列算法配置
                    # COSID生成算法
                    cosId-gen:
                      type: COSID
                      props:
                        id-name: share
                        as-string: false
                  tables:
                    t_order:  # 邏輯表名稱
                      actual-data-nodes: db$->{0..1}.t_order_${0..2} # 數(shù)據(jù)節(jié)點:數(shù)據(jù)庫.分片表
                      key-generate-strategy: # 分布式主鍵生成策略
                        column: id
                        keyGeneratorName: cosId-gen

          CosId-Snowflake

          CosId-Snowflake 是 CosId 框架內(nèi)提供的 Snowflake 算法,它的實現(xiàn)原理和上邊的定制版雪花算法類似,ID主要也是由時間戳、工作機器ID、序列號sequence三部分組成。同樣處理了時鐘回撥等問題。

          public synchronized long generate() {
              long currentTimestamp = this.getCurrentTime();
              if (currentTimestamp < this.lastTimestamp) {
                  throw new ClockBackwardsException(this.lastTimestamp, currentTimestamp);
              } else {
                  if (currentTimestamp > this.lastTimestamp && this.sequence >= this.sequenceResetThreshold) {
                      this.sequence = 0L;
                  }

                  this.sequence = this.sequence + 1L & this.maxSequence;
                  if (this.sequence == 0L) {
                      currentTimestamp = this.nextTime();
                  }

                  this.lastTimestamp = currentTimestamp;
                  long diffTimestamp = currentTimestamp - this.epoch;
                  if (diffTimestamp > this.maxTimestamp) {
                      throw new TimestampOverflowException(this.epoch, diffTimestamp, this.maxTimestamp);
                  } else {
                      return diffTimestamp << (int)this.timestampLeft | this.machineId << (int)this.machineLeft | this.sequence;
                  }
              }
          }

          這個算法提供了兩個屬性:

          • epoch:固定的起始時間點,雪花ID算法的 epoch 變量值,默認值:1477929600000。用它的目的提高生成的ID的時間戳部分的可讀性、穩(wěn)定性和范圍限制,使得生成的ID更加可靠和易于管理。

          • as-string:是否生成字符串類型ID,將 long 類型 ID 轉(zhuǎn)換成 62 進制 String 類型(Long.MAX_VALUE 最大字符串長度11位),并保證字符串 ID 有序性。

          算法類型:COSID_SNOWFLAKE

          spring:
            shardingsphere:
              rules:
                sharding:
                  key-generators:  # 分布式序列算法配置
                    # cosId-snowflake生成算法
                    cosId-snowflake-gen:
                      type: COSID_SNOWFLAKE
                      props:
                        epoch: 1477929600000
                        as-string: false
                  tables:
                    t_order:  # 邏輯表名稱
                      actual-data-nodes: db$->{0..1}.t_order_${0..2} # 數(shù)據(jù)節(jié)點:數(shù)據(jù)庫.分片表
                      key-generate-strategy: # 分布式主鍵生成策略
                        column: id
                        keyGeneratorName: cosId-snowflake-gen

          自定義分布式主鍵

          上邊咱們介紹了 ShardingSphere 內(nèi)提供的 5 種生成主鍵的ID算法,這些算法基本可以滿足大部分的業(yè)務(wù)場景。不過,在某些情況下,我們可能會要求生成的ID具有特殊的含義或遵循特定的規(guī)則。ShardingSphere 也支持我們自定義生成主鍵ID,來滿足定制的業(yè)務(wù)需求。

          實現(xiàn)接口

          要實現(xiàn)自定義的主鍵生成算法,首先需要實現(xiàn) KeyGenerateAlgorithm 接口,并實現(xiàn)內(nèi)部 4 個方法, 其中有兩個方法比較關(guān)鍵:

          • getType():我們自定義的算法類型,方便配置使用;

          • generateKey():處理主鍵生成的核心邏輯,我們可以根據(jù)業(yè)務(wù)需求選擇合適的主鍵生成算法,比如美團的 Leaf、滴滴的 TinyId 等。

          @Data
          @Slf4j
          public class SequenceAlgorithms implements KeyGenerateAlgorithm {

              // 這個方法用于指定我們自定義的算法的類型。它會返回一個字符串,表示所使用算法的類型,方便在配置和識別時使用。
              @Override
              public String getType() {
                  // 返回算法類型表示
                  return "custom";
              }

              // 這是生成主鍵的核心邏輯所在。在這個方法內(nèi)部,我們可以根據(jù)業(yè)務(wù)需求選擇合適的主鍵生成算法,比如美團的Leaf、滴滴的TinyId等。這個方法的具體實現(xiàn)會根據(jù)所選算法的特點和要求來設(shè)計
              @Override
              public Comparable<?> generateKey() {
                  return null;
              }

              @Override
              public Properties getProps() {
                  return null;
              }
              // 這個方法用于初始化主鍵生成算法所需的資源或配置
              @Override
              public void init(Properties properties) {
              }
          }

          在引入外部的分布式ID生成器時,應(yīng)盡量遵循以下原則:

          • 全局唯一:必須保證ID是全局性唯一的,基本要求

          • 高性能:高可用低延時,ID生成響應(yīng)要塊,否則反倒會成為業(yè)務(wù)瓶頸

          • 高可用:100%的可用性是騙人的,但是也要無限接近于100%的可用性

          • 好接入:要秉著拿來即用的設(shè)計原則,在系統(tǒng)設(shè)計和實現(xiàn)上要盡可能的簡單

          SPI 注冊

          通過 SPI 方式加載我們自定義的主鍵算法,需要在 resource/META-INF/services 目錄下創(chuàng)建一個文件,文件名為 org.apache.shardingsphere.sharding.spi.KeyGenerateAlgorithm,并將我們自定義的主鍵算法的完整類路徑放入文件內(nèi),每行一個。在系統(tǒng)啟動時會自動加載到這個文件,讀取其中的類路徑,然后通過反射機制實例化對應(yīng)的類,完成主鍵算法的注冊和加載。

          resource
              |_META-INF
                  |_services
                     |_org.apache.shardingsphere.sharding.spi.KeyGenerateAlgorithm

          配置使用

          上邊完成了自定義算法的邏輯,使用上與其他的算法一致。只需將我們剛剛定義的算法類型 custom 配置上即可。

          spring:
            shardingsphere:
              rules:
                sharding:
                  key-generators:  # 分布式序列算法配置
                    # 自定義ID生成策略
                    xiaofu-id-gen:
                      type: custom
                  tables:
                    t_order:  # 邏輯表名稱
                      actual-data-nodes: db$->{0..1}.t_order_${0..2} # 數(shù)據(jù)節(jié)點:數(shù)據(jù)庫.分片表
                      key-generate-strategy: # 分布式主鍵生成策略
                        column: id
                        keyGeneratorName: xiaofu-id-gen

          當執(zhí)行插入操作時,debug 看已經(jīng)進入到了定義的主鍵算法內(nèi)了。

          總結(jié)

          我們介紹了 ShardingSphere 的幾種內(nèi)置主鍵生成策略以及如何自定義主鍵生成策略,市面上還有許多優(yōu)秀的分布式ID框架都可以整合進來,但具體選擇何種策略還是要取決于自身的業(yè)務(wù)需求。關(guān)于分布式 ID 生成器,我曾經(jīng)撰寫過一篇 一口氣說出 9種 分布式ID生成方式,詳細介紹了多種生成器的優(yōu)缺點,大家可以作為參考。

          案例GitHub地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/shardingsphere101/shardingsphere-sequence-algorithm

          分庫分表系列往期推薦:





          1、好好的系統(tǒng),為什么要分庫分表?


          2、分庫分表的 21 條法則,hold 住!


          3、SpringBoot 2 種方式快速實現(xiàn)分庫分表,輕松拿捏!


          4、分庫分表如何管理不同實例中幾萬張分片表?


          5、一口氣搞懂分庫分表 12 種分片算法,大廠都在用

          我是小富~ 下期見!

          ··········  END  ··············


                    
          在看點贊轉(zhuǎn)發(fā),是對我最大的鼓勵

          《ShardingSphere5.x分庫分表原理與實戰(zhàn)》PDF公眾號內(nèi)回復(fù)[ 分庫分表 ] Get


          技術(shù)書籍公眾號內(nèi)回復(fù)[ pdf ] Get


          面試筆記、springcloud進階實戰(zhàn)PDF,公眾號內(nèi)回復(fù)[ 1222 ] Get


          瀏覽 158
          10點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          10點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中国色情一级视频 | 欧美黄色成人 | 超碰97色 | 黄片视频软件下载 | 91无码人妻精品一区二区三区四 |