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.
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
endRedis 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.SentinelLimiterAopAfter 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
