# Hot-Swapping Mechanism for Dynamically Adjusting SDS Downgrade Strategies: A Deep Dive into Didi SDS

> Learn about Didi SDS hot-swapping mechanism for zero-downtime strategy updates. Dynamically adjust SDS downgrade strategies by atomically replacing in-memory configurations without JVM restarts.

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

---

**SDS (Service Degrade System) enables zero-downtime strategy updates through a hot-swapping mechanism that pulls fresh downgrade configurations from the admin server every 5 seconds and atomically replaces the in-memory strategy map without restarting the JVM or redefining classes.**

The Didi SDS (Service Degrade System) is an open-source Java framework designed to protect microservices through runtime downgrade capabilities. Its hot-swapping mechanism for dynamically adjusting SDS downgrade strategies allows operators to modify thresholds, exception rates, and fallback behaviors in real-time while production traffic continues unaffected. This implementation relies on a combination of Java agent instrumentation, background heartbeat pulling, and atomic memory operations to achieve seamless configuration updates.

## Core Components of the Hot-Swapping Architecture

The mechanism consists of four cooperating components that work together to enable dynamic strategy adjustment without application restarts.

### SdsBootStrap (Java Agent Entry Point)

Located in [`sds-bootstrap/src/main/java/com/didiglobal/sds/bootstrap/SdsBootStrap.java`](https://github.com/didi/sds/blob/main/sds-bootstrap/src/main/java/com/didiglobal/sds/bootstrap/SdsBootStrap.java), this class serves as the entry point for the Java agent. Its `premain()` method parses agent arguments, instantiates the singleton `SdsClient`, and registers the `SdsClassFileTransformer` for the user-specified package scan path. This establishes the foundation for hot-swapping by injecting the downgrade decision points directly into business methods at startup.

### SdsClassFileTransformer (Bytecode Instrumentation)

Found in [`sds-bootstrap/src/main/java/com/didiglobal/sds/bootstrap/transformer/SdsClassFileTransformer.java`](https://github.com/didi/sds/blob/main/sds-bootstrap/src/main/java/com/didiglobal/sds/bootstrap/transformer/SdsClassFileTransformer.java), this component instruments methods annotated with `@SdsDowngradeMethod`. It injects bytecode that wraps method execution with calls to `SdsClient.shouldDowngrade(..)` before entry and `SdsClient.downgradeFinally(..)` after completion. This design makes the downgrade logic **data-driven**—the bytecode remains static while the decision strategy referenced by the client can be hot-swapped at any time.

### SdsHeartBeatService (Background Strategy Puller)

Defined in [`sds-client/src/main/java/com/didiglobal/sds/client/service/SdsHeartBeatService.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/service/SdsHeartBeatService.java), this service runs `CyclePullPointStrategyTask` in a scheduled thread that executes every 5 seconds. It sends heartbeat requests to the SDS admin server endpoint `/sds/heartbeat/pullstrategy`, transmitting the current client version and active point list. When the server responds with `changed=true`, the service triggers the hot-swap sequence.

### SdsStrategyService (Atomic Configuration Holder)

Located in [`sds-client/src/main/java/com/didiglobal/sds/client/service/SdsStrategyService.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/service/SdsStrategyService.java), this class maintains a `ConcurrentHashMap<String, SdsStrategy>` that maps point identifiers to their corresponding strategy executors (`VisitStrategyExecutor`, `TokenBucketStrategyExecutor`, etc.). The `resetAll()` method performs an atomic replacement of the entire map, enabling instant updates visible to all subsequent downgrade checks.

## How the Hot-Swapping Loop Works

The hot-swapping mechanism operates through a continuous six-step cycle that ensures strategies remain fresh without interrupting service.

### 1. Agent Startup and Instrumentation

When launching the JVM with the SDS agent, the `premain()` method initializes the system:

```bash
java -javaagent:/opt/sds/sds-bootstrap-1.0.0.jar=demoGroup,orderService,http://sds-admin:8080,com.example.service

```

The transformer then processes every method bearing `@SdsDowngradeMethod`, injecting bytecode equivalent to:

```java
SdsClient __sdsClient = SdsBootStrap.getClient();
if (__sdsClient != null && __sdsClient.shouldDowngrade("POINT")) {
    throw new SdsException("POINT", ExceptionCode.DOWNGRADE);
}
// … original method body …
SdsClient ____sdsClient = SdsBootStrap.getClient();
if (____sdsClient != null) {
    ____sdsClient.downgradeFinally("POINT");
}

```

This instrumentation ensures that every business method references the global `SdsClient` for its downgrade decisions.

### 2. Periodic Strategy Fetching

Every 5 seconds, `SdsHeartBeatService` executes its pull task:

```java
// Inside SdsHeartBeatService.updatePointStrategyFromWebServer()
if (response.isChanged()) {
    ConcurrentHashMap<String, SdsStrategy> newStrategies = new ConcurrentHashMap<>();
    for (SdsStrategy s : response.getStrategies()) {
        newStrategies.put(s.getPoint(), s);
    }
    // Hot-swap the whole map atomically
    SdsStrategyService.getInstance().resetAll(newStrategies);
    // Synchronize fallback return values
    SdsDowngradeReturnValueService.getInstance().reset(newStrategies);
}

```

The service parses the server response into a fresh `ConcurrentHashMap`, preparing it for atomic installation.

### 3. Atomic Memory Replacement

The `resetAll()` method in `SdsStrategyService` writes the new map reference to a volatile field. Because `ConcurrentHashMap` is thread-safe and the reference replacement is atomic, all subsequent calls to `shouldDowngrade` immediately observe the new thresholds. Ongoing requests continue using the old strategy map until they complete, while new requests pick up the configuration instantly.

### 4. Return-Value Synchronization

`SdsDowngradeReturnValueService`, located in [`sds-client/src/main/java/com/didiglobal/sds/client/service/SdsDowngradeReturnValueService.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/service/SdsDowngradeReturnValueService.java), performs an identical atomic swap for fallback return values. This ensures that both the downgrade decision logic and the fallback behavior remain consistent after a hot-swap operation.

## Practical Implementation Examples

### Configuring Business Methods for Hot-Swap

Annotate service methods to enable dynamic downgrade adjustment:

```java
public class OrderService {

    @SdsDowngradeMethod(point = "CREATE_ORDER")
    public Order createOrder(OrderReq req) {
        // business logic …
        return orderDao.save(req);
    }
}

```

The `point` identifier serves as the key for strategy lookup in the hot-swapped map.

### Inspecting Current Strategies at Runtime

Debug or monitor the active configuration without stopping the service:

```java
SdsStrategy current = SdsStrategyService.getInstance().getStrategy("CREATE_ORDER");
System.out.println("Current downgradeRate = " + current.getDowngradeRate());

```

Because the underlying map refreshes atomically, this call always reflects the latest configuration pulled from the admin server.

## Summary

- **Bytecode instrumentation** via `SdsClassFileTransformer` embeds downgrade checkpoints that reference dynamic strategy lookups, separating decision logic from business code.
- **Heartbeat pulling** through `SdsHeartBeatService` checks for configuration updates every 5 seconds via the `/sds/heartbeat/pullstrategy` endpoint.
- **Atomic map replacement** in `SdsStrategyService` uses `ConcurrentHashMap` and volatile references to swap entire strategy sets instantly without class redefinition.
- **Zero-downtime updates** allow in-flight requests to complete using old strategies while new requests immediately adopt updated thresholds.
- **Synchronized fallbacks** via `SdsDowngradeReturnValueService` ensure that return-value strategies hot-swap alongside downgrade decision logic.

## Frequently Asked Questions

### What triggers a strategy update in SDS?

The `SdsHeartBeatService` polls the SDS admin server every 5 seconds. When the server response indicates `changed=true`—typically because an operator modified thresholds through the admin console—the client parses the new strategy definitions and triggers the hot-swap. This pull-based model ensures the client always receives the latest configuration without requiring push notifications.

### Does hot-swapping require restarting the Java application?

No. The hot-swapping mechanism for dynamically adjusting SDS downgrade strategies operates entirely at runtime. The Java agent performs one-time bytecode instrumentation during `premain()`, after which strategies update through in-memory map replacement. No JVM restart, class reloading, or process interruption is required to apply new downgrade thresholds.

### How does SDS ensure thread safety during configuration updates?

Thread safety is achieved through two mechanisms. First, `SdsStrategyService` stores strategies in a `ConcurrentHashMap`, which provides thread-safe read operations. Second, the `resetAll()` method replaces the entire map reference atomically using a volatile field. This ensures that all `shouldDowngrade()` calls see a consistent strategy set, either the old or new configuration, never a partially updated state.

### What happens to requests currently executing during a hot-swap?

Requests in flight continue using the strategy map reference they obtained at the start of their execution. Because the old `ConcurrentHashMap` remains in memory until all references are released, ongoing method involutions complete safely. New requests that begin after the atomic swap immediately query the updated strategy thresholds, achieving zero-downtime configuration changes.