15.sharding-jdbc中的分布式ID

实现动机

传统数据库软件开发中,主键自动生成技术是基本需求。而各大数据库对于该需求也提供了相应的支持,比如MySQL的自增键。 对于MySQL而言,分库分表之后,不同表生成全局唯一的Id是非常棘手的问题。因为同一个逻辑表内的不同实际表之间的自增键是无法互相感知的, 这样会造成重复Id的生成。我们当然可以通过约束表生成键的规则来达到数据的不重复,但是这需要引入额外的运维力量来解决重复性问题,并使框架缺乏扩展性。

目前有许多第三方解决方案可以完美解决这个问题,比如UUID等依靠特定算法自生成不重复键(由于InnoDB采用的B+Tree索引特性,UUID生成的主键插入性能较差),或者通过引入Id生成服务等。 但也正因为这种多样性导致了Sharding-JDBC如果强依赖于任何一种方案就会限制其自身的发展。

基于以上的原因,最终采用了以JDBC接口来实现对于生成Id的访问,而将底层具体的Id生成实现分离出来。

摘自sharding-jdbc分布式主键:http://shardingjdbc.io/1.x/docs/02-guide/key-generator/

sharding-jdbc的分布式ID采用twitter开源的snowflake算法,不需要依赖任何第三方组件,这样其扩展性和维护性得到最大的简化。但是snowflake算法最大的缺陷,即强依赖时间,如果时钟回拨,就会生成重复的ID,sharding-jdbc没有给出解决方案,如果用户想要解决这个问题,需要自行优化;

美团的分布式ID生成系统也是基于snowflake算法,并且解决了时钟回拨的问题,读者有兴趣请阅读Leaf——美团点评分布式ID生成系统:https://tech.meituan.com/MT_Leaf.html

分布式ID简介

github上对分布式ID这个特性的描述是:,两个重要特性是:分布式唯一时间序;基于Twitter Snowflake算法实现,长度为64bit;64bit组成如下:

1bit :签名校验位,也可以当做预留位。

41bits :当前时间与服务第一版本发布时间的差值。

10bits :进程ID(也可以分解成2bit+8bit,其中2bit表示数据中心,可以容纳4个数据中心,8bit表示进程ID,可以256个进程)。

12bits :每一毫秒的自增值。所以snowflake算法能达到4096/ms的并发能力。

snowflake算法核心图

分布式ID源码分析

核心源码在sharding-jdbc-core模块中的中:

获取workerId的三种方式

sharding-jdbc的模块中,提供了三种方式获取workerId的方式,并提供接口获取分布式唯一ID的方法--,接下来对各种方式如何生成workerId进行分析;

HostNameKeyGenerator

根据hostname获取,源码如下(HostNameKeyGenerator.java):

IPKeyGenerator

根据IP获取,源码如下(IPKeyGenerator.java):

IPSectionKeyGenerator

根据IP段获取,源码如下(IPSectionKeyGenerator.java):

总结

大道至简,笔者还是比较推荐HostNameKeyGenerator方式获取workerId,只需服务器按照标准统一配置好hostname即可;这种方案有点类似spring-boot:约定至上;并能够让架构最简化,不依赖任何第三方组件。因为依赖的组件越多,维护成本越高,出问题概率越大,可靠性更低!

当然HostNameKeyGenerator这种方式的话,就不能一台服务器上部署多个实例,事实上这不是问题。一般生产环境会有很多的服务器,也有很多的服务实例。我们可以通过交叉部署来避免这个问题。比如不要一台服务器上部署3个订单服务,而是3台服务器上分别部署1个订单服务实例,服务器上多余的资源可以部署其他服务。

总之,每种方法都有它的优缺点,我们要做的就是trade-off。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180915G0A32400?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券