高并发系统设计八-发号器-如何保证分库分表后ID的全局唯一性

1、分库分表后带来的问题

  • 查询的时候必须带着分区键字段
  • 一个聚合类查询性能比较差,需要考虑使用计数器等其他的解决方案
  • 主键的全局唯一性问题

2、数据库中的主键要如何选择

数据库中的每一条记录都需要有一个唯一的标识,依据数据库的第二范式,数据库中每一个表中都需要有一个唯一的主键,其他数据元素和主键一一对应。

  • 使用业务字段作为主键

比如用户表中使用手机号码,email或者身份证号码作为主键。但是有的不是太适用,比如要考虑作为主键的业务字段能否唯一标识一个人,一个人可能会有多个手机号码,email,身份证号码可以是用户的唯一标识,但是它有属于隐私属性,还有就是已有的身份证号码可能会变更,比如在1999年时身份证号码从15位变更为了18位。

  • 使用生成的唯一 ID 作为主键

这种方式的话,可以保证唯一性,生成后也不会更改,可以随意引用。

单库单表的场景下,使用数据库的自增字段作为ID,但是在分库分表后,使用自增字段就无法保证ID的全局唯一性。

使用UUID作为主键会有什么问题

  • 生成的ID最好具有单调递增性(有序,ID可能会成为排序字段),而UUID不具备这个。
  • ID有序会提升数据的写入性能。

MySQL InnoDB 存储引擎使用 B+ 树存储索引数据,而主键也是一种索引。索引数据在 B+ 树中是有序排列的。


当插入的下一条记录的 ID 是递增的时候,比如插入 30 时,数据库只需要把它追加到后面就好了。但是如果插入的数据是无序的,比如 ID 是 13,那么数据库就要查找 13 应该插入的位置,再挪动 13 后面的数据,这就造成了多余的数据移动的开销

  • UUID不具备业务含义。
  • UUID 是由 32 个 16 进制数字组成的字符串,如果作为数据库主键使用比较耗费空间。

3、基于 Snowflake 算法搭建发号器

运用它去解决 ID 全局唯一性的问题。

Snowflake 的核心思想是将 64bit 的二进制数字分成若干部分,每一部分都存储有特定含义的数据,比如说时间戳、机器 ID、序列号等等,最终生成全局唯一的有序 ID


不同公司也会依据自身业务的特点对 Snowflake 算法做一些改造,比如说减少序列号的位数增加机器 ID 的位数以支持单 IDC 更多的机器,也可以在其中加入业务 ID 字段来区分不同的业务。比方说我现在使用的发号器的组成规则就是:1 位兼容位恒为 0 + 41 位时间信息 + 6 位 IDC 信息(支持 64 个 IDC)+ 6 位业务信息(支持 64 个业务)+ 10 位自增信息(每毫秒支持 1024 个号)

3.1、实现方式

  • 嵌入到业务代码中(分布在业务服务器中)。
    • 好处是业务代码在使用的时候不需要跨网络调用,性能上会好一些,
    • 但是就需要更多的机器 ID 位数来支持更多的业务服务器。
    • 由于业务服务器的数量很多,我们很难保证机器 ID 的唯一性,所以就需要引入 ZooKeeper 等分布式一致性组件来保证每次机器重启时都能获得唯一的机器 ID。
  • 作为独立的服务进行部署-发号器服务。
    • 多一次的网络调用
    • 微博和美图都是使用独立服务的方式来部署发号器的,性能上单实例单 CPU 可以达到两万每秒

3.2、实际项目中可能遇到的问题

如果请求发号器的 QPS 不高,比如说发号器每毫秒只发一个 ID,就会造成生成 ID 的末位永远是 1,那么在分库分表时如果使用 ID 作为分区键就会造成库表分配的不均匀

  • 时间戳不记录毫秒而是记录秒,这样在一个时间区间里可以多发出几个号,避免出现分库分表时数据分配不均
  • 生成的序列号的起始号可以做一下随机,这一秒是 21,下一秒是 30,这样就会尽量地均衡了

4、其他方案

  • 滴滴和美团都有提出基于数据库生成 ID 的方案。这些方法根植于公司的业务,同样能解决分布式环境下 ID 全局唯一性的问题

  • 百度开源的UidGenerator(仅支持单机部署)使用Snowflake算法,单机QPS可达600万。项目说明:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md 。

  • 美团Leaf(分布式ID生成系统),QPS近5万。项目地址:https://tech.meituan.com/2017/04/21/mt-leaf.html 。

  • 微信序列号生成器
    文档地址:https://www.infoq.cn/article/wechat-serial-number-generator-architecture

发布了57 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/wmdkanh/article/details/105523102