Cloud Native 14 min read

Spring Cloud Microservices Tutorial – Sentinel for Fault Tolerance and Rate Limiting

This article walks through adding Alibaba Sentinel to a Spring Cloud microservice suite to protect against service outages, traffic spikes, and slow calls by configuring rate limiting, circuit breaking, and fallback mechanisms across user, order, and gateway services, with full Docker‑compose setup and testing steps.

Coder Trainee
Coder Trainee
Coder Trainee
Spring Cloud Microservices Tutorial – Sentinel for Fault Tolerance and Rate Limiting

Goal

Build a chain of services (client → Gateway → order‑service → user‑service) protected by Sentinel, providing:

Rate limiting – block requests when QPS exceeds a threshold.

Circuit breaking – open the circuit when error rate or slow‑call ratio is high.

Fallback – return default data when a downstream service is unavailable.

Why Service Fault Tolerance Is Needed

Service avalanche effect

User request → Gateway → order‑service → user‑service → DB
    ↓
user‑service timeout
    ↓
order‑service threads blocked
    ↓
Gateway threads blocked
    ↓
System crash

Sentinel solution

Traffic spike → Rate limiting (QPS / thread count)

Slow / timeout → Circuit breaking (slow‑call ratio)

Service error → Circuit breaking (exception ratio / count)

Upstream unavailable → Fallback

Project Structure (Sentinel added)

spring-cloud-teaching-ep06/
├── pom.xml                     # Sentinel dependency management
├── docker-compose.yml          # Sentinel dashboard container
├── user-service/               # Sentinel config for user service
├── order-service/              # ★ Feign + Sentinel circuit break
├── gateway/                    # Sentinel rate‑limit for gateway
└── README.md

Environment Preparation

1. Start Sentinel dashboard

# docker-compose.yml addition
sentinel:
  image: bladex/sentinel-dashboard:1.8.6
  container_name: sentinel-teaching
  ports:
    - "8858:8858"
  environment:
    - AUTH_USERNAME=sentinel
    - AUTH_PASSWORD=sentinel

2. Access the dashboard

Open http://localhost:8858 (username/password: sentinel / sentinel).

user‑service Integration

1. Dependency

<!-- user-service/pom.xml -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2. Configuration

# user-service/src/main/resources/application.yml
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8858
        port: 8719
      eager: true   # register immediately

3. Rate‑limit example

package com.teaching.user.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/api/sentinel")
public class SentinelController {
    @GetMapping("/test")
    @SentinelResource(value = "test-resource", blockHandler = "handleBlock")
    public Map<String, Object> test() {
        Map<String, Object> result = new HashMap<>();
        result.put("message", "正常响应");
        result.put("time", System.currentTimeMillis());
        return result;
    }

    // block handler
    public Map<String, Object> handleBlock(BlockException ex) {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 429);
        result.put("message", "请求过于频繁,请稍后重试");
        return result;
    }
}

order‑service Feign + Sentinel Circuit Break (Key Part)

1. Dependency

<!-- order-service/pom.xml -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2. Configuration

# order-service/src/main/resources/application.yml
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8858
        port: 8719
      eager: true
    feign:
      sentinel:
        enabled: true   # ★ Enable Feign‑Sentinel support

3. Feign client with fallback

package com.teaching.order.client;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.Map;

@FeignClient(name = "user-service", fallback = UserFeignClientFallback.class) // ★ configure fallback
public interface UserFeignClient {
    @GetMapping("/api/user/{id}")
    Map<String, Object> getUser(@PathVariable("id") Long id);
}
package com.teaching.order.client;

import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;

@Component
public class UserFeignClientFallback implements UserFeignClient {
    @Override
    public Map<String, Object> getUser(Long id) {
        Map<String, Object> fallback = new HashMap<>();
        fallback.put("id", id);
        fallback.put("name", "用户服务不可用(降级数据)");
        fallback.put("error", true);
        fallback.put("message", "服务熔断,返回默认数据");
        return fallback;
    }
}

4. Circuit‑breaker test endpoint

package com.teaching.order.controller;

import com.teaching.order.client.UserFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/api/circuit")
public class CircuitBreakerController {
    @Autowired
    private UserFeignClient userFeignClient;

    @GetMapping("/test")
    public Map<String, Object> testCircuitBreaker() {
        long start = System.currentTimeMillis();
        Map<String, Object> user = userFeignClient.getUser(1L); // may trigger fallback
        long cost = System.currentTimeMillis() - start;
        Map<String, Object> result = new HashMap<>();
        result.put("userInfo", user);
        result.put("costMs", cost);
        result.put("message", user.containsKey("error") ? "降级生效" : "正常调用");
        return result;
    }
}

Gateway Rate Limiting

1. Dependency

<!-- gateway/pom.xml -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

2. Configuration

# gateway/src/main/resources/application.yml
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8858
        port: 8719
      eager: true
      filter:
        enabled: true

3. Gateway rate‑limit rule (QPS = 5)

package com.teaching.gateway.config;

import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import jakarta.annotation.PostConstruct;
import java.util.HashSet;
import java.util.Set;

@Configuration
public class SentinelGatewayConfig {
    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }

    @PostConstruct
    public void initGatewayRules() {
        // 1. Define API group
        Set<ApiDefinition> apiDefinitions = new HashSet<>();
        ApiDefinition orderApi = new ApiDefinition("order-api")
            .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                add(new ApiPathPredicateItem()
                    .setPattern("/api/order/**")
                    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
            }});
        apiDefinitions.add(orderApi);
        GatewayApiDefinitionManager.loadApiDefinitions(apiDefinitions);

        // 2. Configure rate‑limit rule
        Set<GatewayFlowRule> gatewayRules = new HashSet<>();
        GatewayFlowRule orderRule = new GatewayFlowRule("order-api")
            .setCount(5)          // QPS = 5
            .setIntervalSec(1);
        gatewayRules.add(orderRule);
        GatewayRuleManager.loadRules(gatewayRules);
        System.out.println("✅ Sentinel gateway rate‑limit rule loaded");
    }
}

Verification Tests

1. Start all services

# Start Nacos + Sentinel
docker-compose up -d
# Start user‑service
cd user-service && mvn spring-boot:run
# Start order‑service
cd order-service && mvn spring-boot:run
# Start gateway
cd gateway && mvn spring-boot:run

2. Verify rate limiting (QPS > 5 should be blocked)

for i in {1..20}; do
  curl -s http://localhost:8080/api/order/1 | grep -o '"message":"[^"]*"'
  sleep 0.1
done

3. Verify circuit breaking & fallback

# Normal call (user‑service up)
curl http://localhost:8080/api/order/1
# Stop user‑service, then call order‑service to trigger fallback
curl http://localhost:8082/api/circuit/test

4. Observe metrics in Sentinel dashboard

Open http://localhost:8858 to view service list, real‑time metrics, and the configured rate‑limit and circuit‑break rules.

Common Issues & Troubleshooting

Issue 1: Service not shown in Sentinel console

Cause: Lazy registration – the service registers only after the first request.

Solution: Send an initial request or enable eager registration with eager: true in application.yml.

Issue 2: Feign fallback not triggered

Confirm feign.sentinel.enabled=true is set.

Ensure the fallback class is annotated with @Component.

Verify the @FeignClient declaration includes fallback = ….

Issue 3: Gateway rate limiting ineffective

Check that the SentinelGatewayFilter bean is present.

Confirm the rule is loaded (log should contain “✅ Sentinel gateway rate‑limit rule loaded”).

Verify the URL pattern in the rule matches the actual request path.

Code Structure Overview

spring-cloud-teaching-ep06/
├── pom.xml
├── docker-compose.yml
├── user-service/
│   ├── pom.xml
│   ├── src/main/resources/application.yml
│   └── src/main/java/.../controller/SentinelController.java
├── order-service/
│   ├── pom.xml
│   ├── src/main/resources/application.yml
│   └── src/main/java/.../client/UserFeignClientFallback.java
├── gateway/
│   ├── pom.xml
│   ├── src/main/resources/application.yml
│   └── src/main/java/.../config/SentinelGatewayConfig.java
└── README.md
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.

Microservicesfault tolerancefeignsentinelgatewayrate limitingSpring Cloudcircuit breaker
Coder Trainee
Written by

Coder Trainee

Experienced in Java and Python, we share and learn together. For submissions or collaborations, DM us.

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.