1 Sequence简介
DRDS sequence全称:全局唯一数字序列,顾名思义,其作用是生成全局唯一和有序递增的数字序列。常用于主键列、唯一索引列等值的生成。
Sequence分类,总共分为两大类:
显式sequence:通过sequence语法进行创建与维护,可以单独使用。
隐式sequence:DRDS表主键定义 AUTO_INCREMENT后,用于自动填充主键,由 DRDS 自动维护
每类sequence针对不同的使用场景还分为四种类型,分别为Group Sequence,Group Sequence(单元化),Time-based Sequence,Simple Sequence。
详情参考阿里云官网
本文重点介绍group隐式sequence。为什么?
1、sequence原理性的东西,在官网上基本没有体现,我们只知其然而不知其所以然2、当然是因为做DRDS数据迁移踩的关于隐式sequence的坑太多了,经常跟阿里研发取经,加上环境测试了解到一些东西。
2 sequence的原理理解
1、sequence值是如何分配的?
如图所示:DRDS在分配sequence的时候,会根据自身的节点数来划分多个sequence段,默认每个段的长度为10万。注意这里是根据DRDS的规格节点数来划分的sequence端,而不是根据RDS的数量,与RDS无关。
通过show sequences;命令,可以查看当前sequence的value。
这里的value值通常是表示已经分配的最大sequence段的起始值,即200000
2、sequence的起始值
有没有发现上图中,sequence段的起始值我是从100001开始取值的。默认情况下,sequence的起始值并不是按照1来开始递增的,而是按照100001开始的。这就涉及到内部的一些算法:
(value - value % (innerStep unit_count)) + innerStep unit_count + nodeIndex * innerStep
实验证明如下:
新建一张表,并且插入一条测试数据:
可以看到主键的id是从100001开始取值的。
3、sequence的缓存
这里在节点上分配的sequence段,我们可以称之为sequence的缓存,正常情况下,节点上的缓存用完才会重新分配sequence段。
缓存实验测试如下:
truncate表清理了数据之后,重新插入数据还是会用到之前的缓存,从100002开始。
由于这种缓存的存在,尤其是DRDS在数据迁移的某些场景时,会产生很大的影响。
某客户案例:
DRDS进行平台的数据迁移,由于没有直接迁移DRDS to DRDS的工具,经过多次测试与衡量决定采用底层RDS to RDS方式的数据迁移。在第二次进行应用测试大批量报错主键冲突。原因就是第一次测试完,truncate清理数据后,缓存还是存在的。第二次导入数据后则还是会用缓存的值,这时候测试插入数据就会出现主键冲突。
这里出现sequence冲突的根本原因是,sequence本来是DRDS层面维护的,但是采用非标的方式迁移底层的RDS数据,虽然数据没有问题,但sequence就没有人来维护了。这样就很容易出现很多问题。所以不到迫不得已尽量不要走非标方案。
解决方法:清理sequence缓存。
常用的清理缓存的方法:
1、alter sequence start with AUTO__XXXX;使用命令抬高sequence,命令是表级别的。
2、重启drds,目的是重启节点。
3、表删除重新建表
4、缓存的值是如何计算出来
我们已经知道,初始化的时候,sequence的值会按照算法定义起始值。那alter sequence start with AUTO__XXXX命令是如何更新sequence的value 以及 缓存的呢?
同理,alter sequence调整后,也会重新初始化sequence,先用算法更新起始值
(value - value % (innerStep unit_count)) + innerStep unit_count + unit_index * innerStep
然后再用下面的公式计算缓存区间:所有节点先后用公式计算
value + (inner_step * unit_count)
简单的说:一般而言,执行命令alter后,首先会根据算法,将调整的sequence“合法化”,就是取整数,然后加一段区间更新到缓存,所以缓存会更新到一个更大的值。所以你会发现,在执行alter命令后,之后的主键值并不是按照修改的值递增的,主键值肯定比调整的value要大。
测试验证如下:
上图可以看到,show sequence显示的值为200000,与缓存中已分配的sequence段的最大值匹配。
上图中,随意调大了sequence的value,show sequence显示为了432432,(这个只是暂时显示,后面还是会更新为最大sequence段的起始值)
上图中,又插入了一条数据,发现show sequence的值已经改了。用命令查询一下缓存,果然缓存已经更新了,并且是比alter设置的value值要大。
这里还会发现,图中第一次show sequence时,不是代表最大的sequence段的起始值。这是因为sequence值用到的时候才会更新这个value。
那为什么执行查看缓存的命令inspect后就恢复了呢?
猜测这个命令会强制刷新value与缓存保持一致。
那么此时再插入数据主键会是从432432开始吗?
当然不是了,如果你还觉得是,那就是之前我啰嗦的不够透彻。
这里就是按照缓存中的值来取sequence了。