CosId Distributed ID Generation: Snowflake & Segment Modes Explained
This article explores CosId's two ID generation modes—local computation (Snowflake) and segment allocation (SegmentId, SegmentChainId)—with detailed configuration for JDBC, Redis, ZooKeeper, MongoDB, and Proxy backends, plus Spring Boot, MyBatis, and ShardingSphere integration examples.
This article provides a comprehensive technical guide to CosId, a unified distributed ID generation library for Spring Boot applications. It begins by contrasting CosId with TSID: while TSID focuses on a single time-based ID, CosId allows registering multiple generators (e.g., order, invoice, payment) under different algorithms within one application.
Two Generation Routes
CosId offers four generators grouped into two fundamental routes:
Local computation route : SnowflakeId (64-bit integer) and CosIdGenerator (short string via Radix62/36/Friendly). Both require a unique machine ID obtained at startup (manual, StatefulSet, or dynamic via JDBC/Redis/ZooKeeper/MongoDB/Proxy). Daily generation happens locally without remote calls.
Segment allocation route : SegmentId (plain segment) and SegmentChainId (prefetch chain). They fetch non-overlapping numeric ranges (e.g., 1–1000, 1001–2000) from a coordination backend. SegmentId fetches the next segment synchronously when the current one exhausts; SegmentChainId uses a background thread to prefetch subsequent segments, reducing latency at boundaries.
The article emphasizes that CosIdGenerator is not a simple string conversion of Snowflake; it encodes its own timestamp, machine ID, and sequence state. Segment modes do not embed machine IDs; they rely on atomic upper-bound advancement.
Architecture: Provider, Generator, Distributor
Three core roles: IdGeneratorProvider: registry of named generators (like an address book). IdGenerator: business-facing entry point with generate() and generateAsString(). Distributor: manages finite resources—machine IDs or segments.
At Spring Boot startup, the Starter reads cosid.* configuration, creates generators, and registers them. Business code retrieves a generator by name (e.g., provider.getRequired("order")) and calls generate().
Quick Start: Versions and Dependencies
CosId aligns major versions with Spring Boot: 1.x for Spring Boot 2.x (Java 8), 2.x for Spring Boot 3.x (Java 17), 3.x for Spring Boot 4.x (Java 17). The article uses CosId 3.2.0. Minimal dependency is cosid-spring-boot-starter; additional modules ( cosid-jdbc, cosid-spring-redis, cosid-zookeeper, cosid-mongo, cosid-proxy, cosid-mybatis, cosid-spring-data-jdbc) are added per backend.
SnowflakeId: From Generation to Machine ID Management
4.1 Local Generation with Manual Machine ID
Development config example sets machine.distributor.type=manual and machine.manual.machine-id=0. A simple REST endpoint demonstrates generating two distinct 64-bit IDs (e.g., 881846796089962497, 881846796094156801).
4.2 64-bit Layout
Default layout: 41 bits timestamp, 10 bits machine ID (0–1023), 12 bits sequence. Core generation code shifts and ORs these components. Changing machine bits changes the valid range; both generator and distributor must agree.
4.3 Machine ID Lifecycle
Dynamic distributors (JDBC, Redis, etc.) handle registration, periodic guarding (default every 1 minute after 1 minute initial delay), active release on graceful shutdown, and recovery after a safety window (default 5 minutes) on crash. Local state file ( ./cosid-machine-state/) is not a sole recovery source; remote coordination state must be reliable.
4.4 Manual Distributor
No registration center, no lease renewal, no auto-recycle. Suitable for fixed environments with external machine ID ledger.
4.5 StatefulSet Distributor
Parses pod ordinal from HOSTNAME (e.g., order-id-2 → machine ID 2). Requires StatefulSet; Deployment pod names have random suffixes. Multi-cluster deployments need shared coordination backend or custom cluster-id + pod ordinal scheme.
4.6 Dynamic Backends
JDBC, Redis, ZooKeeper, MongoDB, Proxy all persist machine ID occupancy. Registration, guarding, release, and recovery follow the same lifecycle. Daily ID generation reads the in-memory machine ID; remote backend hiccups don't slow per-ID generation, but prolonged guard/registration failures must alert to prevent stale instances from issuing IDs.
CosIdGenerator: Short String IDs
Three encoding types: RADIX62 (0-9, A-Z, a-z, case-sensitive, compact), RADIX36 (0-9, A-Z, case-insensitive), FRIENDLY (human-readable time-ish). Default Radix62 uses 44-bit timestamp, 20-bit machine ID, 16-bit sequence → 15 chars. The generator first creates a CosIdState (timestamp, machine ID, sequence) then encodes it. Parsing back to state requires the same layout/encoding. Switching encoding after production use breaks length, charset, and parsing.
SegmentId vs SegmentChainId: Why Two Segment Modes
6.1 SegmentId with JDBC
Table cosid stores name, last_max_id, last_fetch_time. Config: segment.mode=segment, distributor.type=jdbc, step=100. Fetching a new segment runs in a single transaction: UPDATE ... SET last_max_id = last_max_id + 100 then SELECT last_max_id. Local increment uses segment.incrementAndGet(); on overflow, maxIdDistributor.nextIdSegment() fetches next range. Step=1 defeats caching; larger steps reduce remote calls but increase gaps on crash. Concurrency test with 150 parallel IDs verifies uniqueness.
6.2 SegmentChainId Prefetch
Config: segment.mode=chain, chain.safe-distance=5, chain.prefetch.worker.core-pool-size=2, chain.prefetch.period=1s, step=1000. Background thread maintains a chain of segments ahead of consumption. Generation walks the chain; if exhausted, it synchronously creates a fallback segment and signals prefetch job. Comparison table summarizes differences: local cache (single segment vs chain), next segment fetch (sync at boundary vs background prefetch), thread complexity, suitable scenarios (low/medium traffic vs high concurrency latency-sensitive), and failure behavior.
Five Coordination Backends: Selection Guide
Backends store different state: machine ID occupancy vs segment upper bounds. Even using same Redis, keys are separate. Risks: duplicate machine IDs vs segment counter rollback.
JDBC : State in cosid_machine and cosid tables. Advantages: queryable, auditable, backupable. Watch for primary switchover, lock contention, connection pool exhaustion, and ensure writes go to primary.
Redis : High performance but state loss is dangerous. Keys must persist (check persistence, maxmemory-policy, master failover). Not every ID hits Redis; only registration, guarding, segment fetch.
ZooKeeper : Suitable if cluster already exists and team knows session/node lifecycle. Not worth deploying solely for ID generation. Watch session jitter, reconnection, quorum loss.
MongoDB : Reuse if primary storage. Default DB cosid_db. Verify permissions, write concern, replica set elections.
Proxy : Centralizes credentials and coordination logic. Applications talk HTTP to Proxy; Proxy manages underlying stores. Adds network hop; Proxy itself needs HA, service discovery, monitoring. Good for multi-team shared infrastructure.
Selection priority: use what you already operate reliably. Throughput is secondary; reliability of state persistence and failure recovery matters more.
Spring Ecosystem Integrations
8.1 Grouped Segments (Date-Prefixed Invoice Numbers)
GroupedIdSegmentDistributoradds time grouping (YEAR, YEAR_MONTH, YEAR_MONTH_DAY, NEVER). Example: group.by=year_month_day, pattern=yyMMdd, prefix=INV-, char-size=8, pad-start=true produces INV-260824-00000001. Requires consistent timezone and clock sync across instances; does not guarantee gapless sequences for legal invoices.
8.2 Starter Internals
Starter binds cosid.* properties, creates distributors, registers generators into IdGeneratorProvider. Troubleshooting missing generator: check category enabled, provider.<name> exists, backend module present.
8.3 MyBatis Auto-Fill
Add cosid-mybatis, annotate entity ID with @CosId("order"). On insert, if ID null, generator "order" fills it. Behavior on pre-filled ID or type mismatch should be tested per version.
8.4 Spring Data JDBC Auto-Fill
Add cosid-spring-data-jdbc; same @CosId annotation works via before-save callback.
8.5 ShardingSphere Integration
Since ShardingSphere 5.1.0, CosId is integrated as a key generator under ShardingSphere's own config (
spring.shardingsphere.rules.sharding.key-generators.cosid.type=COSID, props.id-name=__share__). Not controlled by cosid.* properties. Version-specific YAML structure may differ; consult official docs.
When to Use CosId
Adopt when: Spring Boot project needs Snowflake, short strings, and segments simultaneously; team wants unified registration/invocation by business name; existing reliable coordination backend (JDBC/Redis/ZooKeeper/MongoDB) can be reused; MyBatis/Spring Data JDBC auto-fill needed; willing to manage versions, config, monitoring, failure drills.
Avoid when: single-node random ID (UUID suffices); multi-language protocol consistency required (Java lib doesn't solve cross-language governance); legal invoices demand strict gapless continuity (plain segments have gaps); team cannot maintain chosen coordination backend or Proxy; legacy Snowflake epoch/layout frozen without compatibility verification.
Three production guardrails: ensure machine IDs never duplicate, segment state never rolls back, and application stops issuing IDs when external coordination fails.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Yumin Fish Harvest
A deep‑sea salvage fisherman sharing architecture insights, practical tips, and lessons learned.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
