In-Depth Explanation of the Distributed ID Segment Mode

In modern microservices and high-concurrency environments, traditional database auto-incrementing IDs often fall short. They introduce single-point bottlenecks that limit write performance, and they fail to guarantee global uniqueness across sharded databases. To address these challenges, the industry has adopted various distributed ID generation strategies, such as UUIDs, the Snowflake algorithm, and the Segment Mode—the core focus of this article.

The segment mode strikes a pragmatic balance between fetching an ID for every single request and fetching an entire batch at once. Its core philosophy is simple: rather than querying the database for every ID, an application client retrieves a contiguous range of IDs in a single batch (for example, numbers 1000 through 1999) and caches them in local memory. Once this local supply is exhausted, the client requests the next segment. This architecture drastically reduces database access frequency while maintaining ID uniqueness and sequential order.
The segment mode typically relies on a dedicated database table (often named id_segment) containing several key attributes:

  • biz_tag: A business identifier used to isolate ID spaces across different services.
  • max_id: The upper boundary of the currently allocated ID block.
  • step: The size of the allocated segment (the batch volume).
  • version: An optimistic locking version number used for concurrency control.

The typical workflow proceeds as follows:

  1. Initialization: Upon startup, the system reads the current max_id from the database.
  2. Local Caching: The application loads the range from max_id to max_id + step - 1 into local memory, utilizing thread-safe structures like AtomicLong or LongAdder.
  3. ID Generation: As business requests arrive, IDs are incremented directly from local memory without hitting the database.
  4. Segment Depletion: When the local range is fully consumed, the system triggers a database update to advance max_id by step, securing a fresh segment.

Concurrency Control and Data Consistency

Because multiple application instances may request new segments simultaneously, race conditions must be actively managed. The segment mode generally relies on database optimistic locking to prevent conflicts.

When updating the max_id, the SQL statement typically looks like this:

UPDATE id_segment 
SET max_id = max_id + #{step}, version = version + 1 
WHERE biz_tag = #{bizTag} AND version = #{version};

If the affected row count equals zero, it indicates that the version number has already changed—meaning another instance updated the segment first. The current instance must then retry or throw an exception. This mechanism guarantees that even under high concurrency, different instances never acquire overlapping ID ranges, preserving global uniqueness.

Pros and Cons Analysis

Advantages:

  • High Performance: The vast majority of ID generation operations happen entirely in memory, completely bypassing network I/O and database query overheads to yield exceptional throughput.
  • Sequential Ordering: Within a single segment, IDs are strictly incremental, which benefits database index optimization and cache hit rates.
  • Low Latency: Compared to querying the database for every single ID, the average latency is exceptionally low.

Disadvantages:

  • Non-Strict Global Ordering: When multiple instances pull segments concurrently, the generated IDs may interleave globally. For instance, if Instance A holds 1–100 and Instance B holds 101–200, B might issue 150 before A issues 50.
  • Service Restart Waste: If an application restarts before a segment is fully exhausted, the remaining IDs are discarded, creating "holes" in the sequence. While these gaps do not impact uniqueness, they break absolute continuity.
  • Database Availability Dependency: When a local segment runs dry, the system must communicate with the database. If the database goes down, new IDs cannot be generated.

Best Practices and Optimization Strategies

  1. Calibrate the Step Size:

    • A step size that is too small triggers frequent database access and heightens lock contention.
    • A step size that is too large results in significant ID wastage whenever services restart.
    • Adjust this parameter through load testing based on your business QPS and expected restart frequency. For high-QPS services, steps are commonly set between 1,000 and 10,000.
  2. Implement a Double-Buffer Mechanism:

    • To prevent business threads from blocking when a segment is exhausted, adopt a dual-buffer strategy. When the current segment crosses a certain usage threshold (e.g., 10% remaining), trigger an asynchronous thread to prefetch the next segment. This ensures zero-downtime transitions and a smooth user experience.
  3. Robust Monitoring and Alerting:

    • Monitor local segment consumption rates and fire alerts when supplies run low.
    • Track the update frequency of the id_segment table; sudden spikes can indicate improperly sized steps or hot-spot contention.
  4. Graceful Degradation and Fault Tolerance:

    • When the database becomes unavailable, consider fallback strategies such as generating temporary IDs via local random number generators (provided they can be reconciled later), though you must carefully evaluate the impact on core business logic.

Summary

The segment mode represents an excellent architectural compromise between performance and consistency in distributed systems. By batching ID acquisition, it significantly relieves database pressure while preserving local sequential ordering. Combined with a double-buffer mechanism and well-tuned step configurations, the segment mode easily scales to support millions or even tens of millions of TPS, making it a premier architectural choice for building highly available distributed ID services.