微服务系列之分布式ID

前言

在我们第一次接触MySQL的时候,除了那些表啊,行啊,列啊特性之外,紧接着我们就接触到了主键ID,这个ID一般我们默认会设置为整张表唯一的且是不断递增的,如果是单机系统里面,对于这个自增的主键ID其实没有多大问题,但是在复杂的分布式系统中,需要对大量的数据和消息进行唯一标识,如果面对的是订单,日志这种大数据级别的数据,可能会涉及到对数据进行分库分表,那么就需要有一个全局的唯一ID来标识不同来源进来的数据和记录,而且不能重复,这个时候,单纯的自增主键ID就有一定的弊端了,比如生成规则一样,会导致数据不唯一,再或者数据量庞大,自增会达到上限(MySQL的自增机制是有上限的),所以这里面我们就要引进:全局唯一ID,相关策略有很多种,但是每种策略都有对应的适用场景和优缺点,下面我们深入探索一下

介绍

个人理解:它是一个在分布式环境或者更复杂的环境下的一种可以保证唯一且可以一直生成的主键ID

特点

1、全局唯一性:不能出现重复,毕竟是唯一标识,这是所有特性的前提

2、趋势递增:在InnDB引擎中使用的是聚集索引,但是由于多数RDBMS使用的是B树的数据结构来存储索引数据,所以在主键的选择上面我们应该尽量使用有序的主键,保证写入性能

3、单调递增:保证下一个ID一定大于上一个ID,因为可能我们会有需求是对ID进行排序的

4、信息安全:遇到过SQL注入漏洞的都清楚,如果一个ID是连续的,很容易被爬到数据,所以我们要保证ID不容易被猜到,最起码不能是有规律的自增。比如每次+1,我们要保证ID无规则、不规则

5、高可用性:全局ID,说白了也是一个程序,如果这个程序崩掉了,那可能就会带来很大的麻烦,无法预想的麻烦,所以这个程序肯定不能是单点的,一定要是高可用的

6、分片支持:把某些数据放在同一个分片内,这样根据定位分片更容易查询和修改

7、长度适中:长度很长的话,也意味着逻辑很长,同时生成ID的等待时间就很长,所以长度适中就好

常见的ID生成策略 

1、数据库自增主键ID

这个是最常见的,也是最简单的,是利用MySQL自身提供的机制,来设置的

【优点】

简单,成本小,性能能够接受

【缺点】

1、太依赖数据库:毕竟是数据库自身的一个机制

2、单点故障:在单个数据库或读写分离或一主多从的场景下,只有一个主库可以生成,那就存在单点故障的问题

3、数据一致性问题:数据一致性在特殊情况下难以保证主从赋值的可用性,如果在主从切换的时候,可能会导致重复

4、难于拓展:ID性能和长度都是有限制的,在性能达不到要求的情况下,比较难拓展

【解决方案】

在主从场景下,如果有多个Master的话,那就可以区分开生成规则,比如Master1的自增是1,4,7,10,那Master2可以是2,5,8,11


2、UUID

相对比较常见,它是利用程序生成的

目的

UUID是让分布式系统中的所有元素都能有唯一的标识每个人都可以建立与他人不重复的UUID,这样的话,就不需要考虑数据库建立时的名称重复问题

组成讲解

UUID的一个标准形式是32个16进制的数字,以“-”符号分为五段,,示例:d8702430-9ef3-48e0-b48b-dc49a09421b9,目前我知道生成UUID的方式有五种,不过最常见的就是下面这一种:

System.out.println(UUID.randomUUID().toString());

【优点】

1、很简单:直接用上面的代码即可生成

2、性能很好:生成id没有网络消耗,基本不存在性能问题

3、全局唯一:在数据库迁移、系统数据合并或者其他数据库数据操作,都可以应对

【缺点】

1、存储成本比较高:因为UUID比较长,很多场景不适用,如果是海量数据,就得考虑存储量的问题了

2、信息不安全:UUID生成的时候,其中的参数包括本机的MAC地址,可能会造成MAC地址泄漏,曾经这个漏洞是发生过损失的

3、不适合做主键:UUID看它生成的串就知道它往往是字符串存储的,如果让它做数据库的主键,会导致查询的效率很慢

4、UUID是无序的:不是单调递增的,每次生成的字符串,与上一次或者历史生成的都没有一定的规律在里面,无序加上比较长的字符串导致主键新增效率比较低

5、传输数据量比较大

6、不可读,也不好维护

【解决方案】

关于上面缺点,很多公司都给出了对应的解决方案

  • 解决UUID不可读的问题,可以使用UUID to Int64的方法来生成
  • 解决UUID无序的问题:NHibernate在其主键生成方式中提供了Comb算法。保留GUID的10个字节,用另6个字节表示GUID生成的时间

3、Redis

基于redis的incr和incrby可以来实现ID的生成,关于redis就不做过多介绍了

【应用方案】

如果是为了解决订单号的ID生成问题,可以指定订单号规则,比如订单号=order+时间戳,然后后面跟上redis的incr命令自增的值即可

【优点】

1、不依赖数据库,redis本身也是数据库而且因为redis的机制,它的性能还比数据库好

2、数字ID是有一定规则的,是递增的,对数据的分页和排序有一个好的支持

【缺点】

1、需要在系统里进入redis中间件

2、Redis单点故障,会影响序列服务的可用性

3、如果是对redis使用不熟练的童鞋,有关配置和维护的工作量还是有点的


4、ZooKeeper

因为zk本身znode机制,可以生成32/64位的版本号,用这个版本号可以做唯一的标识,但是我没咋见过有哪家公司用zk做ID生成工具的,因为调用zk的API,存在锁的问题,这样的话,性能在分布式环境下,可能会大打折扣,了解就行,我也不做过多介绍了


5、snowflake算法(也称雪花算法)

这个需要大家注重学习一下哈

【介绍】

大家应该对他会很陌生,他是开源的分布式ID生成算法,是专门为分布式唯一ID而生滴,生成一串long类型的ID,它其实就是把64bit分别划分为多段,每一段都有对应的含义,比如表示机器、时间等等

  • 41-bit表示毫秒数
  • 10-bit-workerID表示机器的ID
  • 10-bit序列号作为毫秒内的流水号,意味着每个节点在每毫秒可以产生4096个ID
  • 还有一个符号位,永远是0

【优点】

1、稳定性高:不依赖第三方系统,已服务的方式部署,相对稳定性比较高,生成ID的性能也是非常可观的

2、灵活方便:可以根据自身业务特性分配bit位

3、单机上ID单调自增:毫秒级在高位,自增序列在低位,整个ID是趋势递增的

【缺点】

1、比较依赖当前机器的时间,如果时间回拨,会导致重复或者服务不可用

2、ID可能不是全局递增,只是在单机上是递增的,但是因为在分布式环境,没太机器的始终不可能完全同步,所以会有时候出现不是全局递增的情况

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值