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

OSCHINA-MIRROR/AhooWang-CosId

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

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

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

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

Введение

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

  • CosIdGenerator : автономный (производительность TPS: 15 570 085 операций в секунду), в три раза превышает производительность UUID.randomUUID(), глобально возрастающий с течением времени.
  • SnowflakeId : автономный (производительность TPS: 4 096 000 операций в секунду) JMH Benchmark, решает две основные проблемы SnowflakeId: проблему выделения номера машины и проблему обратной перемотки часов и предлагает более удобный и гибкий опыт.
  • SegmentId: каждый раз получает сегмент (шаг) идентификатора для снижения частоты запросов сети к распределителю IdSegment и повышения производительности.
    • IdSegmentDistributor:
      • RedisIdSegmentDistributor: распределитель IdSegment на основе Redis.
      • JdbcIdSegmentDistributor: распределитель IdSegment на основе JDBC, поддерживающий различные реляционные базы данных.
      • ZookeeperIdSegmentDistributor: распределитель IdSegment на основе Zookeeper.
      • MongoIdSegmentDistributor: распределитель IdSegment на основе MongoDB.
  • SegmentChainId (рекомендовано): SegmentChainId (без блокировки) является улучшенной версией SegmentId. Схема дизайна представлена ниже. PrefetchWorker поддерживает безопасное расстояние, так что SegmentChainId достигает приблизительно производительности AtomicLong: 127 439 148+ операций в секунду JMH Benchmark.
    • PrefetchWorker поддерживает безопасное расстояние (safeDistance) и поддерживает динамическое расширение и сокращение безопасного расстояния в зависимости от состояния голода.

SnowflakeId

Snowflake

SnowflakeId — это алгоритм распределенного генератора уникальных идентификаторов, использующий битовое деление Long (64-битного) для генерации идентификатора. Общая схема распределения битов: 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 напрямую здесь). Обычно такого количества экземпляров не требуется, поэтому его следует переопределить в соответствии со шкалой развертывания.
  • 12-бит sequence = (1L << 12) * 1000 = 4096000 Это значит, что одна машина может генерировать около 409 миллионов идентификаторов в секунду, а глобальная кластеризация одного сервиса может генерировать 4096000 * 1024 = 4194304000 = 4,19 миллиардов (TPS).

Из дизайна SnowflakeId видно:

  • :thumbsup: Первые 41 бит представляют собой timestamp, поэтому SnowflakeId локально монотонно возрастает и глобально возрастает благодаря синхронизации часов.
  • :thumbsup: SnowflakeId не имеет сильной зависимости от третьих сторон и имеет очень высокую производительность.
  • :thumbsup: Схема распределения битов может быть гибко настроена в соответствии с потребностями системы для достижения оптимального использования.
  • :thumbsdown: Сильная зависимость от локальных часов, потенциальные проблемы обратной перемотки часов могут вызвать дублирование идентификаторов.
  • :thumbsdown: Номер машины 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

Использует стабильный идентификационный идентификатор 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`, используется метод `Thread.sleep()` для ожидания синхронизации часов. Если значение превышает `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 lastTimestamp) {
        return new MachineState(machineId, lastTimestamp);
    }
}
cosid:
  snowflake:
    machine:
      state-storage:
        local:
          state-location: ./cosid-machine-state/

По умолчанию LocalMachineStateStorage использует локальное файловое хранилище для хранения номера машины и последнего временного штампа, который используется как кэш MachineState.

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 в тип String или настраивать распределение битов 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 при запуске, чтобы избежать необходимости её создания вручную. Аналогично выполнению следующего скрипта инициализации SQL, нет необходимости беспокоиться о неправильной операции, так как name является первичным ключом.

INSERT INTO cosid (name, last_max_id, last_fetch_time) VALUES ('namespace.name', 0, UNIX_TIMESTAMP());

SegmentChainId

SegmentChainId

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);
}
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__

Interval-based time range sharding algorithm

CosIdIntervalShardingAlgorithm

  • Простота использования: поддерживает несколько типов данных (Long/LocalDateTime/DATE/String/SnowflakeId). Официальная реализация сначала преобразует данные в строку, а затем в LocalDateTime. Успешность преобразования зависит от символов формата времени.

  • Производительность: по сравнению с org.apache.shardingsphere.sharding.algorithm.sharding.datetime.IntervalShardingAlgorithm, производительность выше в 1200–4000 раз.| PreciseShardingValue | RangeShardingValue | |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Пропускная способность IntervalShardingAlgorithm - PreciseShardingValue | Пропускная способность IntervalShardingAlgorithm - RangeShardingValue |

  • CosIdIntervalShardingAlgorithm

    • type: COSID_INTERVAL
spring:
  shardingsphere:
    rules:
      sharding:
        sharding-algorithms:
          alg-name:
            type: COSID_INTERVAL
            props:
              logic-name-prefix: logic-name-prefix
              id-name: cosid-name
              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

CosIdModShardingAlgorithm

CosId Mod Sharding Algorithm

  • Производительность: по сравнению с org.apache.shardingsphere.sharding.algorithm.sharding.datetime.IntervalShardingAlgorithm, производительность выше в 1200–4000 раз. Имеет более высокую стабильность и значительное снижение производительности.
PreciseShardingValue RangeShardingValue
Пропускная способность ModShardingAlgorithm - PreciseShardingValue Пропускная способность ModShardingAlgorithm - RangeShardingValue
spring:
  shardingsphere:
    rules:
      sharding:
        sharding-algorithms:
          alg-name:
            type: COSID_MOD
            props:
              mod: 4
              logic-name-prefix: t_table_

Примеры

В проекте представлены примеры использования различных сценариев (например, 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

spring:
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: 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
        jdbc-url: 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}
  machine-device:
    enabled: true
    #      stability: true
    #      bit-machine-device: 10
    #      instance-id: ${HOSTNAME}
    distributor:
      type: redis
    #        manual:
    #          machine-id: 0
  snowflake:
    enabled: true
    #    epoch: 1577203200000
    back-time:
      spin-rate: 10
      break-rate: 2000
    availability:
      clock-sync: true
      friendliness: true
    provider:
      order_item:
        #        test-time-bit:
        sequence-bit: 12
      snowflake:
        sequence-bits: 12
      safeJs:
        machine-bit: 3
        sequence-bits: 9
  segment:
    enabled: true
    mode: chain
    chain:
      safety-distance: 5
      preprocessor-worker:
        main-pool-size: 2
        preprocessing-period: 1s
    distributor:
      type: redis
    availability:
      offset: 0
      step: 100
    provider:
      order:
        offset: 10000
        step: 100
      long-id:
        offset: 10000
        step: 100

JMH-Benchmark

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

SnowflakeId

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

Пропускная способность (операций/с) SegmentChainId

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

Процентиль-образец (P9999=0.208 мкс/операция) SegmentChainId> В статистике процентиль — это значение, ниже которого находится указанное количество значений в частотном распределении (исключающее определение) или значение, которое равно или меньше указанного количества значений (включительное определение). Например, 50-й процентиль (медиана) — это значение, ниже которого (исключающее определение) или равное или меньшее которого (включительное определение) находятся 50% значений в распределении.

Образец процентилей SegmentChainId

CosId против MeiTuan Leaf

CosId (SegmentChainId) работает в пять раз быстрее, чем Leaf(segment).

CosId против MeiTuan Leaf

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

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

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

Введение

Описание недоступно Развернуть Свернуть
Java и 6 других языков
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