前言

 生产系统随着业务增长总会经历一个业务量由小变大的过程,可扩展性是考量数据库系统高可用性的一个重要指标;在单表/数据库数据量过大,更新量不断飙涨时,MySQL DBA往往会对业务系统提出sharding的方案。既然要sharding,那么不可避免的要讨论到sharding key问题,在有些业务系统中,必须保证sharding key全局唯一,比如存放商品的数据库等,那么如何生成全局唯一的ID呢,下文将从DBA的角度介绍几种常见的方案。

方案一

专门建一个库/表分配全局唯一的ID

  • 1.创建一个生成ID的表(auto_increment id),要插入新业务数据时,开启事务,获取自增ID,使用此自增ID进行业务数据插入。 这个方法的问题在于每次生成ID都要开事务生成和查询新的ID,在高并发系统下资源竞争剧烈,效率极低,分配ID的表会成为整个系统的瓶颈。

  • 2.使用max(id)方案,创建一个表存放每个表的max id,需要插入新的业务数据时,查看max_id表找到当前ID中最大的ID,将此ID+1分配给新插入的业务数据,同时更新该业务数据所表对应的表的max id。这个方法的问题同上,唯一的好处是不会使分配ID的表的size变的很大。

方案二

每张表划分区域

  创建表时为每张表指定不同的AUTO_INCREMENT起始值。比如第一张表从1开始,第二张表从100000开始,当然这样显然存在一个问题,当第一张表的数据量,或者分配的ID超过100000时,就会导致ID重复,所以必须监控每个表的自增ID增长状况,当ID增长过快时,需要通过命令调整AUTO_INCREMENT起始值。

方案三

错位分配

 在设计阶段,通过指定每个sharding 表的 AUTO_INCREMENT 和步长来实现错位分配。需要注意的时,步长值要大于sharding的数目, 否在会导致重复分配ID,步长值-sharding数目=未来可扩展的sharding数量,这种方案的局限性也就在此,当布长值等于sharding数目时,想要再进行扩展是很复杂的。

方案四

组合ID

  • 1.使用sharding编号作为前缀+自增ID生成全局ID,需要再每个sharding的库或者实例下创建一个生产ID的表。这种实现的缺点在于每个sharding的实例或者逻辑下需要一个单独生产ID的表。
  • 2.组合主键,sharding表中增加一列存储sharding标识,用这一列和自增列共同作为主键,实现全局唯一。这种实现的缺点在于联表操作比较复杂,增加了存储成本。

其他

使用GUID\UUID或者twitter的snowflake等实现。

总结

方案一的两种实现都是非分布式的,也就是说所有的sharding都要依赖这个系统,那么这个系统很容易成为瓶颈,适合业务和并发量不大的系统,方案二和方案三都是通过调整和设计MySQL的AUTO_INCREMENT实现,但是都有各自的局限性。方案四是一种分布式的方案,各个sharding之间互不影响,不存在方案一的单点瓶颈问题,是比较好的实现方案。以上几种方案都是从DBA的角度提供的方案,UUID或者snowflake是业务端实现的方式,这里就不在赘述。