0%

全局唯一ID

分布式系统定义:一个硬件或软件组件分布在不同的网络计算机上,彼此之间通过消息传递进行通信和协调的系统。

一、概念

      随着应用业务的复杂,用户量的增长,单机部署已经不能满足现有的需求了,随之而来的就是在数据库层分库、分表,以及分布式部署应用等。全局唯一ID,其实就是在分布式应用中唯一标识某条记录的ID。生成全局唯一ID有两个基本要求:全局唯一性、趋势有序性。

ID生成系统的需求

  1. 全局唯一性:不能出现重复的ID,最基本的要求。
  2. 趋势递增:MySQL InnoDB引擎使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数据,在主键的选择上面我们应尽量使用有序的主键保证写入性能。
  3. 单调递增:保证下一个ID一定大于上一个ID。
  4. 信息安全:如果ID是连续递增的,恶意用户就可以很容易的窥见订单号的规则,从而猜出下一个订单号,如果是竞争对手,就可以直接知道我们一天的订单量。所以在某些场景下,需要ID无规则。

二、常见算法

  1. uuid

    • 生成足够简单,本地生成无网络消耗,具有唯一性
    • 无序的字符串,不具备趋势自增特性
    • 没有具体的业务含义
  2. 数据库自增id

    • 实现简单,ID单调自增,数值类型查询速度快
    • DB单点存在宕机风险,无法扛住高并发场景
  3. 数据库多主模式

    • 分别设置起始值和自增步长
    • 可以解决DB单点问题
    • 不利于后续扩容,高并发下单个数据库自身压力大
  4. 号段模式

    • 从数据库批量的获取自增ID如1~1000并缓存在本地,减少数据库请求次数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    CREATE TABLE id_generator (
    id int(10) NOT NULL,
    max_id bigint(20) NOT NULL COMMENT '当前最大id',
    step int(20) NOT NULL COMMENT '号段的布长',
    biz_type int(20) NOT NULL COMMENT '业务类型',
    version int(20) NOT NULL COMMENT '版本号',
    PRIMARY KEY (`id`)
    )
    biz_type:不同业务类型
    max_id:当前最大的可用id
    step:号段的长度
    version:乐观锁

    update id_generator set max_id = #{max_id+step}, version = version + 1 where version = # {version} and biz_type = XXX
  5. Redis

    • incr
  6. Mongo

1
2
3
4
5
6
function getUniqId() {
if (!class_exists('MongoDB\BSON\ObjectId')) {
throw new Exception("mongodb extension no exists");
}
return (string)(new MongoDB\BSON\ObjectId());
}
  1. 雪花算法
    • Snowflake ID组成结构:正数位(1比特)+时间戳(41比特)+workId(10比特)+自增值(12比特),总共64比特组成的一个Long类型ID。
  2. 滴滴TinyId
  3. 百度UidGenerator
  4. 美团Leaf

三、参考

  1. 参考一