库自增ID

基于数据库的ID生成

sequence单表方案

在单数据源情况下,基于原理2生成id,此时数据库就是中心节点,所有序列号由中心节点派发;而在多数据源和单元化场景下,单元化是多数据源的特例,支持多数据源就能方便实现单元化支持。

这种情况下一个序列只存储于一张sequence表,使用SequenceDao进行表的读写。一张sequence表可以存储多个序列,不同的序列用名字(name)字段区分,所以一般而言一个应用一个sequence表就够了,甚至多个应用可以共享一张sequence表。通过这种单点数据源的方式,可以实现序列全局唯一,由于数据库知道目前派发出去的最大id号,后续的请求,只要在现在基础上递增即可。现在应用申请一个id,需要用乐观锁(CAS)的方式更新序列的值,但是每个id都要乐观锁更新db实在太慢,因此为了加速id分配,一次CAS操作批量分配id,分配id的数量就是sequence的内步长,默认的内步长是1000,这样可以降低1000倍的数据库访问,不过有得必有失,这种方式生成的序列就不能保证全局有序了,并且在应用重启的时候,将会重新申请一段idsequence所用的数据库表结构如下:

-- ----------------------------
--  Table structure for `sequence`
-- ----------------------------
DROP TABLE IF EXISTS `sequence`;
CREATE TABLE `sequence` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Id',
  `name` varchar(64) NOT NULL COMMENT 'sequence name',
  `value` bigint(20) NOT NULL COMMENT 'sequence current value',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` timestamp NULL DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='sequence'
;

sequence表的核心字段就两个:namevaluename就是当前序列的名称,value就是当前sequence已经分配出去的id最大值。多数据源的场景除了能够自适应后面的单元化场景之外,还可以避免单点故障,即一个sequence表不可用情况下,sequence能够用其他数据源继续提供id生成服务。

即为每个数据源分配一个序号,数据源根据自己的序号在序列空间中独占一组序列号,原理如下图:

image

水平扩展

单台机器自然存在可用性问题,最简单的方式就是考虑将其扩展到多台机器,在前文的sequence单表方案中,我们是基于单表的自增;在分布式情况下,我们可以通过设置不同数据库的auto_increment_increment以及auto_increment_offset来不同的自增规则:

begin;
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();
commit;

在分布式系统中我们可以多部署几台机器,每台机器设置不同的初始值,且步长和机器数相等。比如有两台机器。设置步长step2TicketServer1的初始值为1(1,3,5,7,9,11…TicketServer2的初始值为2(2,4,6,8,10…。如下所示,为了实现上述方案分别设置两台机器对应的参数,TicketServer11开始发号,TicketServer22开始发号,两台机器每次发号之后都递增2

TicketServer1:
auto-increment-increment = 2
auto-increment-offset = 1

TicketServer2:
auto-increment-increment = 2
auto-increment-offset = 2

假设我们要部署N台机器,步长需设置为N,每台的初始值依次为0,1,2N-1那么整个架构就变成了如下图所示:

不过这种方式也存在问题,系统水平扩展比较困难,比如定义好了步长和机器台数之后,很难进行增删。ID没有了单调递增的特性,只能趋势递增,并且数据库压力还是很大,每次获取ID都得读写一次数据库,只能靠堆机器来提高性能。

上一页