1. 基于號段模式的分布式ID設計

        共 2499字,需瀏覽 5分鐘

         ·

        2022-07-17 06:17

        這里介紹基于號段模式的分布式ID設計思路、方案

        abstract.png

        背景

        對于分布式ID生成方案,很樸素的思路就是利用DB的自增主鍵進行實現(xiàn)。但其存在明顯的弊端。業(yè)務系統(tǒng)每次獲取ID都需要請求、訪問數(shù)據(jù)庫。數(shù)據(jù)庫壓力較大。如果這里的數(shù)據(jù)庫是單機,則容易發(fā)展成為整個系統(tǒng)的單點故障。一旦該DB宕機,則整個業(yè)務系統(tǒng)都將無法正常繼續(xù)

        而如果這里的數(shù)據(jù)庫是采用集群的形式。比如這里有兩個DB——#1實例、#2實例。其中,#1實例自增ID的起始值、步長分別為1、2;#2實例自增ID的起始值、步長分別為2、2。則#1實例生成的ID序列則是1、3、5、7、···,#2實例生成的ID序列則是2、4、6、8、···。然后再提供一個發(fā)號服務來對外提供服務即可。業(yè)務系統(tǒng)只需請求發(fā)號服務獲取ID,而發(fā)號服務內部則會隨機選取一個數(shù)據(jù)庫實例來獲取相應的數(shù)據(jù)庫自增ID。雖然采用集群的方式進一步地提高了系統(tǒng)的可用性、解決了單點故障。但缺陷依然很明顯,拓展性非常差。目前DB集群中存在2臺實例,如果后期再增加1臺變成含3個實例的集群。此時,我們需要人工手動修改原#1、#2實例的步長。而且還需要將#3實例的起始值設置的足夠長,以避免發(fā)生ID重復的問題。甚至說在整個過程中,發(fā)號服務需要對外停止服務才能完成擴容

        號段模式

        所謂號段模式,則是指發(fā)號服務每次會從數(shù)據(jù)庫獲取一批ID,然后將這批ID緩存到發(fā)號服務本地。業(yè)務系統(tǒng)每次向發(fā)號服務請求ID時,后者會先判斷其本地是否還有可用的ID分配給業(yè)務系統(tǒng)。如果有則直接分配,反之則再次訪問數(shù)據(jù)庫來批量獲取ID。顯然在號段模式下,由于發(fā)號服務不用每次都請求數(shù)據(jù)庫。一方面減輕了數(shù)據(jù)庫的壓力,另一方面提高了系統(tǒng)的可用性、可靠性。同時,后續(xù)由于業(yè)務拓展、業(yè)務系統(tǒng)激增時,對基于號段模式的設計方案進行分庫分表也非常便于實現(xiàn)

        具體地,當發(fā)號服務請求數(shù)據(jù)庫時,即會獲取一個號段范圍內的ID,例如[1,2000]號段表示1~2000的ID。發(fā)號服務會把這2000個ID緩存到本地。直到該業(yè)務第2001次向發(fā)號服務請求ID時,由于發(fā)號服務對于該業(yè)務的本地ID都已經被使用完畢了。故其會再次請求數(shù)據(jù)庫,獲取下一個號段范圍的ID——即[2001,4000]號段

        號段模式下的數(shù)據(jù)表,典型設計如下所示。其中

        • service_name:用于實現(xiàn)服務隔離
        • business_name:用于實現(xiàn)服務下不同業(yè)務場景的隔離
        • current_max_id:則表示該業(yè)務當前已經分配了的最大ID值
        • step:表示發(fā)號服務每次批量獲取ID的數(shù)量。換言之,每次更新數(shù)據(jù)庫current_max_id的增量值即是step值
        • version:樂觀鎖,保證并發(fā)場景下的可靠性
        -- 基于號段模式的分布式ID數(shù)據(jù)表
        create table common_sequence (
          `id` bigint(40NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
          `service_name` varchar(255DEFAULT NULL COMMENT '服務名稱',
          `business_name` varchar(255NOT NULL COMMENT '服務的業(yè)務名稱',
          `current_max_id` bigint(40NOT NULL COMMENT '當前最大ID值',
          `step` int(4NOT NULL COMMENT '步長',
          `version` int(4NOT NULL COMMENT '版本號',
          `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
          `modify_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
          primary key (`id`)
        comment = '分布式ID數(shù)據(jù)表';

        發(fā)號服務每次請求數(shù)據(jù)庫獲取號段時的SQL語句大體如下所示

        # 發(fā)號服務獲取號段時執(zhí)行的SQL
        update common_sequence
        set current_max_id = current_max_id + step,
            version = version + 1
        where service_name = #{service_name}
            and business_name= #{business_name}
            and version = #{version}    


        瀏覽 65
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
          
          

            1. 一级A片AAAAAAAXXXX | 成 人 网 站 在 线 视 频不 | 黄色仓库 | A级片黄色片 | 一区二区人妻 |