前面两节中,我们了解了分布式存储的两个核心:数据冗余和数据分片;架构图如下: 我们通过分库分表和主从读写分离的方式解决了数据库扩展的问题,但是数据库采用了分库分表之后,也带来了很多限制,‘ 比如关联查询,查询的时候必须带分区键,聚合类的查询需要借助第三方手段。 其实还有一个问题,没有提到,也是本章节需要讨论的, 主键的唯一性 数据库的主键要如何选择? 依据数据库的第二范式,数据库中表都需要有一个唯一主键,其他元素跟主键一一对应。 那么主键的选择就是关键了: 使用业务字段,比如对于用户表来说,身份证号、手机号等 使用唯一的ID作为主键。 对于大多数业务场景,第一种方式是不适用的。能找到一个唯一不变的业务字段比较难,比如手机号有可能变更或者废弃 身份证是用户的唯一标识,但是由于它的隐私性,并不是每一个用户都会提供。 因此我们比较倾向于采用第二种方式,不但唯一,而且生成之后也是不可变更的。 单库单标情况下,我们直接使用数据库自身提供的主键自增功能就可以了。但是当数据库采用了分库分表之后,这个时候再采用数据库自身提供的自增就无法满足了。这个时候怎来做呢?业内通用: 搭建分布式服务Id 统一对外提供 id 的生成。 基于 Snowflake 算法搭建发号器 twitter 开源的服务,这里不做负责介绍了,感兴趣同学可以自行 github 上研究下原理。 UUID 不能作为 ID 的另一个原因是它不具备业务含义, 其实现实世界使用的 ID都有一些有意义的数据,这些数据会出现在Id固定的位置上,UUID 是由 32 个 16 进制数字组成的字符串,如果作为数据库主键使用比较耗费空间。 Snowflake 算法设计得非常简单且巧妙,性能上也足够高效,同时也能够生成具有全局唯一性、单调递增性和有业务含义的 ID,但是它也有一些缺点,其中最大的缺点就是它依赖于系统的时间戳,一旦系统时间不准,就有可能生成重复的 ID。所以如果我们发现系统时钟不准,就可以让发号器暂时拒绝发号,直到时钟准确为止。 其实,大厂除了采取 Snowflake 算法之外,还会选用一些其他的方案,比如滴滴和美团都有提出基于数据库生成 ID 的方案。这些方法根植于公司的业务,同样能解决分布式环境下 ID 全局唯一性的问题。对你而言,可以多角度了解不同的方法,这样能够寻找到更适合自己业务目前场景的解决方案, 不过我想说的是,方案不在多,而在精,方案没有最好,只有最适合,真正弄懂方法背后的原理,并将它落地,才是你最佳的选择。