背景

我们大致了解常见分布式id有9种解决方案如下:

  1. Redis自增id
  2. UUID
  3. 数据库id
  4. 多主数据库id
  5. 分段id
  6. snowflake
  7. 基于snowflake的百度 uid-generator
  8. 基于snowflake的美团 leaf
  9. 滴滴的分段 tinyId

基于高可用,高性能,简单易用性,使用tinyId和学习tinyId源码.
关于tinyid,并不是滴滴官方产品,只是滴滴拥有的代码。

tinyId-官方wiki


代码行数统计

简单使用


## git原版
git clone https://github.com/didi/tinyid.git

## cnpmjs 加速版本
git clone https://github.com.cnpmjs.org/didi/tinyid.git

源码分析点

  1. 项目模块 tinyid-base tinyid-client tinyid-server 之间的关系
tinyid-base 
1. SegmentId 中定义了号段核心实体,用于获取nextId()
2. 定义公用的 IdGeneratorFactory,IdGenerator,SegmentIdService 接口,让client和server实现其各自方法。

tinyid-server 是部署分布式id服务的

tinyid-server是java client,需要自己install到本地,官方没有发布到maven仓库
  1. client IdGenerator 是如何保证高性能,高可用的
1. 高性能,不论调用的是nextId还是batch方法,本质是在本地生成的,如果超出了本地生成策略。去服务器获取Segment段的长度. 不必每次发送http请求获取。
2. 高可用,客户端在resource配置 tinyid_client.properties文件,其参数 tinyid.server =>
#(tinyid.server=localhost:9999/gateway,ip2:port2/prefix,...)  用逗号分隔,达到负载均衡的效果。
详情可看源码 com.xiaoju.uemc.tinyid.client.factory.impl.IdGeneratorFactoryClient#init
当获取新的segment时会choose,算法是 random

  1. 服务器如何搭建集群
为了防止服务端挂掉产生的单点问题。导致服务不可用,遂需要搭建集群,直接搭建多节点就行。

关于mysql的多主数据源问题=> com.xiaoju.uemc.tinyid.base.entity.SegmentId#init

如果你有多个数据源达到数据库的高可用,需要配置数据库 delta=数据库个数
remainder 从0按顺序递增


    /**
     * 这个方法主要为了1,4,7,10...这种序列准备的
     * 设置好初始值之后,会以delta的方式递增,保证无论开始id是多少都能生成正确的序列
     * 如当前是号段是(1000,2000],delta=3, remainder=0,则经过这个方法后,currentId会先递增到1002,之后每次增加delta
     * 因为currentId会先递增,所以会浪费一个id,所以做了一次减delta的操作,实际currentId会从999开始增,第一个id还是1002
     */
    public void init() {
        if (isInit) {
            return;
        }
        synchronized (this) {
            if (isInit) {
                return;
            }
            long id = currentId.get();
            if (id % delta == remainder) {
                isInit = true;
                return;
            }
            for (int i = 0; i <= delta; i++) {
                id = currentId.incrementAndGet();
                if (id % delta == remainder) {
                    // 避免浪费 减掉系统自己占用的一个id
                    currentId.addAndGet(0 - delta);
                    isInit = true;
                    return;
                }
            }
        }
    }
  1. tinyid-server 中是如何建立多数据源的
核心是 => org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource

在读取envionment配置时,没见过的一个用法是 RelaxedPropertyResolver,可以根据前缀获取信息
  1. tinyid-server的maven profiles配置学习
    <profiles>
        <profile>
            <id>online</id>
            <properties>
                <package.environment>online</package.environment>
            </properties>
        </profile>
        <profile>
            <id>offline</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <package.environment>offline</package.environment>
            </properties>
        </profile>
    </profiles>

    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/resources/${package.environment}</directory>
            </resource>
            <resource>
                <directory>src/main/resources/base</directory>
            </resource>
        </resources>
    </build>

不过貌似一般不这么用V