分布式ID生成器-GeDid

原创
2021/07/05 10:24
阅读数 287

源起

​ 尝试设计实现一个分布式id工具,已是好几年前的事了,这里是历史的痕迹。

​ 最初实现了基于redis(jedis客户端)的版本,而后在19年左右,考虑接入Zookeeper版本的。但是一直没有着手去做。

​ 最近借助一次"翻新"的机会,把它又拿出来,考虑完成Zookeeper版本的实现。因spring-boot-x已经有了很多的基础,也便于Gedid在springboot环境下使用,与springboot的整合和利用已有的springboot资源,所以考虑把Gedid迁移至spring-boot-x,以至于进行了大量的改造。多次调整之后,变有了现在的结果。也有了这个文章的整理。

​ 这个文章目的:把Gedid的使用场景和使用方式道明白。

开始

引入依赖

<dependency>
    <groupId>org.openingo.spring</groupId>
    <artifactId>spring-boot-x</artifactId>
    <version>${spring-boot-x.version}</version>
</dependency>

在启动类上加入@EnableExtension

目前最新版本 maven

ID引擎

目前支持引擎如下:

  • EtcdIdEngine since v4.3.0 [ 2021.7.3更新 ]

    • 基于PutResponsePrev_Kvversion;
    • 对应的id类型是Long
    • 支持业务隔离,对应的businessName就是业务的标识;
    • 使用jetcd客户端;
    • etcd存储的数据key格式为:"gedid-{businessName}",可以通过此查询对应的数据; since v4.3.1
  • SnowflakeIdEngine since v4.3.0 [ 2021.7.3更新 ]

    • 对应的id类型是Long
    • 天然支持业务隔离;
  • RedisIdEngine

    • 基于redis的incr指令;
    • 对应的id类型是Long
    • 支持业务隔离,对应的businessName就是业务的标识;
    • 支持lettucejedis,默认为lettuce;
    • redis存储的数据key格式为:"gedid:{businessName}",可以通过此查询对应的数据; since v4.3.1
  • ZookeeperIdEngine

    • 基于CreateMode.PERSISTENT节点的version(ZookeeperIdEngineMode#DATA_VERSION)或zxmid(ZookeeperIdEngineMode#DATA_ZX_MID);可以注入不同的Bean配置使用的mode,如下:

      @Bean
      public ZookeeperIdEngineMode zookeeperIdEngineMode() {
        return ZookeeperIdEngineMode.DATA_ZX_MID;
      }
      
    • 对应的Id类型是Long

    • 支持业务隔离,对应的businessName就是业务的标识;

    • 使用curator客户端;

      使用ZookeeperIdEngineMode#DATA_VERSION时,对应id受限于integer类型的version的取值范围

      使用ZookeeperIdEngineMode#DATA_ZX_MID时,对应id可能会因为zk的重启出现较大范围的跳跃。

    • Zookeeper存储的path数据格式为:"/gedid-{businessName}",可以通过此查询对应的数据; since v4.3.1

  • UuidEngine

    • 基于java.util.UUID#randomUUID;
    • 对应id类型为String
    • 天然支持业务隔离;

使用

配置说明

  • EtcdIdEngine [ 2021.7.3更新 ]

    openingo:
      gedid:
        engine:
          etcd:
            endpoints: http://localhost:2379
            user: user
            password: password
    

    多个endpoint用英文,分割

  • SnowflakeIdEngine [ 2021.7.3更新 ]

    无需配置;默认workerIddataCenterId都是0L,可以通过重新注入SnowflakeIdEngine到SpringIoC的方式调整二者,二者取值均需<=31L

    	@Configuration
    	static class SnowflakeConfig {
    
    		@Bean
    		@ConditionalOnMissingBean
    		SnowflakeIdEngine snowflakeIdEngine() {
    			return new SnowflakeIdEngine(12L, 13L);
    		}
    	}
    
  • RedisIdEngine

    spring-boot-starter-data-redis配置类似,配置前缀为openingo.gedid.engine.redis

  • ZookeeperIdEngine

    spring-cloud-starter-zookeeper-discovery的配置类似,配置前缀为openingo.gedid.engine.zookeeper

  • UuidEngine

    无需配置

  • 配置示例

    openingo:
      gedid:
        engine:
          zookeeper:
            connect-string: localhost:2182
          redis:
            cluster:
              nodes: localhost:7291,localhost:7292,localhost:7293,localhost:7294,localhost:7295,localhost:7296
          etcd:
            endpoints: http://localhost:2379
            user: user
            password: password
    

    示例中使用了2182端口对应的zk,与默认的2181区分,目的是为了说明与默认配置的隔离;redis使用的集群配置。

    redis和Zookeeper的配置前缀与默认的配置完全隔离,目的是将业务使用的redis和Zookeeper和GeDid使用的redis、Zookeeper隔离开,如此配置不会造成业务与GeDid是相互影响。当然也可以配置成完全一样的服务器信息。

业务配置

  • 根据业务情况,参考如下配置DidLoader 【推荐】

    /**
     * IdLoaderConfig
     *
     * @author Qicz
     * @since 2021/6/24 16:03
     */
    @Configuration
    public class IdLoaderConfig implements DidLoaderConfigurer {
    
    	@Bean
    	public ZookeeperIdEngineMode zookeeperIdEngineMode() {
    		return ZookeeperIdEngineMode.DATA_ZX_MID;
    	}
    
    	@Override
    	public void configureDidLoader(DidLoader didLoader) {
    		// business abc
    		didLoader.follow("redis://abc");
    		// business a
    		didLoader.follow("redis", "a");
    		// business b
    		didLoader.follow("redis", "b");
    		// business zk
    		didLoader.follow("zookeeper", "zk");
    		// business uuid
    		didLoader.follow("uuid", "uuid");
    	}
    }
    
  • 业务中使用

    @Autowired
    DidLoader didLoader;
    
    didLoader.next(businessName);  // 下一个Id
    didLoad.nextToLong(businessName); // 下一个Long Id
    didLoad.nextToString(businessName); //下一个String Id
    
  • 动态配置DidLoader

    某些特定的情况,可能需要动态的配置业务的id生成,虽然推荐使用【推荐】方式配置,但仍旧提供了对应的支持。

    @Autowired
    DidLoader didLoader;
    
    this.didLoader.follow("redis", businessName);
    

高级使用

BusinessURI

在【推荐】中看到了如下的配置

didLoader.follow("redis://abc");

这是一种基于BusinessURI的配置方式。与标准URI语法完全一致,只是具体含义有些差异。以redis://abc举例:

  • URISchema

    示例中的redis即就是URI的Schema,在BusinessURI中,其对应着使用的具体IdEngine。比如redis即会使用engineNameredis的IDEngine。默认可用的Schema有redis,zookeeper,uuid分别对应着RedisIDEngine,ZookeeperIdEngine,UuidEngine

  • URIHost

    示例中的abc即就是URI的Host,在BusinessURI中,其对应着follow的businessName。这也是didLoader.next(businessName); 的基础。

自定义IdEngine

org.openingo.spring.extension.gedid.engine.IDidEngine定义了实现一个IdEngine的基本要素

/**
 * IDidEngine
 *
 * @author Qicz
 * @since 2021/6/25 10:48
 */
public interface IDidEngine<T> {

	String GEDID = "gedid";

	/**
	 * Follow The business with name.
	 * @param businessName business name
	 * @param startId the first id
	 */
	void follow(String businessName, T startId);

	/**
	 * get the embellished business name
	 * @param businessName the business name
	 * @return embellished business name
	 */
	default String getEmbellishedName(String businessName) {
		return businessName;
	}

	/**
	 * get fixed start id
	 *
	 * @param startId not all startId
	 * @return {@link T} default return startId self
	 */
	default T getFixedStartId(T startId) {
		return startId;
	}

	/**
	 * the next id
	 * @param businessName the business name
	 * @return Next id.
	 */
	T next(String businessName);

	/**
	 * throw onw unsupportedOperationException
	 * @param operation unsupported operation
	 */
	default void unsupportedOperation(String operation) {
		throw new UnsupportedOperationException(String.format("`%s` : The `%s` Operation is not supported!", this.engineName(), operation));
	}

	/**
	 * current engine's name
	 * @return the engine name
	 */
	String engineName();
}

engineName()可以随意定义除了默认Schema之外的任意的名称。

自定义IdEngine示例
/**
 * QiczEngine
 *
 * @author Qicz
 * @since 2021/6/25 17:41
 */
public class QiczEngine implements IDidEngine<String>  {

	@Override
	public void follow(String businessName, String startId) {

	}
  
  @Override
	public String getEmbellishedName(String businessName) {
		return businessName;
	}

	@Override
	public String getFixedStartId(String startId) {
		return "";
	}

	@Override
	public String next(String businessName) {
		return UUID.randomUUID().toString();
	}

	@Override
	public String engineName() {
		return "qicz";
	}
}

此处示例,以UUID为例。特别注意,自定义示例需要注入到SpringIoC才可以正常使用。

配置自定义IdEngine
/**
 * IdLoaderConfig
 *
 * @author Qicz
 * @since 2021/6/24 16:03
 */
@Configuration
public class IdLoaderConfig implements DidLoaderConfigurer {

	@Override
	public void configureDidLoader(DidLoader didLoader) {
		// business abc
		didLoader.follow("qicz://business-abcd");
    ...
	}
}

使用qicz引擎follow业务business-abcd

结语

至此,关于的GeDid目前的所有都在这里了。后续有变动将在本文中陆续更新。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部