# SDS Request Volume Limiting vs Concurrency Limiting: Differences and Selection Criteria

> Understand SDS request volume limiting vs concurrency limiting. Learn how to choose the right method to control your system's request flow effectively.

- Repository: [DiDi/sds](https://github.com/didi/sds)
- Tags: deep-dive
- Published: 2026-02-28

---

**Request volume limiting restricts the total number of requests within a sliding time window, while concurrency limiting restricts the simultaneous number of active executions using a semaphore-based approach.**

The DiDi SDS (Service Downgrade System) provides two independent flow-control mechanisms to protect services from overload. Understanding the distinctions between SDS request volume limiting and concurrency limiting ensures you apply the correct protection strategy for each downgrade point.

## Core Differences Between Limiting Strategies

SDS implements these mechanisms through separate strategy executors that check different thresholds during request evaluation.

### Request Volume Limiting (Visit Threshold)

**Request volume limiting** controls the total number of requests allowed within a fixed sliding window (10 seconds by default). The `VisitStrategyExecutor` located in [`sds-client/src/main/java/com/didiglobal/sds/client/strategy/executor/VisitStrategyExecutor.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/strategy/executor/VisitStrategyExecutor.java) performs the check by comparing `strategy.getVisitThreshold()` against the current request count stored in `checkData.getVisitCount()`.

The implementation uses `PowerfulCycleTimeCounter` to aggregate request counts per second across the sliding window. When the cumulative volume exceeds the configured threshold, the executor returns `false` and SDS rejects further calls until the window slides.

### Concurrency Limiting

**Concurrency limiting** controls the number of simultaneous active threads executing a protected method. The `ConcurrentStrategyExecutor` in [`sds-client/src/main/java/com/didiglobal/sds/client/strategy/executor/ConcurrentStrategyExecutor.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/strategy/executor/ConcurrentStrategyExecutor.java) manages this through a `java.util.concurrent.Semaphore` stored in `ConcurrentData.concurrentLimit`.

During request entry, the system attempts to acquire a semaphore permit. The boolean result (`checkData.concurrentAcquire`) determines whether the request proceeds. If the semaphore is exhausted because the current number of in-flight calls has reached `strategy.getConcurrentThreshold()`, the request is rejected or blocked depending on client configuration.

| Feature | Request Volume Limiting | Concurrency Limiting |
|---------|------------------------|---------------------|
| **What it limits** | Total requests in a sliding window | Simultaneous active executions |
| **Strategy class** | `VisitStrategyExecutor` | `ConcurrentStrategyExecutor` |
| **Configuration field** | `SdsStrategy.visitThreshold` (Long, -1 = disabled) | `SdsStrategy.concurrentThreshold` (Integer, -1 = disabled) |
| **Implementation** | Sliding-window counter (`PowerfulCycleTimeCounter`) | `Semaphore` acquisition (`ConcurrentData`) |
| **Trigger condition** | Cumulative volume exceeds threshold | Semaphore cannot be acquired |
| **Typical use case** | API QPS limits, downstream protection | Connection pools, non-thread-safe resources |

## Selection Criteria: When to Use Each Strategy

Choose between these mechanisms based on the nature of your bottleneck and operational requirements.

### Traffic Volume and QPS Control

Use **request volume limiting** when the bottleneck relates to total traffic volume or downstream service capacity. This applies when protecting services that can handle a specific request rate (e.g., 100 req/s) but fail under higher loads. The strategy spreads restrictions evenly across the sliding window and provides fast rejection without blocking, making it ideal for latency-sensitive APIs where immediate failure is preferable to queueing.

### Resource Contention Protection

Use **concurrency limiting** when protecting scarce resources that cannot handle parallel access. This includes limited-size connection pools, non-thread-safe libraries, or critical sections that cause contention under concurrent load. Unlike volume limiting, concurrency limiting grants access to the first *N* callers regardless of overall traffic levels, making it suitable for thread-pool-like behavior where you can afford short waits for resource availability.

### Combining Both Strategies

In production environments, enable both limits on the same downgrade point for layered protection. SDS evaluates executors in a specific chain order (`Visit → TokenBucket → Concurrent → …`), and if any executor returns `false`, the request is downgraded. This configuration allows the request volume limit to cap overall load while the concurrency limit safeguards specific scarce resources.

## Implementation Details in SDS Source Code

The configuration fields reside in [`sds-client/src/main/java/com/didiglobal/sds/client/bean/SdsStrategy.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/bean/SdsStrategy.java):

```java
// Request volume threshold (Long type, -1 disables the check)
private Long visitThreshold;

// Concurrency threshold (Integer type, -1 disables the check)  
private Integer concurrentThreshold;

```

Runtime data flows through [`CheckData.java`](https://github.com/didi/sds/blob/main/CheckData.java) ([`sds-client/src/main/java/com/didiglobal/sds/client/bean/CheckData.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/bean/CheckData.java)), which carries:
- `visitCount`: The current aggregated request count for volume limiting
- `concurrentAcquire`: The boolean result of the semaphore acquisition attempt

For concurrency limiting, the low-level semaphore implementation resides in [`ConcurrentData.java`](https://github.com/didi/sds/blob/main/ConcurrentData.java) ([`sds-client/src/main/java/com/didiglobal/sds/client/counter/ConcurrentData.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/counter/ConcurrentData.java)), while volume limiting relies on [`PowerfulCycleTimeCounter.java`](https://github.com/didi/sds/blob/main/PowerfulCycleTimeCounter.java) for sliding-window statistics.

## Practical Configuration Example

Configure both limits programmatically or through the SDS admin console:

```java
// Initialize strategy for a downgrade point
SdsStrategy strategy = new SdsStrategy();
strategy.setPoint("orderCreate");

// Request-volume limit: max 200 requests per 10s window
strategy.setVisitThreshold(200L);

// Concurrency limit: at most 20 simultaneous executions
strategy.setConcurrentThreshold(20);

// Register with SDS client
SdsClient sdsClient = SdsClientFactory.getOrCreateSdsClient(
        "BikeBusinessDepartment", "order", "http://127.0.0.1:8887");

```

In the SDS admin console:
- Set **访问量阈值** (Visit Threshold) to adjust request volume limits
- Set **并发阈值** (Concurrent Threshold) to adjust concurrency limits

Both values can be modified at runtime and take effect immediately without restarting services.

## Summary

- **Request volume limiting** uses `VisitStrategyExecutor` and a sliding-window counter to restrict total requests per time window (default 10s), ideal for QPS control and downstream protection.
- **Concurrency limiting** uses `ConcurrentStrategyExecutor` and a `Semaphore` to restrict simultaneous active threads, essential for protecting finite resources like connection pools.
- Both thresholds are defined in `SdsStrategy` (`visitThreshold` and `concurrentThreshold`) and can operate simultaneously on the same downgrade point.
- Volume limiting provides fast rejection without blocking, while concurrency limiting can accommodate brief waits for resource availability.
- Changes made through the SDS admin console apply immediately to both limiting strategies.

## Frequently Asked Questions

### What is the default time window for SDS request volume limiting?

The default sliding window is **10 seconds**, implemented through `PowerfulCycleTimeCounter` in the SDS client. The system aggregates request counts per second and maintains a rolling window of statistics to determine when the `visitThreshold` has been exceeded.

### Can I use both request volume and concurrency limiting on the same downgrade point?

**Yes.** SDS supports enabling both limits simultaneously. The system evaluates `VisitStrategyExecutor` before `ConcurrentStrategyExecutor` in the strategy chain. If either check fails, the request is downgraded. This dual-layer approach protects against both traffic spikes and resource exhaustion.

### How does SDS concurrency limiting handle thread safety?

SDS concurrency limiting uses `java.util.concurrent.Semaphore` via the `ConcurrentData` class, which provides thread-safe permit acquisition and release. The semaphore is acquired during request entry and released in the `downgradeFinally` block, ensuring permits are returned even if exceptions occur during execution.

### What happens when a request exceeds the configured thresholds?

When thresholds are exceeded, the `shouldDowngrade()` method returns `true`, directing the request to the downgrade path. For request volume limiting, this happens immediately when the count exceeds the threshold. For concurrency limiting, it occurs when the semaphore cannot be acquired. The application can then return a fallback value or throw an exception based on business requirements.