每日一题: 分库分表之后,id主键如何处理?
分库分表之后,id主键如何处理?(本问题由 @Howe 同学提出并提供参考答案,特此鸣谢)
这个问题的意思就是当进行了分库分表之后,将同一个数据表拆分成多个表,那么主键id如何保证全局唯一性?
① 使用数据库自增id,在另一个数据库中创建一张没有用途的表,每次插入业务数据之前先往这张表插入一个没有意义的数据,获取主键id,然后提供给业务数据使用。这种方式比较简单,但缺点在于采用了单库生成id,遇到高并发场景时会有性能瓶颈。其实在Java系统里维护一个id值也是同样的做法,在Java程序里维护自增ID,最终也需要落入磁盘。
② 设置表自增字段的步长,比如假设将一张表拆分成5张表,那么就将自增步长设置为5,并且每一个节点的起始id都不相同,比如0,1,2,3,4。这种方式的缺点在于步长会被定死,如果要增加节点,除了要修改步长之外,还要避免和已经插入的数据重复,所以扩展性比较差。
③ 使用UUID,但是UUID太长、占用空间大,如果将UUID作为数据库主键,因为UUID不是有序的,会导致插入索引的时候无法按顺序写,性能较差,不建议使用UUID作为数据库主键字段。
④ 使用系统当前时间,将系统当前时间作为主键id,但这种方式不适合在高并发场景下使用,并发很高时,一秒可能有几百上千的并发,会有id重复的情况。
⑤ 使用snowflake算法,snowflake算法是twitter开源的分布式id生成算法,使用64个bit来生成一个long类型的64位id(1个保留bit + 41个毫秒数bit + 10个机器id bit + 12个序列号bit),snowflake算法在高并发场景下性能较好,可以抗住每秒几万的并发,相对比较靠谱。
⑥ 还可以使用美团开源的leaf,leaf是美团基础研发平台推出的一个分布式ID生成服务,具备高可靠、低延迟、全局唯一等特点。
后续我们可以专门介绍一下snowflake算法以及leaf是如何实现的。除了以上5种方案,你还有什么其他方案吗?