大佬的总结:https://segmentfault.com/a/1190000022717820

    image.png

    做个表格汇总一下

    方式 生成方式 优点 缺点 是否推荐
    UUID jdk自带
    - 生成足够简单,本地生成无网络消耗,具有唯一性

    - 无序的字符串,不具备趋势自增特性
    - 没有具体的业务含义
    - 长度过长16 字节128位,36位长度的字符串,存储以及查询对MySQL的性能消耗较大,MySQL官方明确建议主键要尽量越短越好,作为数据库主键 UUID 的无序性会导致数据位置频繁变动,严重影响性能。
    基于数据库自增ID 基于数据库的auto_increment自增ID
    - 实现简单,ID单调自增,数值类型查询速度快

    - DB单点存在宕机风险,无法扛住高并发场景
    基于数据库集群模式 设置起始值和自增步长
    - 解决DB单点问题

    - 不利于后续扩容,而且实际上单个数据库自身压力还是大,依旧无法满足高并发场景。
    基于Redis模式 利用redis的 incr命令实现ID的原子性自增
    - 效率高
    - 具有隔离性

    - 需要考虑redis持久化的问题
    - RDB会定时打一个快照进行持久化,假如连续自增但redis没及时持久化,而这会Redis挂掉了,重启Redis后会出现ID重复的情况。
    - AOF会对每条写命令进行持久化,即使Redis挂掉了也不会出现ID重复的情况,但由于incr命令的特殊性,会导致Redis重启恢复的数据时间过长。
    基于雪花算法 见下
    百度(uid-generator) 基于Snowflake算法实现的,与原始的snowflake算法不同在于,uid-generator支持自定义时间戳、工作机器ID和 序列号 等各部分的位数,而且uid-generator中采用用户自定义workId的生成策略。
    美团(Leaf) 同时支持号段模式和snowflake算法模式,可以切换使用
    滴滴(Tinyid) 基于号段模式原理实现的与Leaf如出一辙

    雪花算法
    image.png
    Snowflake ID组成结构:正数位(占1比特)+ 时间戳(占41比特)+ 机器ID(占5比特)+ 数据中心(占5比特)+ 自增值(占12比特),总共64比特组成的一个Long类型。

    • 第一个bit位(1bit):Java中long的最高位是符号位代表正负,正数是0,负数是1,一般生成ID都为正数,所以默认为0。
    • 时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L _60 _60 _24 _365) = 69年
    • 工作机器id(10bit):也被叫做workId,这个可以灵活配置,机房或者机器号组合都可以。
    • 序列号部分(12bit),自增值支持同一毫秒内同一个节点可以生成4096个ID