1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/AhooWang-CosId

Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

CosId Универсальный, гибкий, высокопроизводительный генератор распределенных идентификаторов

Лицензия GitHub релиз Maven Central Codacy Badge codecov Статус интеграционного тестирования Задать вопрос DeepWiki

Документация на китайском

Введение*CosId*旨在提供一个通用、灵活且高性能的分布式ID生成器。- CosIdGenerator: Stand-alone производительность TPS: 15 570 085 операций/секунду, в три раза выше, чем у UUID.randomUUID(), глобальный тренд увеличения на основе времени.

  • SnowflakeId: Stand-alone производительность TPS: OnClickListener 4 096 000 операций/секунду JMH Benchmark, решает две основные проблемы SnowflakeId: проблему распределения номеров машин и проблему откатывания времени, и предоставляет более дружественный и гибкий опыт.
  • SegmentId: Получает ID сегмента (Step) каждый раз, чтобы уменьшить частоту запросов к сети IO дистрибьютора IdSegment и улучшить производительность.
    • IdSegmentDistributor:
      • RedisIdSegmentDistributor: Дистрибьютор IdSegment на основе Redis.
      • JdbcIdSegmentDistributor: Дистрибьютор IdSegment на основе JDBC, поддерживающий различные реляционные базы данных.
      • ZookeeperIdSegmentDistributor: Дистрибьютор IdSegment на основе Zookeeper.
      • MongoIdSegmentDistributor: Дистрибьютор IdSegment на основе MongoDB.
  • SegmentChainId(рекомендуется): SegmentChainId (без блокировки) является улучшением SegmentId, схема дизайна представлена ниже. PrefetchWorker поддерживает безопасное расстояние, чтобы SegmentChainId достигал приблизительно производительности TPS: 127 439 148+ операций/секунду JMH Benchmark.
    • PrefetchWorker поддерживает безопасное расстояние (safeDistance) и поддерживает динамическое расширение и сокращение безопасного расстояния в зависимости от статуса голода.## SnowflakeId

Исправлено:

  • "OnClickListener 4 096 000" заменено на "TPS: 4 096 000".

    Snowflake

SnowflakeId — это распределённый алгоритм генерации идентификаторов, использующий Long (64-бит) разбиение на части для генерации ID. Общая схема распределения битов: timestamp (41-бит) + machineId (10-бит) + sequence (12-бит) = 63-бит.

  • 41-бит timestamp = (1L<<41)/(1000/3600/24/365) ≈ 69 лет, которые могут быть сохранены в виде метки времени, то есть доступное абсолютное время — EPOCH + 69 лет. Обычно требуется настроить EPOCH как время начала разработки продукта. Кроме того, можно увеличить количество выделенных битов, сжимая другие области, что позволяет продлить доступное время.
  • 10-бит machineId = (1L<<10) = 1024, то есть можно развернуть 1024 копии одного и того же бизнес-приложения (в контексте Kubernetes нет понятия главного и резервного копирования, и здесь используется определение Kubernetes напрямую). Обычно требуется так много копий, поэтому machineId будет переопределен в зависимости от масштаба развертывания.
  • 12-бит sequence = (1L<<12) * 1000 = 4096000, то есть одна машина может генерировать около 409 миллионов ID в секунду, а глобальная кластерная система одного и того же сервиса может генерировать 4096000*1024=4194304000=4,19 миллиарда (TPS).

Из дизайна SnowflakeId можно сделать вывод:- :thumbs_up: Первые 41 бит — это timestamp, поэтому SnowflakeId локально монотонно увеличивается, и, подверженный глобальной синхронизации часов, SnowflakeId глобально увеличивается.

  • :thumbs_up: SnowflakeId не имеет сильной зависимости от какого-либо стороннего middleware, и его производительность также очень высока.
  • :thumbs_up: Схема распределения битов может быть гибко настроена в зависимости от потребностей бизнес-системы для достижения оптимального использования.
  • :thumbs_down: Сильная зависимость от локальных часов, потенциальные проблемы с перемещением часов назад могут привести к дублированию ID.
  • :thumbs_down: machineId необходимо задавать вручную. Если machineId задаётся вручную при развертывании, это будет очень неэффективно.---

CosId-SnowflakeId

Основная задача — решение двух основных проблем SnowflakeId: проблемы распределения номеров машин и проблемы перемещения часов назад, а также предоставление более дружественного и гибкого опыта.### MachineIdDistributor

В настоящее время CosId предоставляет три дистрибьютора MachineId.

ManualMachineIdDistributor

cosid:
  snowflake:
    machine:
      distributor:
        type: manual
        manual:
          machine-id: 0

Ручное распределение MachineId

StatefulSetMachineIdDistributor

cosid:
  snowflake:
    machine:
      distributor:
        type: stateful_set

Использует стабильный идентификатор ID, предоставленный StatefulSet Kubernetes, как номер машины.

RedisMachineIdDistributor

Redis Machine Id Distributor

Machine Id Safe Guard

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

```java
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 локальное хранилище состояния машины использует локальный файл для хранения номера машины и самого последнего таймстампа, который используется как кэш состояния машины.

ClockSyncSnowflakeId

cosid:
  snowflake:
    share:
      clock-sync: true

По умолчанию SnowflakeId будет выбрасывать исключение ClockBackwardsException при обратном движении часов, в то время как использование ClockSyncSnowflakeId будет использовать ClockBackwardsSynchronizer для активного ожидания синхронизации часов для перегенерации идентификатора, что обеспечивает более удобный для пользователя опыт.

SafeJavaScriptSnowflakeId

SnowflakeId snowflakeId = SafeJavaScriptSnowflakeId.ofMillisecond(1);

Number.MAX_SAFE_INTEGER в JavaScript имеет только 53 бита. Если 63-битный SnowflakeId будет напрямую возвращен на фронтенд, значение переполнится. Обычно мы можем преобразовать SnowflakeId в строковый тип или настраивать распределение битов SnowflakeId, чтобы уменьшить количество битов SnowflakeId, чтобы идентификатор не переполнялся при передаче на фронтенд.### 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

SegmentId

Segment Id

RedisIdSegmentDistributor

cosid:
  segment:
    enabled: true
    distributor:
      type: redis

JdbcIdSegmentDistributor

Инициализация таблицы cosid

create table if not exists cosid
(
    name            varchar(100) not null comment '{namespace}.{name}',
    last_max_id     bigint       not null default 0,
    last_fetch_time bigint       not null,
    constraint cosid_pk
        primary key (name)
) engine = InnoDB;
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test_db
    username: root
    password: root
cosid:
  segment:
    enabled: true
    distributor:
      type: jdbc
      jdbc:
        enable-auto-init-cosid-table: false
        enable-auto-init-id-segment: true

После включения enable-auto-init-id-segment: true, приложение попытается создать запись idSegment при запуске, чтобы избежать ручного создания. Аналогично выполнению следующего скрипта инициализации, не нужно беспокоиться о неправильных действиях, так как name является первичным ключом.```mysql insert into cosid (name, last_max_id, last_fetch_time) values ('namespace.name', 0, unix_timestamp());


### SegmentChainId

![SegmentChainId](./docs/SegmentChainId.png)

```yaml
cosid:
  segment:
    enabled: true
    mode: chain
    chain:
      safe-distance: 5
      prefetch-worker:
        core-pool-size: 2
        prefetch-period: 1s
    distributor:
      type: redis
    share:
      offset: 0
      step: 100
    provider:
      bizC:
        offset: 10000
        step: 100
      bizD:
        offset: 10000
        step: 100

IdGeneratorProvider

cosid:
  snowflake:
    provider:
      bizA:
        #      timestamp-bit:
        sequence-bit: 12
      bizB:
        #      timestamp-bit:
        sequence-bit: 12
IdGenerator idGenerator = idGeneratorProvider.get("bizA");

В реальном использовании мы обычно не используем один и тот же IdGenerator для всех бизнес-услуг, но разные бизнесы используют разные IdGenerator. Тогда IdGeneratorProvider существует для решения этой проблемы, и это контейнер IdGenerator, с помощью которого можно получить соответствующий IdGenerator по имени бизнеса.

CosIdPlugin (MyBatis Plugin)

Kotlin DSL

    implementation("me.ahoo.cosid:cosid-mybatis:${cosidVersion}")
@Target({ElementType.FIELD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CosId {
    String value() default IdGeneratorProvider.SHARE;
    
    boolean friendlyId() default false;
}
public class LongIdEntity {
    
    @CosId(value = "safeJs")
    private Long id;
    
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
}

public class FriendlyIdEntity {
    
    @CosId(friendlyId = true)
    private String id;
    
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
}
```@Mapper
public interface OrderRepository {
    @Insert("INSERT INTO t_table (id) VALUES (#{id});")
    void insert(LongIdEntity order);
    
    @Insert({
        "<script>",
        "INSERT INTO t_friendly_table (id)",
        "VALUES" +
            "<foreach item='item' collection='list' open='' separator=',' close=''>" +
            "(#{item.id})" +
            "</foreach>",
        "</script>"})
    void insertList(List<FriendlyIdEntity> list);
}
``````java
        LongIdEntity entity = new LongIdEntity();
    entityRepository.insert(entity);
    /**
     * {
     *   "id": 208796080181248
     * }
     */
    return entity;

ShardingSphere Plugin

cosid-shardingsphere

CosIdKeyGenerateAlgorithm (Distributed-Id)

spring:
  shardingsphere:
    rules:
      sharding:
        key-generators:
          cosid:
            type: COSID
            props:
              id-name: __share__

Интервал-основанная временная шардирование алгоритм

Интервал-основанная временная шардирование алгоритм

- Простота использования: поддерживает несколько типов данных (`Long`/`LocalDateTime`/`DATE`/`String` / `SnowflakeId`), официальная реализация состоит в том, чтобы сначала преобразовать в строку, а затем в `LocalDateTime`, успешность преобразования зависит от символов форматирования времени. - Производительность: по сравнению с `org.apache.shardingsphere.sharding.algorithm.sharding.datetime.IntervalShardingAlgorithm`, производительность в *1200~4000* раз выше.
PreciseShardingValue RangeShardingValue
Производительность IntervalShardingAlgorithm - PreciseShardingValue Производительность IntervalShardingAlgorithm - RangeShardingValue
  • CosIdIntervalShardingAlgorithm
    • тип: COSID_INTERVAL```yaml spring: shardingsphere: rules: шардирование: шард-алгоритмы: alg-name: type: COSID_INTERVAL props: логическое-имя-префикс: logic-name-prefix имя-id: cosid-name нижняя-дата-время: 2021-12-08 22:00:00 верхняя-дата-время: 2022-12-01 00:00:00 шард-суффикс-шаблон: yyyyMM интервал-единица-времени: MONTHS интервал-количество: 1

#### CosIdModShardingAlgorithm

<p align="center">
     <img src="./document/docs/.vuepress/public/assets/design/CosIdModShardingAlgorithm.png" alt="CosId Mod Sharding Algorithm"/>
</p>

- Производительность: В сравнении с `org.apache.shardingsphere.sharding.algorithm.sharding.datetime.IntervalShardingAlgorithm`, производительность в 1200~4000 раз выше. Имеет более высокую стабильность и отсутствие серьезного ухудшения производительности.

| **PreciseShardingValue**                                                                                                                                                        | **RangeShardingValue**                                                                                                                                                      |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ![Пропускная способность ModShardingAlgorithm - PreciseShardingValue](./document/docs/.vuepress/public/assets/perf/sharding/Throughput-Of-ModShardingAlgorithm-PreciseShardingValue.png) | ![Пропускная способность ModShardingAlgorithm - RangeShardingValue](./document/docs/.vuepress/public/assets/perf/sharding/Throughput-Of-ModShardingAlgorithm-RangeShardingValue.png) |```yaml
spring:
  shardingsphere:
    rules:
      шардирование:
        шард-алгоритмы:
          alg-name:
            type: COSID_MOD
            props:
              mod: 4
              логическое-имя-префикс: t_table_
```## Примеры
> В проекте представлены примеры использования различных сценариев (например, `jdbc`, `proxy`, `redis-cosid`, `redis`, `shardingsphere`, `zookeeper` и т.д.). В процессе работы можно использовать эти примеры для быстрого подключения с помощью соответствующей конфигурации.

[Посмотреть примеры](https://github.com/Ahoo-Wang/CosId/tree/main/examples)

## Установка

### Gradle

> Kotlin DSL

```kotlin
    val cosidVersion = "1.14.5"
    implementation("me.ahoo.cosid:cosid-spring-boot-starter:${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.14.5</cosid.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>me.ahoo.cosid</groupId>
            <artifactId>cosid-spring-boot-starter</artifactId>
            <version>${cosid.version}</version>
        </dependency>
    </dependencies>

</project>

Примеры

В проекте представлены примеры использования различных сценариев (например, jdbc, proxy, redis-cosid, redis, shardingsphere, zookeeper и т.д.). В процессе работы можно использовать эти примеры для быстрого подключения с помощью соответствующей конфигурации.

Посмотреть примеры

Установка

Gradle

Kotlin DSL

    val cosidVersion = "1.14.5"
    implementation("me.ahoo.cosid:cosid-spring-boot-starter:${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.14.5</cosid.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>me.ahoo.cosid</groupId>
            <artifactId>cosid-spring-boot-starter</artifactId>
            <version>${cosid.version}</version>
        </dependency>
    </dependencies>

</project>
```### application.yaml
```yaml
spring:
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbcUrl: jdbc:mysql://localhost:3306/cosid_db_0
        username: root
        password: root
      ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbcUrl: jdbc:mysql://localhost:3306/cosid_db_1
        username: root
        password: root
    props:
      sql-show: true
    rules:
      sharding:
        binding-tables:
          - t_order,t_order_item
        tables:
          cosid:
            actual-data-nodes: ds0.cosid
          t_table:
            actual-data-nodes: ds0.t_table_$->{0..1}
            table-strategy:
              standard:
                sharding-column: id
                sharding-algorithm-name: table-inline
          t_date_log:
            actual-data-nodes: ds0.t_date_log_202112
            key-generate-strategy:
              column: id
              key-generator-name: snowflake
            table-strategy:
              standard:
                sharding-column: create_time
                sharding-algorithm-name: data-log-interval
        sharding-algorithms:
          table-inline:
            type: COSID_MOD
            props:
              mod: 2
              logic-name-prefix: t_table_
          data-log-interval:
            type: COSID_INTERVAL
            props:
              logic-name-prefix: t_date_log_
              datetime-lower: 2021-12-08 22:00:00
              datetime-upper: 2022-12-01 00:00:00
              sharding-suffix-pattern: yyyyMM
              datetime-interval-unit: MONTHS
              datetime-interval-amount: 1
        key-generators:
          snowflake:
            type: COSID
            props:
              id-name: snowflake
cosid:
  namespace: ${spring.application.name}
  машинное:
    включен: true
    #      стабильный: true
    #      машинный-бит: 10
    #      инстанс-id: ${HOSTNAME}
    дистрибьютор:
      тип: redis
    #        ручной:
    #          машинный-id: 0
  снوفлэйк:
    включен: true
    #    эпоха: 1577203200000
    часовой_обратный:
      spin-порог: 10
```      поломанный-порог: 2000
     разделяемый:
       часовой_синхрон: true
       дружественный: true
     поставщик:
       order_item:
         #        timestamp-бит:
         последовательный_бит: 12
       снофлэйк:
         последовательный_бит: 12
       safeJs:
         машинный_бит: 3
         последовательный_бит: 9
   сегмент:
     включен: true
     режим: цепь
     цепь:
       безопасное_расстояние: 5
       prefetch_worker:
         core_pool_размер: 2
         prefetch_период: 
     дистрибьютор:
       тип: redis
     разделяемый:
       смещение: 0
       шаг: 100
     поставщик:
       order:
         смещение: 10000
         шаг: 100
       longId:
         смещение: 10000
         шаг: 100
 ```## JMH-Benchmark

- Разработка ноутбука: MacBook Pro (M1)
- Все тесты производительности проводятся на ноутбуке для разработки.
- Установка Redis на ноутбуке для разработки.

### SnowflakeId

```shell
gradle cosid-core:jmh
# или
java -jar cosid-core/build/libs/cosid-core-1.14.5-jmh.jar -bm thrpt -wi 1 -rf json -f 1
Benchmark                                                    Mode  Cnt        Score   Error  Units
SnowflakeIdBenchmark.millisecondSnowflakeId_friendlyId      thrpt  4020311.665          ops/s
SnowflakeIdBenchmark.millisecondSnowflakeId_generate        thrpt  4095403.859          ops/s
SnowflakeIdBenchmark.safeJsMillisecondSnowflakeId_generate  thrpt  511654.048           ops/s
SnowflakeIdBenchmark.safeJsSecondSnowflakeId_generate       thrpt  539818.563           ops/s
SnowflakeIdBenchmark.secondSnowflakeId_generate             thrpt  4206843.941          ops/s

Пропускная способность (ops/s) SegmentChainId

Пропускная способность SegmentChainId

Процентиль-образец (P9999=0.208 us/op) SegmentChainId

В статистике перцентиль (или центиль) — это оценка, ниже которой находится заданный процент оценок в её частотном распределении (исключающее определение) или оценка, ниже которой (исключающее определение) или включая которую (включающее определение) находится заданный процент оценок. Например, 50-й перцентиль (медиана) — это оценка, ниже которой (исключающее определение) или включая которую (включающее определение) находится 50% оценок в распределении.

Пример-перцентиля-сегмента-SegmentChainId

### CosId VS MeiTuan Leaf

CosId (SegmentChainId) в 5 раз быстрее, чем Leaf(segment).

CosId VS MeiTuan Leaf

Сообщество и спонсоры

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Описание недоступно Развернуть Свернуть
Apache-2.0
Отмена

Обновления (75)

все

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/AhooWang-CosId.git
git@api.gitlife.ru:oschina-mirror/AhooWang-CosId.git
oschina-mirror
AhooWang-CosId
AhooWang-CosId
main