Master Traffic Coloring & Gray Release with Spring Cloud Gateway

This article explains how to use Spring Cloud Gateway for traffic coloring and gray release, enabling you to tag requests, route VIP or test traffic to new service versions gradually, and ensure safe, controlled rollouts in production environments.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Master Traffic Coloring & Gray Release with Spring Cloud Gateway

What is traffic coloring? Why do we need it?

Traffic coloring means adding an identity tag to a request so that all services in the call chain can recognize it. For example, when launching a new feature for a VIP user, the gateway adds X-Traffic-Tag: vip to the request header, allowing downstream services such as order, payment, and logging to handle the request differently.

Traffic coloring breaks the limitation of treating all traffic the same; with tags, gray release, A/B testing, and environment isolation become possible.

What is gray release?

Based on traffic‑coloring tags, gray release lets a portion of traffic run the new version while the rest stays on the old version, verifying stability step by step.

Pre‑release: only internal test accounts (tag test) use the new version.

Early stage: 5% of VIP users (tag vip) use the new version.

Mid stage: increase to 30‑50% of VIP users.

Full release: after confirming stability, all users switch to the new version.

If a problem appears (e.g., VIP users encounter order failures), the gray rule can be turned off, rolling all traffic back to the old version with minimal impact.

By proportion: route 10% of traffic based on user‑ID modulo.

By scenario: only the "new user registration" API goes to the new version.

By device: iOS users first, Android later.

Implement traffic coloring + gray release

The process consists of three steps: request coloring → gray routing → effect verification.

Project dependencies

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!-- Service discovery if routing to a registry -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

Step 1: Implement traffic coloring

Use a GlobalFilter with order -1 to ensure it runs before authentication or rate‑limiting filters. The filter extracts the user type from request parameters or cookies and injects the appropriate X-Traffic-Tag header.

@Configuration
public class TrafficDyeFilterConfig {
    // Order(-1) ensures the filter runs first
    @Bean
    @Order(-1)
    public GlobalFilter trafficDyeFilter() {
        return (exchange, chain) -> {
            // 1. Get user type from request
            String userType = getUserTypeFromRequest(exchange);
            // 2. Determine traffic tag
            String trafficTag = getTrafficTagByUserType(userType);
            // 3. Inject tag into request header
            exchange.getRequest().mutate()
                .header("X-Traffic-Tag", trafficTag)
                .build();
            // 4. Continue filter chain
            return chain.filter(exchange);
        };
    }

    private String getUserTypeFromRequest(ServerWebExchange exchange) {
        List<String> userTypeParams = exchange.getRequest().getQueryParams().get("userType");
        if (userTypeParams != null && !userTypeParams.isEmpty()) {
            return userTypeParams.get(0);
        }
        return "normal";
    }

    private String getTrafficTagByUserType(String userType) {
        switch (userType) {
            case "vip":
                return "vip";
            case "test":
                return "test";
            default:
                return "normal";
        }
    }
}

Key notes : Order(-1) is crucial so the tag is available to downstream filters.

The tag is placed in the request header X-Traffic-Tag, which downstream services can read via request.getHeader("X-Traffic-Tag").

To add more complex rules (e.g., user‑ID modulo), extend getUserTypeFromRequest.

Step 2: Implement gray routing

Create a custom RoutePredicateFactory that checks the X-Traffic-Tag header against an allowed list (e.g., ["vip", "test"]). If the tag matches, the request is routed to the new service version.

@Configuration
public class GrayRoutePredicateFactory extends AbstractRoutePredicateFactory<GrayRoutePredicateFactory.Config> {
    private static final String TRAFFIC_TAG_HEADER = "X-Traffic-Tag";

    public GrayRoutePredicateFactory() {
        super(Config.class);
    }

    public static class Config {
        @NotEmpty
        private List<String> allowTags;
        public List<String> getAllowTags() { return allowTags; }
        public void setAllowTags(List<String> allowTags) { this.allowTags = allowTags; }
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("allowTags");
    }

    @Override
    public GatewayPredicate apply(Config config) {
        return exchange -> {
            List<String> trafficTags = exchange.getRequest().getHeaders().get(TRAFFIC_TAG_HEADER);
            if (trafficTags == null || trafficTags.isEmpty()) {
                return false;
            }
            String trafficTag = trafficTags.get(0);
            return config.getAllowTags().contains(trafficTag);
        };
    }

    @Override
    public String toString() {
        return "GrayRoutePredicate{allowTags=" + config.getAllowTags() + "}";
    }
}

Configure gateway routes

spring:
  cloud:
    gateway:
      routes:
        # Gray route for VIP/test tags → new version
        - id: gray_route_v2
          uri: lb://order-service-v2
          predicates:
            - name: GrayRoute
              args:
                allowTags[0]: vip
                allowTags[1]: test
            - Path=/api/order/**
          filters:
            - RewritePath=/api/(?<segment>.*),/${segment}
        # Normal route → old version
        - id: normal_route_v1
          uri: lb://order-service-v1
          predicates:
            - Path=/api/order/**
          filters:
            - RewritePath=/api/(?<segment>.*),/${segment}

Key notes :

Use lb:// to enable load‑balancing via the service registry.

Place the gray route before the normal route so it matches first.

For percentage‑based gray releases, add modulo logic inside the predicate factory.

Step 3: Verify the effect

After deploying the code and configuration, send a request such as http://gateway-ip:port/api/order/create?userType=vip. The request should be forwarded to order-service-v2. Use tools like Postman to confirm routing.

Production considerations

1. Tag propagation

Ensure X-Traffic-Tag is passed through the entire call chain (e.g., gateway → order service → inventory service). When using OpenFeign, add a request interceptor to forward the header; with Dubbo, implement a similar filter.

@Component
public class FeignTrafficTagInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        String trafficTag = TrafficTagContextHolder.get();
        if (trafficTag != null) {
            template.header("X-Traffic-Tag", trafficTag);
        }
    }
}

2. Dynamic gray rule adjustment

Store gray rules (allowed tags, percentages) in Nacos configuration. Let the gateway listen for changes and update the predicate factory without restarting.

3. Fast rollback

Add a gray switch in Nacos (e.g., gray.switch=false). The custom predicate should first check this switch; if disabled, all traffic routes to the old version.

Final thoughts

The gateway is more than a simple forwarder; it is the traffic control center. By using traffic coloring and gray release, you can safely roll out new features, limit risk, and demonstrate mastery of Spring Cloud Gateway in interviews.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Backendmicroservicesgray-releasetraffic coloringSpring Cloud Gateway
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.