Snowflake 雪花算法
为什么使用雪花算法?❄️
在复杂的系统中,往往需要对大量的数据如订单,账户进行标识,以一个有意义的有序的序列号来作为全局唯一的ID,即需要一个ID号生成器
。
ID号生成器是服务端系统的基础设施,而且ID号
这个东西基本搞后端开发的程序员天天都要接触。而关于ID生成的算法
现在业界首屈一指的当属Snowflake
雪花算法。
常见企业级使用的方案
1. UUID
UUID = 4个连字号(-) + 32个字节长的字符串,总共36个字节长。比如:
550e8400-e29b-41d4-a716-446655440000
优点:
- 能够保证
独立性
。 - 程序可以在不同的
数据库间迁移
,效果不受影响。
缺点:
- 不易于存储 / 性能问题:UUID太长,128位、36长度字符,不利于Mysql索引(在InnoDB引擎下,
UUID的无序性
可能会引起数据位置频繁变动,严重影响性能
),很多场景不适用。 - 采用
无意义字符串
,数据量增大时造成访问过慢,且不宜排序
。 - 信息不安全:基于MAC地址生成UUID的算法可能会造成MAC地址泄露,这个漏洞曾被用于寻找梅丽莎病毒的制作者位置。
2. 基于数据库方案
自增ID:对于数据敏感场景不宜使用,且不适合于分布式场景
。
优点:
- 简单,成本小
- ID号单调自增,可以实现一些对ID有特殊要求的业务。
缺点:
- 不同
数据库
语法和实现不同,数据库迁移
的时候或多数据库版本
支持的时候需要处理。 - 如果涉及多个系统需要合并或者数据迁移会比较麻烦。
3. 雪花算法
算法描述:
- 最高位是符号位,始终为0,不可用。
- 41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据
时间
进行排序
。 - 10位的
机器
标识,10位的长度最多支持部署
1024个节点。 - 12位的计数序列号,序列号即一系列的
自增id
,可以支持同一节点
同一毫秒生成多个ID
序号,12位
的计数序列号支持每个节点每毫秒产生4096个
ID序号。
UidGenerator
是百度开源的一款基于Snowflake
雪花算法实现的高性能唯一ID生成器。以下是再进行封装的一套更利于Spring Boot项目使用的ID号生成组件,命名为id-spring-boot-starter。
在 Spring Boot 项目中的用法
- 导入SQL脚本
1 | DROP TABLE IF EXISTS WORKER_NODE; |
UidGenerator需要数据库支持
- pom中加入依赖
1 | <dependency> |
- 配置数据库连接
1 | url: jdbc:mysql://xxx.xxx.xxx.xxx:3306/demo?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useOldAliasMetadataBehavior=true&connectionCollation=utf8mb4_unicode_ci&rewriteBatchedStatements=true&allowMultiQueries=true |
- 修改 Spring Boot 主类
Spring Boot应用主类上加上mybatis注解即可:
1 |
|
- 首先用 Autowired的方式引入UidGenService类;
- 直接调用UidGenService类的getUid()方法即可获得一个Long型的ID号
为什么叫雪花算法
呢?私以为众所周知世界上没有一对相同的雪花,而雪花形成的过程中复杂的环境条件则对应了雪花算法中的机器ID,时间戳在现实层面上能够精确到普朗克时间10^-43s,这样时间戳的长度也得以保证。