首选,不管是不是分布式系统,都有ID唯一的使用场景。而在分布式场景下,对ID的唯一性要求更严格!
常见的,我们上淘宝买东西的订单ID,就是一种分布式ID。淘宝,前期的订单id好像是14位,现在好像已经是16位,或者18位了吧。
以我们公司的订单ID为例,它有这几个特点。
- ID全局唯一,不会重复
- ID的增长支持分布式使用
- ID要方便好记,并且通过ID能大概看出是什么时间创建的订单
- 订单ID最好还能追踪到销售员,或下单用户的ID等
- 增长的订单ID还不能让竞争对手发现你每天的业务量
针对第五项,浅显的问题就是不能让非核心运营者知道每天的订单量等信息。如果ID是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,竞对可以直接知道我们一天的订单量。所以在一些应用场景下,会需要ID无规则、不规则。
所以,设计一个好的分布式ID生成器并不是那么容易的。于是网上也有很多大公司开源这类分布式ID生成器。我今天就抽个时间,扯一扯它们之间的不同点吧。
说到,分布式ID,我们首选想到的可能就是UUID了。
UUID
UUID(Universally Unique Identifier)的标准型式包含32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的36个字符,示例:550e8400-e29b-41d4-a716-446655440000,到目前为止业界一共有5种方式生成UUID。
UUID的优点:
- 性能非常高:本地生成,没有网络消耗。
UUID 的缺点:
- 不易于存储:UUID太长,16字节128位,通常以36长度的字符串表示,很多场景不适用。
- 信息不安全:基于MAC地址生成UUID的算法可能会造成MAC地址泄露,这个漏洞曾被用于寻找梅丽莎病毒的制作者位置。
- ID作为主键时在特定的环境会存在一些问题,比如做DB主键的场景下,UUID就非常不适用。MySQL官方有明确的建议主键要尽量越短越好,36个字符长度的UUID不符合要求;UUID还对MySQL索引不利,如果作为数据库主键,在InnoDB引擎下,UUID的无序性可能会引起数据位置频繁变动,严重影响性能。
snowflake
snowflake我就不在介绍了,我直接说它的优点:
- 毫秒数在高位,自增序列在低位,整个ID都是趋势递增的。
- 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成ID的性能也是非常高的。
- 可以根据自身业务特性分配bit位,非常灵活。
缺点:
- 强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。
MongDB的ObjectID可以算作是和snowflake类似方法,通过“时间+机器码+pid+inc”共12个字节,通过4+3+2+3的方式最终标识成一个24长度的十六进制字符。
美团开源的Leaf
支持多种不同模式的生成策略
- 号段模式:该模式需要建DB表, 需要有专门的服务来提供获取id的接口, 存在网络延迟
- Snowflake模式:为了追求更高的性能,需要通过RPC Server来部署Leaf服务,那仅需要引入leaf-core的包,把生成ID的API封装到指定的RPC框架中即可
缺点,可能就是相对来说比较复杂。
sharding-jdbc
sharding-jdbc是一个开源的主键生成组件。它的特点是简单易用,可以指定workerId或者不指定,直接通过jar的方式引入即可。看它的名字就知道,它需要DB支持。
uid-generator
uid-generator是百度开源的一个分布式ID生成器。需要建DB表,需要有专门的服务来提供获取id的接口,存在网络延迟。
现在就以我看到的而言,UUID是使用的比较多的,其他的用的相对较少,甚至有些程序员都不知道它们。
通过这些对比,我也就更深层次的了解了‘没有完美的技术’这句话。
好了,今天就到这了(`ヘ´)ノ☆(#>_<),掰掰。
版权属于:Citrons
本文链接:https://www.citrons.cn/jishu/233.html
转载时须注明出处及本声明