内容简介:CosId 通用、灵活、高性能的分布式 ID 生成器 介绍 CosId 旨在提供通用、灵活、高性能的分布式系统 ID 生成器。 目前提供了俩大类 ID 生成器:SnowflakeId (单机 TPS 性能:409W/s JMH 基准测试)、RedisIdGene...
CosId 通用、灵活、高性能的分布式 ID 生成器
介绍
CosId 旨在提供通用、灵活、高性能的分布式系统 ID 生成器。 目前提供了俩大类 ID 生成器:SnowflakeId (单机 TPS 性能:409W/s JMH 基准测试)、RedisIdGenerator (单机 TPS 性能(步长 1000):3687W+/s JMH 基准测试)。
更新内容(1.0.0) ???? ???? ????
- 增强:支持自定义配置 ClockBackwardsSynchronizer(spring-boot-starter-cosid)。
- 增强:优化 SnowflakeIdProperties 配置体验 (spring-boot-starter-cosid)。
- 变更:重命名 LocalMachineState 为 MachineStateStorage。
- 增强:支持自定义 IdDefinition 来开启 ClockSyncSnowflakeId。
- 增强:优化自定义配置 epoch 。
- 增强:支持配置 RedisIdGenerator#offset ,来设置分布式ID起始值。
- 新增:新增 SnowflakeFriendlyId,生成更具可读性的 SnowflakeIdState。
- 增强:自定义配置 Redis#timeout。
SnowflakeId

SnowflakeId 使用
Long(64 bits) 位分区来生成 ID 的一种分布式 ID 算法。
通用的位分配方案为:timestamp(41 bits) +machineId(10 bits) +sequence(12 bits) = 63 bits 。
- 41 位
timestamp= (1L<<41)/(1000/3600/365) 约可以存储 69 年的时间戳,即可以使用的绝对时间为EPOCH+ 69 年,一般我们需要自定义EPOCH为产品开发时间,另外还可以通过压缩其他区域的分配位数,来增加时间戳位数来延长可用时间。 - 10 位
machineId= (1L<<10) = 1024 即相同业务可以部署 1024 个副本 (在 Kubernetes 概念里没有主从副本之分,这里直接沿用 Kubernetes 的定义) 实例,一般情况下没有必要使用这么多位,所以会根据部署规模需要重新定义。 - 12 位
sequence= (1L<<12) * 1000 = 4096000 即单机每秒可生成约 409W 的 ID,全局同业务集群可产生 4096000*1024=419430W=41.9亿(TPS)。
从 SnowflakeId 设计上可以看出:
-
timestamp在高位,所以 SnowflakeId 是本机单调递增的,受全局时钟同步影响 SnowflakeId 是全局趋势递增的。 - SnowflakeId 不对任何第三方中间件有强依赖关系,并且性能也非常高。
- 位分配方案可以按照业务系统需要灵活配置,来达到最优使用效果。
- 强依赖本机时钟,潜在的时钟回拨问题会导致 ID 重复。
-
machineId需要手动设置,实际部署时如果采用手动分配machineId,会非常低效。
CosId-SnowflakeId 主要解决 SnowflakeId 俩大问题:机器号分配问题、时钟回拨问题。 并且提供更加友好、灵活的使用体验。
MachineIdDistributor (MachineId 分配器)
目前 CosId 提供了以下三种
MachineId分配器。
ManualMachineIdDistributor
cosid:
snowflake:
machine:
distributor:
type: manual
manual:
machine-id: 0
手动分配
MachineId
StatefulSetMachineIdDistributor
cosid:
snowflake:
machine:
distributor:
type: stateful_set
使用
Kubernetes的StatefulSet提供的稳定的标识 ID 作为机器号。
RedisMachineIdDistributor
cosid:
snowflake:
machine:
distributor:
type: redis
使用
Redis作为机器号的分发存储。
ClockBackwardsSynchronizer (时钟回拨同步器)
cosid:
snowflake:
clock-backwards:
spin-threshold: 10
broken-threshold: 2000
默认提供的 DefaultClockBackwardsSynchronizer 时钟回拨同步器使用主动等待同步策略,spinThreshold(默认值 10 毫秒) 用于设置自旋等待阈值, 当大于spinThreshold时使用线程休眠等待时钟同步,如果超过brokenThreshold(默认值 2 秒)时会直接抛出ClockTooManyBackwardsException异常。
MachineStateStorage (机器状态存储)
public class MachineState {
public static final MachineState NOT_FOUND = of(-1, -1);
private final int machineId;
private final long lastTimeStamp;
public MachineState(int machineId, long lastTimeStamp) {
this.machineId = machineId;
this.lastTimeStamp = lastTimeStamp;
}
public int getMachineId() {
return machineId;
}
public long getLastTimeStamp() {
return lastTimeStamp;
}
public static MachineState of(int machineId, long lastStamp) {
return new MachineState(machineId, lastStamp);
}
}
cosid:
snowflake:
machine:
state-storage:
local:
state-location: ./cosid-machine-state/
默认提供的 LocalMachineStateStorage 本地机器状态存储,使用本地文件存储机器号、最近一次时间戳,用作 MachineState 缓存。
ClockSyncSnowflakeId (主动时钟同步 SnowflakeId)
cosid:
snowflake:
share:
clock-sync: true
默认 SnowflakeId 当发生时钟回拨时会直接抛出 ClockBackwardsException 异常,而使用 ClockSyncSnowflakeId 会使用 ClockBackwardsSynchronizer主动等待时钟同步来重新生成 ID,提供更加友好的使用体验。
SafeJavaScriptSnowflakeId (JavaScript 安全的 SnowflakeId)
SnowflakeId snowflakeId=SafeJavaScriptSnowflakeId.ofMillisecond(1);
JavaScript 的 Number.MAX_SAFE_INTEGER 只有 53 位,如果直接将 63 位的 SnowflakeId 返回给前端,那么会值溢出的情况,通常我们可以将SnowflakeId转换为 String 类型或者自定义 SnowflakeId 位分配来缩短 SnowflakeId 的位数 使 ID 提供给前端时不溢出。
SnowflakeFriendlyId (可以将 SnowflakeId 解析成可读性更好的 SnowflakeIdState )
cosid:
snowflake:
share:
friendly: true
public class SnowflakeIdState {
private final long id;
private final int machineId;
private final long sequence;
private final LocalDateTime timestamp;
/**
* {@link #timestamp}-{@link #machineId}-{@link #sequence}
*/
private final String friendlyId;
}
public interface SnowflakeFriendlyId extends SnowflakeId {
SnowflakeIdState friendlyId(long id);
SnowflakeIdState ofFriendlyId(String friendlyId);
default SnowflakeIdState friendlyId() {
long id = generate();
return friendlyId(id);
}
}
SnowflakeFriendlyId snowflakeFriendlyId = new DefaultSnowflakeFriendlyId(snowflakeId);
SnowflakeIdState idState = snowflakeFriendlyId.friendlyId();
idState.getFriendlyId(); //20210623131730192-1-0
RedisIdGenerator
cosid:
redis:
enabled: true
share:
offset: 0
step: 100
provider:
bizA:
offset: 10000
step: 100
bizB:
offset: 10000
step: 100
RedisIdGenerator 步长设置为 1 时(每次生成ID都需要执行一次 Redis 网络 IO 请求)TPS 性能约为 21W/s (JMH 基准测试),如果在部分场景下我们对 ID 生成的 TPS 性能有更高的要求,那么可以选择使用增加每次ID分发步长来降低网络 IO 请求频次,提高 IdGenerator性能(比如增加步长为 1000,性能可提升到 3545W+/s JMH 基准测试)。
IdGeneratorProvider
cosid:
snowflake:
provider:
bizA:
# epoch:
# timestamp-bit:
sequence-bit: 12
bizB:
# epoch:
# timestamp-bit:
sequence-bit: 12
IdGenerator idGenerator = idGeneratorProvider.get("bizA");
在实际使用中我们一般不会所有业务服务使用同一个 IdGenerator ,而是不同的业务使用不同的 IdGenerator,那么 IdGeneratorProvider就是为了解决这个问题而存在的,他是 IdGenerator 的容器,可以通过业务名来获取相应的 IdGenerator。
Examples
安装
Gradle
Kotlin DSL
val cosidVersion = "1.0.0";
implementation("me.ahoo.cosid:spring-boot-starter-cosid:${cosidVersion}")
Maven
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>demo</artifactId>
<properties>
<cosid.version>1.0.0</cosid.version>
</properties>
<dependencies>
<dependency>
<groupId>me.ahoo.cosid</groupId>
<artifactId>spring-boot-starter-cosid</artifactId>
<version>${cosid.version}</version>
</dependency>
</dependencies>
</project>
application.yaml
cosid:
namespace: ${spring.application.name}
snowflake:
enabled: true
# epoch: 1577203200000
clock-backwards:
spin-threshold: 10
broken-threshold: 2000
machine:
# stable: true
# machine-bit: 10
# instance-id: ${HOSTNAME}
distributor:
type: redis
# manual:
# machine-id: 0
state-storage:
local:
state-location: ./cosid-machine-state/
share:
clock-sync: true
friendly: true
provider:
bizA:
# timestamp-bit:
sequence-bit: 12
bizB:
# timestamp-bit:
sequence-bit: 12
# redis:
# enabled: false
# share:
# offset: 0
# step: 100
# provider:
# bizA:
# offset: 10000
# step: 100
# bizB:
# offset: 10000
# step: 100
JMH-Benchmark
SnowflakeId
Benchmark Mode Cnt Score Error Units
SnowflakeIdBenchmark.millisecondSnowflakeId_generate thrpt 4093924.313 ops/s
SnowflakeIdBenchmark.safeJsMillisecondSnowflakeId_generate thrpt 511542.292 ops/s
SnowflakeIdBenchmark.safeJsSecondSnowflakeId_generate thrpt 511939.629 ops/s
SnowflakeIdBenchmark.secondSnowflakeId_generate thrpt 4204761.870 ops/s
RedisIdGenerator
gradle cosid-redis:jmh
Benchmark Mode Cnt Score Error Units
RedisIdGeneratorBenchmark.step_1 thrpt 25 220218.848 ± 2070.786 ops/s
RedisIdGeneratorBenchmark.step_100 thrpt 25 3605422.967 ± 13479.405 ops/s
RedisIdGeneratorBenchmark.step_1000 thrpt 25 36874696.252 ± 357214.292 ops/s
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Practical Django Projects, Second Edition
James Bennett / Apress / 2009 / 44.99
Build a django content management system, blog, and social networking site with James Bennett as he introduces version 1.1 of the popular Django framework. You’ll work through the development of ea......一起来看看 《Practical Django Projects, Second Edition》 这本书的介绍吧!
