当前位置: 首页 > 科技观察

DB分库分表(二):全局主键生成策略

时间:2023-03-13 23:16:36 科技观察

本文将主要介绍一些常见的全局主键生成策略,然后重点介绍flickr使用的一个非常好的全局主键生成方案。sharding的拆分策略和实现细节可以参考本系列上一篇文章:DB分片与分片(一):拆分实现策略及示例演示***部分:一些常用的主键生成策略一旦数据库被拆分成多个物理节点,我们就不能再依赖数据库自己的主键生成机制了。一方面,分区数据库自生成的ID不能保证全局唯一;另一方面,应用程序在为SQL路由插入数据之前需要获取ID。目前有几种可行的主键生成策略:1.UUID:使用UUID作为主键是最简单的方案,但是缺点也很明显。由于UUID很长,除了占用大量存储空间外,主要的问题还是在索引上,无论是创建索引还是基于索引的查询都存在性能问题。2、结合数据库维护一个Sequence表:这个方案的思路也很简单。在数据库中创建一个Sequence表。表的结构类似于:CREATETABLE`SEQUENCE`(`tablename`varchar(30)NOTNULL,`nextid`bigint(20)NOTNULL,PRIMARYKEY(`tablename`))ENGINE=InnoDB取对应表的nextid每当需要为一张表的一条新记录生成一个ID时,就会从Sequence表中取出,并将nextid的值加1更新到数据库中,以供下次使用。这种方案也比较简单,但缺点同样明显:由于所有的insert都需要访问表,表很容易成为系统性能瓶颈,同时也存在单点问题。一旦表数据库出现故障,整个应用程序将无法运行。有人提出用Master-Slave做主从同步,但这只能解决单点问题,不能解决1:1读写比的访问压力问题。另外还有一些解决方案,比如给每个数据库节点分区ID,网上有一些ID生成算法。由于缺乏可操作性和实际测试,本文不推荐使用。其实接下来,我们要介绍的是Fickr使用的一种主键生成方案。这个方案是目前我所知道的最好的方案,并且经过实践检验,可以被大多数应用系统所采用。借鉴。第二部分:一个优秀的主键生成策略。flickr开发团队在2010年写了一篇文章介绍flickr使用的一种主键生成测试策略。同时表示该方案在flickr上的实际运行效果也非常令人满意。这个方案是目前我知道的最好的方案。有点类似于通用的Sequence表方案,但是很好的解决了性能瓶颈和单点问题。它是一种非常可靠和高效的全局主键生成解决方案。图1.flickr采用的sharding主键生成方案示意图。flickr方案的总体思路是建立两个以上的数据库ID生成服务器。每个服务器都有一张Sequence表,记录了当前每张表的ID,但是Sequence中的ID是递增的。的步长是服务器的个数,起始值依次交错,相当于把ID生成散列到每个服务器节点。例如:如果我们设置两台数据库ID生成服务器,那么让其中一张Sequence表的ID起始值为1,每次增长步长为2,另一张Sequence表的ID起始值为2,每次增长step也是2,那么结果就是奇数ID会从第一个服务器生成,偶数ID会从第二个服务器生成,这样生成ID的压力就平均分配到两个上服务器,在应用程序的控制下,当一台服务器出现故障时,系统可以自动切换到另一台服务器获取ID,从而保证了系统的容错性。下面说说这个方案的几个细节:1.flickr的数据库ID生成服务器是一个专用的服务器,服务器上只有一个数据库,数据库中的表都是用来生成Sequence的,这也是因为auto-increment-offsetauto-increment-increment和auto-increment-increment这两个数据库变量是数据库实例级变量。2.flickr解决方案中表中的存根字段只是一个char(1)NOTNULL存根字段,不是表名。所以一般来说一张Sequence表只有一条记录,可以同时为多张表生成ID。如果需要表的ID是连续的,需要为表单独创建一个Sequence表。3、该方案使用了MySQL的LAST_INSERT_ID()函数,这也决定了Sequence表只能有一条记录。4.使用REPLACEINTO插入数据。这是一种非常方便的方式。主要是利用了mysql自身的机制来生成id。不仅因为它如此简单,还因为我们需要ID按照我们设置的方式(初始值和步长)来生成。5.SELECTLAST_INSERT_ID()必须和REPLACEINTO语句连接同一个数据库,才能得到刚刚插入的新ID,否则返回值一直是06。该方案中Sequence表使用MyISAM引擎获得更高的性能,注意:MyISAM引擎使用的是表级锁,MyISAM是串行读写表的,所以不用担心并发读的时候两次读得到相同的ID(另外应用不需要同步),每个请求线程都会得到一个新的连接,没有共享资源需要同步)。经过实际对比测试,使用同一张Sequence表生成ID,MyISAM引擎的性能比InnoDB好很多!7、可以使用纯JDBC实现对Sequence表的操作,以获得更高的效率。实验表明,即使只使用springJDBC,性能也不如纯JDBC快!实现这个方案,应用程序还需要做一些处理,主要有两个方面:1.自动平衡数据库ID生成服务器的访问2.保证某个数据库ID生成服务器出现故障的情况下,可以请求转发给其他服务器执行。