# tinyservices-id **Repository Path**: java-bigdata/tinyservices-id ## Basic Information - **Project Name**: tinyservices-id - **Description**: tinyservices-id 是一个高性能可扩展生成唯一id的服务。目前包含两种生成算法:雪花算法以及自增号段。 部署和使用都很便捷,无论是个人、团队、或是企业,都能够快速的使用 tinyservices-id 来生成唯一id。 - **Primary Language**: Java - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 9 - **Created**: 2022-04-27 - **Last Updated**: 2022-04-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # tinyservices-id ## 一、软件介绍 tinyservices-id 是一个高性能可扩展生成唯一id的服务。目前包含两种生成算法:雪花算法以及自增号段。 部署和使用都很便捷,无论是个人、团队、或是企业,都能够快速的使用 tinyservices-id 来生成唯一id。 ## 二、软件架构 ![tinyservices-id](tinyservices-id.png) - tinyservices-id 有两种id生成算法:基于美团leaf的号段算法以及基于推特推出的雪花算法 - 分为三大模块: - id-server:server端,封装id生成算法以及对外提供http服务,可直接通过http获取id - id-sdk:sdk包,可直接依赖sdk获取id,省去了获取id的网络开销,性能极佳 - id-portal:管理后台,通过管理后台新增/修改/删除的数据无需重启id-server服务,1分钟后可自动生效。每隔1分钟会自动同步数据到buffer中 - 雪花算法对中间件(MYSQL、ZOOKEEPER)弱依赖,每隔几秒会自动将中间件里的workerId刷到本地文件当中,这样即使中间件挂了的话也不影响id-server的正常使用,因为会自动降级到本地文件,因此也不会影响到业务系统 - 提供灵活配置以及可扩展能力,可自定义配置文件名称甚至无需配置文件,自定义实现类将配置放到配置中心。若雪花算法不希望用MYSQL或ZOOKEEPER,也可以自定义实现类进行实现,比如自定义ETCD等其他方式 ## 三、安装教程 ### 1、准备工作 #### 1.1 Java - 版本要求:1.8+,在配置好后可以通过如下命令检查: ```sh java -version ``` #### 1.2 MySQL - 版本要求:5.6.5+,连接上MySQL后,可以通过如下命令检查: ```mysql SHOW VARIABLES WHERE Variable_name = 'version'; ``` #### 1.3 下载 - 选择对应的发行版本下载代码,可以在如下链接进行下载: [https://gitee.com/tinyservices/tinyservices-id/releases](https://gitee.com/tinyservices/tinyservices-id/releases) ### 2、安装步骤 #### 2.1 创建数据库 - 通过MySQL客户端导入如下sql文件即可: ```sql scripts/sql/ts_id.sql ``` - 导入成功后执行以下sql语句来验证: ```sql use ts_id; show tables; ``` - sql执行结果如下则代表正常: ```sql ts_id_segment ts_id_token ts_id_worker_id ``` #### 2.2 配置数据库 - 根据不同环境修改不同的配置值(`dev/test/pre/prod`),所修改文件的位置如下: ```sh scripts/build.sh ``` - `scripts/build.sh`配置含义如下: | 配置项 | 配置含义 | 是否必填 | 默认值 | | :------------------------------: | :----------------------------------------------------------: | -------- | :-----------------------------------: | | id_server_config_db_driver | jdbc的driver | 必填 | 无 | | id_server_config_db_url | jdbc的url | 必填 | 无 | | id_server_config_db_username | mysql用户名 | 必填 | 无 | | id_server_config_db_password | mysql密码 | 必填 | 无 | | id_server_config_db_initial_size | 链接池初始化大小,不写则采取默认值 | 非必填 | 0 | | id_server_config_db_min_idle | 链接池最小空闲连接数,不写则采取默认值 | 非必填 | 0 | | id_server_config_db_max_active | 链接池最大活跃数,不写则采取默认值 | 非必填 | 8 | | id_server_config_db_max_wait | 链接池获取连接的最大等待时间,单位ms,不写则采取默认值 | 非必填 | -1 | | id_snowflake_mode | 雪花算法模式:
LOCAL(本地文件的方式)
MYSQL(对应`ts_id_worker_id`表)
ZOOKEEPER(每次都根据`ip:port`创建一个顺序持久节点)
RECYCLABLE_ZOOKEEPER(如果`ip:port`经常变的话那1023个workerId很容易就被耗光,此种方式是可循环利用workerId的ZOOKEEPER方式) | 非必填 | LOCAL | | id_snowflake_port | 雪花算法端口,不管采取何种方式,都会根据`ip:port`生成唯一key与workerId一一对应。
注:不会真正启动端口,只是作为唯一标识,所以和项目端口可重叠。 | 非必填 | 8080 | | id_snowflake_epoch | 雪花算法epoch,起始值,默认值:1648742400000L | 非必填 | 1648742400000L(2022-04-01 00:00:00) | | id_snowflake_zkConnectionAddr | 如果雪花算法采取ZOOKEEPER或RECYCLABLE_ZOOKEEPER模式,则需要配置ZOOKEEPER地址, | 非必填 | localhost:2181 | | id_server_log_dir | id-server项目日志目录 | 必填 | 无 | | id_portal_log_dir | id-portal项目日志目录 | 必填 | 无 | | id_server_port | id-server项目端口号 | 非必填 | 8080 | | id_portal_port | id-portal项目端口号 | 非必填 | 8080 | ## 四、部署运行 ### 1. 部署运行 #### 1.1 编译打包 - 可直接运行修改后的`scripts/build.sh`文件,比如: ```sh sh scripts/build.sh dev id-server sh scripts/build.sh dev id-portal ``` > 可选参数: > > $1:dev/test/pre/prod,分别代表开发环境/测试环境/预生产环境/生产环境。 > > $2:id-server/id-portal,分别代表id-server/id-portal两个moudle,也就是给哪个moudle打包,配置就是上面所输入dev/test/pre/prod所对应的变量。 #### 1.2 运行 - 编译打包完成后,可直接执行启动脚本,如下: ```sh sh id-server/scripts/startup.sh sh id-portal/scripts/startup.sh ``` - 验证id-server是否启动成功(也可以通过看日志的方式,日志位置就是`id_server_log_dir`对应的值) ```shell curl http(s)://ip:port/health/check ``` 返回如下代表成功: ```json { "code": 0, "msg": "Processed successfully", "data": 666 } ``` - 验证id-portal是否启动成功(也可以通过看日志的方式,日志位置就是`id_portal_log_dir`对应的值) 直接浏览器打开`http(s)://ip:port`,会出现如下页面: ![id-portal](id-portal.png) ## 五、使用说明 ### 1. 准备工作 - token是鉴权的唯一方式。所以需要在`id-portal`管理后台创建好token和业务类型的对应关系。 - 如果是号段模式的话,则需要在`id-portal`管理后台创建好Segment。 - 以上两种添加方式操作完无需重启服务,会有定时任务每一分钟去查数据库将其缓存到内存中,这样获取id的时候直接可用。 使用上有两种使用方式,分别是Server和Sdk,Server的使用很简单,直接对外提供获取id的http接口。Sdk则需要业务系统依赖jar包然后调用方法获取id。下面详细介绍下二者使用方式和区别。 ### 2. Server 不管获取哪种算法的id,都需要添加如下header,否则会提示-4错误码,代表没权限: ```properties tinyservice-id-token=token(token由id-portal管理后台Token菜单获取) ``` #### 2.1 获取号段id ```` # 获取单个 GET http(s)://ip:port/segment/{业务类型} # 批量获取 GET http(s)://ip:port/segment/{业务类型}/{获取的id数量} ```` #### 2.2 获取雪花id ``` # 获取单个 GET http(s)://ip:port/snowflake/{业务类型} # 批量获取 GET http(s)://ip:port/snowflake/{业务类型}/{获取的id数量} ``` ### 3. Sdk #### 3.1 添加依赖 ```xml com.gitee.tinyservices id-sdk 1.0.0 ``` #### 3.2 添加配置 在`classpath`(`springboot`项目通常为`resources`)下添加名为`tinyservices_id_sdk.properties`的配置文件,包含如下配置项: ```properties # id-server的地址,多个用英文逗号隔开,会随机选择一个地址使用 tinyservices.id.server=http://localhost:9990 # 要访问业务类型的token。可在id-portal管理后台配置/查看 tinyservices.id.token=U2FsdGVkX18uip/K7pLiM4ZD5RKrHacD64eKWCNfmW4= ``` #### 3.3 获取id ```java // IdSdkTypeEnum.SEGMENT 号段模式 // IdSdkTypeEnum.SNOWFLAKE 雪花模式 AbstractIdSdk idSdk = IdSdkFactory.getInstance().getIdSdk(IdSdkTypeEnum.SEGMENT).registerConfigSupport(); // 获取id for (int i = 0; i < 10; i ++) { Long id = idSdk.getId("业务类型"); } ``` #### 3.4 全部配置 | 配置项 | 配置含义 | 是否必填 | 默认值 | | :-----------------------------: | :----------------------------------------------------------: | :------: | :-----------------------------------: | | tinyservices.id.token | token,可从id-portal管理后台配置/查看 | 必填 | 无 | | tinyservices.id.server | id-server服务列表,多个用逗号隔开,比如:http://localhost:9990 | 必填 | 无 | | tinyservices.id.readTimeout | sdk和server的超时时间(ms) | 非必填 | 5000ms | | tinyservices.id.connectTimeout | sdk和server的连接超时时间(ms) | 非必填 | 5000ms | | tinyservices.id.snowflake.epoch | 雪花算法的开始时间戳 | 非必填 | 1648742400000L(2022-04-01 00:00:00) | ### 4. 使用建议 Segment模式根据自身业务量规划好步长,比如业务QPS是10000,步长写了10,那可能瞬时流量进来的话会获取到少部分id为null的情况,因为步长太小,双buffer都被瞬时流量打满。 如果对性能有极高要求的话,推荐Sdk方式,此方式直接依赖jar包调用本地方法的方式生成id,由于Sdk的方式免去了网络开销,理论上QPS可达千万。 如果对性能要求不高的话可以使用Server方式,直接请求http接口,减少系统依赖。 ## 六、FAQ ### 1. 如何在本地运行? 给项目添加对应环境变量即可,IDEA添加环境变量的方式如下: ![add-env](add-env.png) #### 1.1 id-server 添加如下环境变量: ```properties spring.datasource.driver=com.mysql.cj.jdbc.Driver;spring.datasource.url=jdbc:mysql://localhost:3306/ts_id?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT;spring.datasource.username=root;spring.datasource.password=12345678;spring.datasource.initial-size=;spring.datasource.min-idle=;spring.datasource.max-active=;spring.datasource.max-wait=;id_server_log_dir=/data/logs/id-server;server_port=9990;id_server_snowflake_mode=MYSQL;id_server_snowflake_port=8888;id_server_snowflake_epoch=1648742400000;id_server_snowflake_zkConnectionAddr=localhost:2181 ``` > 数据库连接、用户名、密码、端口等等参数都根据自身环境自行修改即可。 #### 1.2 id-portal 添加如下环境变量: ```properties spring.datasource.driver=com.mysql.cj.jdbc.Driver;spring.datasource.url=jdbc:mysql://localhost:3306/ts_id?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT;spring.datasource.username=root;spring.datasource.password=12345678;spring.datasource.initial-size=;spring.datasource.min-idle=;spring.datasource.max-active=;spring.datasource.max-wait=;id_portal_log_dir=/data/logs/id-portal;server_port=9990 ``` > 数据库连接、用户名、密码、端口等等参数都根据自身环境自行修改即可。 ### 2. id-portal添加配置后多久生效? 不管是Segment还是Token方式,新增或修改配置后都是一分钟生效,也就是一分钟后id-server服务可用这份配置。 ### 3. 雪花算法如何自定义注册中心? 目前内置四种模式:LOCAL本地文件模式、MYSQL模式、ZOOKEEPER模式以及RECYCLABLE_ZOOKEEPER可回收利用workerId的ZOOKEEPER模式,若想采用其他中间件作为注册中心,那么如下步骤: - 首先自定义一个`Class`继承`AbstractIdSnowflakeHolder`类且重写相应的方法,可参考其他子类,比如:`ZookeeperIdSnowflakeHolder` - 其次在枚举类`IdSnowflakeHolderTypeEnum`当中新增相应类型(此类型必须和配置文件里的`tinyservices.id.snowflake.mode`配置一一对应) - 最后修改工厂类的方法`IdSnowflakeHolderFactory#getIdSnowflakeHolder`,为其新增`case`分支,值为新增的枚举类型 ### 4. 雪花算法采取的是RECYCLABLE_ZOOKEEPER模式,启动很慢? RECYCLABLE_ZOOKEEPER模式首次启动慢正常的,此模式会在启动的时候提前在Zookeeper创建1023个持久节点作为workerId池,利于workerId的复用。因为是持久节点,所以只有首次创建会很慢,之后启动会发现已存在1023个持久节点则不再重复创建。 ### 5. MySQL驱动报错问题 如项目启动过程中出现MySQL驱动错误的话,则自行按需修改版本号,目前内置版本是8.0.21,在根`pom.xml`文件中。如下: ```xml mysql mysql-connector-java 8.0.21 runtime ``` > 修改后再打包的时候别忘了修改`scripts/build.sh`里的`id_server_config_db_driver`配置。 > > 若是本地部署代码运行的话则别忘了修改环境变量里的`id_server_config_db_driver`配置。 ### 6. Sdk模式配置文件如何修改名称? 如果不想采取默认的配置文件名称`tinyservices_id_sdk.properties`,那可以采取如下方式进行自定义: ```java AbstractIdSdk idSdk = IdSdkFactory.getInstance().getIdSdk(IdSdkTypeEnum.SNOWFLAKE, "自定义配置文件名称.properties").registerConfigSupport(); // 获取id for (int i = 0; i < 10; i ++) { Long id = idSdk.getId("业务类型"); } ``` ### 7. Sdk模式如何将配置放到注册中心? 如果不想采取配置文件的方式,公司规范都放到配置中心该怎么办?可以采取如下方式进行自定义: #### 7.1 自定义配置类 ```java /** * 可选择性重写如下五个方法: * String getBizToken(); * String getServerUrl(); * int getReadTimeout(); * int getConnectTimeout(); * long getEpoch(); */ public class CustomIdConfigSupport extends AbstractIdConfigSupport { @Override public String getServerUrl() { // 可通过配置中心获取 return null; } @Override public String getBizToken() { // 可通过配置中心获取 return null; } // ... 省略其他非必需重写的方法 } ``` #### 7.2 注册配置类 ```java AbstractIdSdk idSdk = IdSdkFactory.getInstance().getIdSdk(IdSdkTypeEnum.SNOWFLAKE).registerConfigSupport(new CustomIdConfigSupport()); // 获取id for (int i = 0; i < 10; i ++) { Long id = idSdk.getId("业务类型"); } ``` ### 8. Sdk模式如何获取不同业务类型的id? 背景:sdk方式一个配置文件只允许配置一个token,若一个项目想获取不同业务类型的token该如何获取呢? 解答:有两种方式可以解决: 1. 一个业务类型支持配置多个token,可以将不同业务类型都配置一个公共的token,后台目前只允许生成token,不允许自定义token,如需这么做可以二开下`id-portal`,放开token禁止输入的限制,也可以手动修改`ts_id_worker_id`表数据。 2. 或者采取自定义配置文件的方式,比如要获取两个业务类型的id: 第一个业务类型: ```java AbstractIdSdk idSdk = IdSdkFactory.getInstance().getIdSdk(IdSdkTypeEnum.SEGMENT, "sdk_1.properties").registerConfigSupport(); idSdk.getId("test1"); ``` 第二个业务类型: ```java AbstractIdSdk idSdk = IdSdkFactory.getInstance().getIdSdk(IdSdkTypeEnum.SEGMENT, "sdk_2.properties").registerConfigSupport(); idSdk.getId("test2"); ``` ## 七、鸣谢 - 美团:[https://github.com/Meituan-Dianping/Leaf](https://github.com/Meituan-Dianping/Leaf) - 滴滴:[https://github.com/didi/tinyid](https://github.com/didi/tinyid) ## 八、结束语 - 若贵司接入了`tinyservices-id`,欢迎私信/评论贵司名称,您的支持是我永恒的动力。 - 如有任何问题请提issue。[https://gitee.com/tinyservices/tinyservices-id/issues](https://gitee.com/tinyservices/tinyservices-id/issues)