后端工程师的高阶面经
邓明
前 Shopee 高级工程师,Beego PMC
6888 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 50 讲
后端工程师的高阶面经
15
15
1.0x
00:00/00:00
登录|注册

16|分库分表主键生成:如何设计一个主键生成算法?

你好,我是大明。今天我们来聊一聊分库分表——主键生成。
分库分表在面试里是一个非常热门,而且偏难的一个话题。这节课我就带你来攻克这个难题,带你了解 UUID、自增主键和雪花算法的特点,并且教你在面试的时候刷出亮点。在这些基础上,我会进一步给出一个微创新的主键生成方案,可以作为你面试时候的主要突破口。
不过为了让你的知识系统更加完整,我前面还是会给你讲解一下分库分表相关的知识,这样就算你的基础比较薄弱,也能看懂后面的方案。

前置知识

所谓的分库分表严格来说是分数据源、分库和分表。例如某个公司订单表的分库分表策略就是用了 8 个主从集群,每个主从集群 4 个库,每个库有 32 张表,合在一起可以说成是
不过根据数据规模和读写压力,也可以共享一个主从集群,然后只分库或者只分表。如果面试面到了分库分表的内容,那么主键生成基本上就是一个绕不开的话题。显然,在没有分库分表的时候,我们都可以使用自增主键。
比如说我们在 MySQL 里面的建表语句,指定了 AUTO_INCREMENT。
CREATE TABLE order (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
buyer_id BIGINT NOT NULL
)
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

分库分表是数据库领域的热门话题,本文深入探讨了分库分表的主键生成算法,介绍了UUID、数据库自增和雪花算法等常见主键生成策略。文章详细解释了这些策略的优缺点,并提出了优化方案。此外,还强调了面试准备的重要性,包括深入理解主键生成策略、准备有亮点的方案以及记住可行的优化方案。通过深入讨论分库分表的主键生成问题,为读者提供了面试准备和技术知识的指导。文章还提出了主键内嵌分库分表键的亮点方案,将主键生成策略和分库分表键结合,为读者呈现了一种创新的设计思想。 在主键生成策略方面,文章介绍了全局递增、独一无二等方案,并对其优缺点进行了详细分析。此外,还提出了优化思路,包括批量取、提前取、singleflight取、局部分发等方法,以降低发号器的并发压力,提高性能。 总之,本文通过深入讨论分库分表的主键生成问题,为读者提供了全面的技术知识指导,同时强调了面试准备的重要性,为读者提供了实用的面试准备建议。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《后端工程师的高阶面经》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(19)

  • 最新
  • 精选
  • Johar
    mysql里面也可以把uuid转换为16字节,同时将时间戳按照高,中,低排列,也可以实现自增

    作者回复: 新用法!我倒是没想到还有这种玩法,算是学了一招,感谢!

    2023-07-21归属地:重庆
    3
  • Homto
    你设想这么一个场景:你的分库分表是按照 ID 除以 32 的余数来进行的,那么如果你的业务非常低频,以至于每一个时刻都只生成了尾号为 1 的 ID,那么是不是所有的数据都分到了一张表里面呢? 问题来了:非常低频的话那,是不是就没有必要分表了?

    作者回复: 其实这个主要考虑的高峰和低谷。高峰很高但是低谷也很低。

    2023-08-06归属地:四川
    2
  • 小晨
    在主键内嵌分库分表键的方案中,为什么第三段要采用随机数而不是顺序序列号呢?

    作者回复: 这个跟你怎么落地 ID 生成程序有关系。在这种方案中,可以直接在应用服务器中生成。而一个创建订单的服务有很多实例,通过负载均衡之后,同一个人的请求会落到不同的机器上,这时候你要顺序序列号,就得协调这些机器。 随机就没这个烦恼。

    2023-07-31归属地:江苏
    2
  • sheep
    回答问题: 1. 可以是可以,但是缩减之后所能代表的机器数量也就减少了 2. Go里面的GMP调度中的本地队列和全局队列,Go内存分配中的mcache

    作者回复: 赞!

    2023-10-27归属地:广东
    1
  • 我好像一点都不像程序员
    1、个人认为还是个 trade off 问题,缩短时间戳和缩短机器位数两种方式都是可取的,如果你的业务活不了太久,那么缩短时间戳位数问题不大,如果你确定你不会拼命堆机器来提高业务吞吐量,当然也可以缩短机器位数,没有对与错之分,只有哪个方式更适合当前情况 2、记得PHP是每次都是向OS申请一大片内存空间的,然后再慢慢用,算不 by the way :补充一个我们日常的使用场景《数据迁移》,自增ID对数据迁移来说是非常不友好的,动不动就冲突,如果还用自增ID来做业务关联,那就更麻烦了,如果真的要用自增ID,最好是把它当作占坑用的,业务不要用它,而UUID 的主键虽然可以解决冲突问题,但是它的缺点也很明显,页分裂,查询不友好,占用空间大,这样索引树的空间占用也变大了(非主键索引树叶子节点存的是主键),而雪花ID可以递增又可以解决冲突问题,所以目前我们的新服务我都是要求用雪花ID,雪花ID冲突的场景我工作中确实没有遇到过(业务不给力呀,好想搞电商) 另外,分段思想还挺不错的,感谢大明兄分享

    作者回复: 1. 赞! 2. 哈哈哈,也算。很多系统,包括我们自己设计缓存都是这种套路,自己申请一块,内部慢慢分。 多交流!

    2023-07-22归属地:广东
    5
    1
  • 波多黎各仔
    我觉得实际上,应该不可以挪用机器Id比特位。 虽然说,如果项目规模不大,部署的微服务较少,可以去挪用。但是,现在的情况是微服务的序列都不够用了,说明业务量比较大,一般是有增加机器的需求,怎么还会去减少机器Id比特位呢

    作者回复: 赞!对,这是一个理由!

    2023-07-21归属地:江苏
    1
  • NullPointerException
    普遍情况下,我们都是用买家 ID 来查询对应的订单信息。在别的场景下,比如说我们只有一个订单 ID,这种时候我们可以取出订单 ID 里嵌入进去的买家 ID 后四位,来判断数据存储在哪个库、哪个表。类似的设计还有答题记录按照答题者 ID 来分库分表,但是答题记录 ID 本身可以嵌入这个答题者 ID 中用于分库分表的部分 没太明白只有uid后四位怎么判断uid对应的库表的?

    作者回复: 你是按照买家的后四位来分库分表的,那么你知道这个后四位,就知道数据在哪里了。

    2023-12-14归属地:上海
  • jCodePorter
    在主键内嵌分库分表键的方案中,使用4位的用户id,那么如果本身用户体量非常大,已经达到亿级用户了。那么后四位完全一样的用户数就存在很多很多了,如果同时下单,那生成的主键不就冲突很严重了吗?解决方案除了让业务等待暂停下,还有其他方案吗

    作者回复: 冲突也没想象中的严重。因为时间戳本身是记录的是毫秒数,那么你可以预期,如果是千万 QPS(一秒一千万个订单已经很高了),那么同一毫秒,也就是有一万个请求而已。后四位相同的概率就是 1/9999,而随机数是 8比特,也就是随机数相同的概率是 1/2^8,一万个请求也不一定会有一个相同的 ID。 我这个算法应该不太对,但是量级应该是这样一个量级,就是冲突并没有想象中的那么厉害。并且,冲突了之后,可以再次生成一个随机数,这个时候估计就避开了上一个冲突的同尾号的用户了。

    2023-10-28归属地:河南
  • sheep
    发号器一般都需要单独部署一个新的服务么,类似于基于Redis的发号器这些?

    作者回复: 我主观来说,我是觉得独立部署的发号器是一个纯纯馊主意。我更加倾向于应用服务器本身也充当发号器(也就是不同的线程/goroutine),然后直接应用就从本地的发号器里面拿ID。 独立部署的发号器就是你说的这种,还有微服务集群形态的发号器。

    2023-10-26归属地:广东
  • sheep
    1. 页分裂除了逻辑相邻的数据在磁盘上不相邻之外,页分裂过程也会对数据库性能有所消耗吧 2. 亮点3: 数据堆积这里,这里是对雪花算法之后的数字进行求余,然后确定对应要插入到的数据库么

    作者回复: 1. 对的 2. 是的。比如说你很不幸把所有的大商家的数据都分配到了同一个表里,这张表就会有极多的数据。

    2023-10-26归属地:广东
收起评论
显示
设置
留言
19
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部