Mastering Rate Limiting in Microservices: From Dubbo to Redis, Sentinel and Custom Starters

This article explains why rate limiting is critical for micro‑service architectures, compares implementations across Dubbo, Spring Cloud, Guava, Sentinel and Redis+Lua, and shows how to build reusable AOP annotations and a Spring‑Boot starter to apply throttling consistently across services.

Architect
Architect
Architect
Mastering Rate Limiting in Microservices: From Dubbo to Redis, Sentinel and Custom Starters

1. Background

Rate limiting is essential in a micro‑service system; without it a single overloaded service can become a hidden avalanche factor that blocks, queues, or times out subsequent requests until the JVM resources are exhausted.

2. Rate‑Limiting Overview

When choosing a technology stack (Dubbo, Spring Cloud, Spring Boot, etc.) the rate‑limiting solution must be adapted to the specific framework.

2.1 Dubbo Service Governance

Dubbo uses Netty and offers both client‑side and server‑side throttling.

Client throttling: semaphore‑based, connection‑count throttling.

Server throttling: thread‑pool isolation, semaphore throttling, connection‑count throttling.

2.1.2 Thread‑Pool Configuration

Configure the thread pool in <dubbo:protocol> with parameters such as pool type, queue size, and core thread count.

2.1.3 Third‑Party Integration

For Spring Boot projects you can integrate Hystrix, Guava, or the native Sentinel SDK.

2.2 Spring Cloud Service Governance

Spring Cloud and Spring Cloud Alibaba already include rate‑limiting components that work out‑of‑the‑box.

2.2.1 Hystrix

Hystrix provides rate limiting, circuit breaking and fallback capabilities; it can be enabled at the gateway or per service.

Hystrix defaults to thread‑isolation; configure thread count and queue size to control the limit.

2.2.2 Sentinel

Sentinel is the traffic‑defense component of the Spring Cloud Alibaba ecosystem, offering flow control, circuit breaking, load protection and hotspot limiting.

2.3 Gateway‑Level Rate Limiting

When many services need throttling, a gateway can filter malicious requests, crawlers and attacks, providing a global protection layer.

3. Common Rate‑Limiting Strategies

3.1 Token‑Bucket Algorithm

The token‑bucket algorithm is the most widely used method. Tokens represent permission to process a request; if no token is available the request is queued or dropped.

3.2 Leaky‑Bucket Algorithm

The leaky‑bucket algorithm stores incoming requests in a bucket; when the bucket is full new requests are discarded.

3.3 Sliding Window

A sliding time window counts requests in recent sub‑intervals; expanding the window smooths throttling effects.

4. General Rate‑Limiting Implementations

4.1 Guava‑Based Limiting

Add Guava as a dependency and create a custom annotation to mark methods that need throttling.

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>23.0</version>
</dependency>

Define @RateConfigAnno with limitType and limitCount, then implement an AOP class that obtains a RateLimiter and either proceeds or returns a JSON error when the limit is reached.

@Aspect
@Component
public class GuavaLimitAop {
    private static final Logger logger = LoggerFactory.getLogger(GuavaLimitAop.class);
    private final Map<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>();
    @Pointcut("@annotation(com.congge.annotation.RateConfigAnno)")
    public void pointcut() {}
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        RateConfigAnno anno = method.getAnnotation(RateConfigAnno.class);
        RateLimiter limiter = rateLimiters.computeIfAbsent(method.toString(), k -> RateLimiter.create(anno.limitCount()));
        if (limiter.tryAcquire()) {
            return joinPoint.proceed();
        }
        HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        JSONObject json = new JSONObject();
        json.put("success", false);
        json.put("msg", "限流中");
        resp.setContentType("application/json;charset=UTF-8");
        resp.getWriter().write(json.toJSONString());
        return null;
    }
}

4.2 Sentinel‑Based Limiting

Include sentinel‑core and create a custom annotation. The AOP class registers a flow rule and uses SphU.entry to protect the resource.

@Aspect
@Component
public class SentinelMethodLimitAop {
    @Pointcut("@annotation(com.congge.annotation.SentinelLimitAnnotation)")
    public void pointcut() {}
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        SentinelLimitAnnotation anno = method.getAnnotation(SentinelLimitAnnotation.class);
        initFlowRule(anno.resourceName(), anno.limitCount());
        try (Entry entry = SphU.entry(anno.resourceName())) {
            return joinPoint.proceed();
        } catch (BlockException e) {
            return "被限流了";
        }
    }
    private void initFlowRule(String resource, int count) {
        FlowRule rule = new FlowRule(resource);
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(count);
        FlowRuleManager.loadRules(Collections.singletonList(rule));
    }
}

4.3 Redis + Lua Limiting

Redis provides atomic operations and thread‑safety. Write a Lua script that increments a counter and expires it, then invoke the script via RedisTemplate inside an AOP interceptor.

local key = "rate.limit:" .. KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('get', key) or "0")
if current + 1 > limit then
  return 0
else
  redis.call("INCRBY", key, "1")
  redis.call("expire", key, "2")
  return current + 1
end

Redis Configuration

@Bean
public DefaultRedisScript<Number> redisluaScript() {
    DefaultRedisScript<Number> script = new DefaultRedisScript<>();
    script.setScriptSource(new ResourceScriptSource(new ClassPathResource("limit.lua")));
    script.setResultType(Number.class);
    return script;
}

5. Building a Rate‑Limiting Starter

Package the annotations, AOP classes and spring.factories into a JAR so other micro‑services can simply add the dependency and gain out‑of‑the‑box throttling.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.congge.aop.SemaphoreLimiterAop,\
  com.congge.aop.GuavaLimiterAop,\
  com.congge.aop.SentinelLimiterAop

After publishing the JAR, import it in any Spring Boot project and annotate methods with @TokenBucketLimiter, @ShLimiter or @SentinelLimiter to activate the corresponding throttling strategy.

6. Conclusion

Rate limiting is a crucial part of service governance; the article demonstrated several practical implementations (Dubbo, Spring Cloud, Guava, Sentinel, Redis+Lua) and showed how to encapsulate them into a reusable Spring Boot starter for consistent protection across micro‑service ecosystems.

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.

sentinelGuavaLua
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

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.