重構 分布式ID設計方案

2021-08-21 17:31:43 字數 4562 閱讀 4155

分布式id的生成方案有很多種,在網上都可以搜到。在這裡詳細介紹一下我們目前專案所用到的實際方案。

一. id值獲取及表結構設計

(1)獲取id值的介面

獲取唯一id的介面方法是由我們乙個基礎功能微服務提供,url如下:

:/sequence/getsequence 

請求引數為:string prefix(id值的型別,一種型別對應id值的乙個字首,比如test_no對應id字首no,只是起乙個對應關係)

eg:入參prefix=test_no,返回新id:no2018073000000054

入參prefix=req_my,返回新id:my2018073000000054

(2)id值組成

比如:no20180730

00000054

最前面的no為設定的id字首,緊接著是生成的年月日(20180730, 共8位),最後幾位是遞增的數值(總長度為下表定義的seq_len值)。具體看下面二中的test_currval儲存過程的實現。

(3)表結構分析

涉及的表就一張,結構如下:

create table `id_sequence` (

`name` varchar(50) collate utf8mb4_bin not null,

`current_value` int(11) not null,

`increment` int(11) not null default '5',

`cur_date` date default null,

`default_value` int(11) default null,

`seq_len` int(8) default null,

`prefix` varchar(10) collate utf8mb4_bin default null,

primary key (`name`)

) engine=innodb default charset=utf8mb4 collate=utf8mb4_bin;

其中,

name:分配器名字,表示有多個用於分配id值的分配器;

current_value:當前id值取的值;

increment:固定步長,這裡是5;

cur_date:當前日期,用於id值的中間幾位;

default_value:剛插入資料時的預設初始值;

seq_len:id值最後遞增位數的長度;

prefix:id值的字首;

(4)往該表預插入資料

insert into `id_sequence` (`name`, `current_value`, `increment`, `cur_date`, `default_value`, `seq_len`, `prefix`) values ('test_no_0', 1, 5, '2018-07-24', 1, 8, 'no');

insert into `id_sequence` (`name`, `current_value`, `increment`, `cur_date`, `default_value`, `seq_len`, `prefix`) values ('test_no_1', 2, 5, '2018-07-24', 2, 8, 'no');

insert into `id_sequence` (`name`, `current_value`, `increment`, `cur_date`, `default_value`, `seq_len`, `prefix`) values ('test_no_2', 3, 5, '2018-07-24', 3, 8, 'no');

insert into `id_sequence` (`name`, `current_value`, `increment`, `cur_date`, `default_value`, `seq_len`, `prefix`) values ('test_no_3', 4, 5, '2018-07-24', 4, 8, 'no');

insert into `id_sequence` (`name`, `current_value`, `increment`, `cur_date`, `default_value`, `seq_len`, `prefix`) values ('test_no_4', 5, 5, '2018-07-24', 5, 8, 'no');

表資料:

name

current_value

increment

cur_date

default_value

seq_len

prefix

test_no_015

2018-07-2418

notest_no_125

2018-07-2428

notest_no_235

2018-07-2438

notest_no_345

2018-07-2448

notest_no_455

2018-07-2458

no可以看出,這裡採用的方案是根據不同節點固定步長的方式。

(5)現通過(1)的介面新增乙個id:no2018072400000008,此時表資料變成:

name

current_value

increment

cur_date

default_value

seq_len

prefix

test_no_015

2018-07-2418

notest_no_125

2018-07-2428

notest_no_285

2018-07-2438

notest_no_345

2018-07-2448

notest_no_455

2018-07-2458

no可以看到,只有test_no_2的current_value由3變成了8(因為步長increment為5),而取test_no_2這條數是隨機的。

二. 介面實現

獲取id介面的實現,其實就是呼叫test_nextval儲存過程來獲取乙個新id。

首先看:

1. test_nextval

begin

declare seqname varchar(64);

set @seqname=concat(seq_name,"_",round(rand()*4));

update id_sequence set current_value = if (cur_date=current_date,current_value + increment,defult_value),cur_date=current_date where name = @seqname; 

return test_currval(@seqname);  

end可以看出,

(1)test_nextval的入參是seq_name,這裡傳的是「test_no」。而seqname=concat(seq_name,"_",round(rand()*4))的作用是根據seq_name和隨機生成(0-4)的數拼接成name值,這個作為後面更新的name條件值,此時就確定了要獲取哪條資料(test_no_0到test_no_4中一條)的值。

(2)而update語句則是判斷cur_date是不是當前日期(current_date是mysql函式),如果是,則current_value取當前值加上步長(increment=5,這樣保證當天取的id值都是從當前值進行遞增),如果不是,則current_value取預設值(default_value,也即初始值,這樣保證新一天取的id值都是從初始值開始遞增)。

(3)將seqname作為引數傳入test_currval儲存過程裡。

2. test_currval

begin

declare retval varchar(64);

set retval="-999999999";

select  concat(prefix,date_format(current_date,'%y%m%d'),lpad(cast(current_value as char),seq_len,0)) into retval  from id_sequence  where name = seq_name;  

return retval; 

end在這裡,

(1)定義乙個varchar(64)的retval值,預設值是-999999999,只有出錯情況下才返回該值。

(2)concat處就定義了id值是怎麼組成的:

字首prefix(這裡是no) +年月日(date_format(current_date,'%y%m%d')) +seq_len長度的遞增數字lpad是mysql填充字串函式,總長為seq_len=8,不夠長度8時,左邊以0補充;而cast是mysql轉換函式,將current_value轉為char型別)

面試刷題31 分布式ID設計方案

面試中關於分布式的問題很多。分布式事務,基本理論cap,base,分布式鎖 先來乙個簡單的。簡單說一下分布式id的設計方案?首先要明確在分布式環境下,分布式id的基本要求。1,全域性唯一,在分布式集群下,不同的節點並發生成的分布式id要唯一 2,順序性,分布式id是有序生成 然後給出分布式id的設計...

分布式ID解決方案

在分布式系統中,當資料庫資料量達到一定量級的時候,需要進行資料拆分 分庫分表操作,傳統使用方式的資料庫自有的自增特性產生的主鍵id已不能滿足拆分的需求,它只能保證在單個表中唯一,所以需要乙個在分布式環境下都能使用的全域性唯一id。uuid uuid是指在一台機器上生成的數字,主要由當前日期和時間 時...

分布式ID生成方案

系統唯一id是設計乙個系統的時候常常會遇到的問題,也常常為這個問題而糾結。生成id的方法有很多,適應不同的場景 需求以及效能要求。所以有些比較複雜的系統會有多個id生成的策略。1 全域性唯一性 不能出現重複的id號,既然是唯一標識,這是最基本的要求 2 粗略有序 如果在分布式環境中做到完全有序,需要...