Dubbo高可用之限流
服务端连接控制
dubbo-samples-xml-provider:限制当前提供者在使用dubbo协议最多接受10个消费者链接
<!--限制当前提供者在使用dubbo协议最多接受accepts个消费者链接,如果消费者个数超过了会报错-->
<dubbo:protocol name="dubbo" port="-1" accepts="1"/>
启动多个消费者,会报错:
并发控制
dubbo-samples-xml-provider:限制服务端(或具体方法)并发执行(或占用线程池线程数)不能超过1个:
<!--服务的每个方法的服务端并发执行(或占用线程池线程数)不能超过executes个,超过了,消费端调用会报错:
cause: The service using threads greater than <dubbo:service executes="1" /> limited.-->
<dubbo:service interface="com.harvey.samples.client.OrderService" ref="orderServiceImpl"
protocol="dubbo" group="one" executes="1"/>
ConsumerStarter.java
public class ConsumerStarter {
public static void main(String[] args) throws IOException, InterruptedException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/dubbo-consumer.xml"});
context.start();
System.out.println("consumer start.....");
//dubbo
OrderService orderService = context.getBean("orderService", OrderService.class);
CyclicBarrier barrier = new CyclicBarrier(30);
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(30);
for (int i = 0; i < 30; i++) {
fixedThreadPool.submit(new InvokerRunnable(orderService, barrier));
}
fixedThreadPool.shutdown();
}
static class InvokerRunnable implements Runnable {
private OrderService orderService;
private CyclicBarrier cyclicBarrier;
public InvokerRunnable(OrderService orderService, CyclicBarrier cyclicBarrier) {
this.orderService = orderService;
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + ":等待");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + ":开始运行");
Random rm = new Random();
long orderId = rm.nextInt(100) + 1;
Order order = orderService.getOrderInfo(orderId);
System.out.println(Thread.currentThread().getName() + " --> SUCCESS: got getOrderInfo " + order);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
actives限流
该限流方式与前两种不同,其可以设置在提供端,也可以设置在消费者端。可以设置为接口级别,也可以设置为方法级别。
根据消费者与提供者建立的连接类型,其意义也不同。
- 长连接: 表示当前的长连接最多可以处理的请求个数。与长连接的数量没有关系。
- 短连接:表示当前服务可以同时处理的短连接数量。
<dubbo:service interface="com.harvey.samples.client.OrderService" ref="orderServiceImpl"
protocol="dubbo" group="one" actives="1"/>
<dubbo:reference id="orderService" interface="com.harvey.samples.client.OrderService"
protocol="dubbo" group="one" actives="1"/>
消费端并发调用的时候,会报错:
connections限流
可以设置在提供端,也可以设置在消费者端。限定连接的个数。对于短连接,和actives相同。但对于长连接,表示长连接的个数。
一般情况下,会使connections与actives联用,让connections限制长连接的个数,让actives限制长连接中可以处理的请求个数。
限制客户端服务使用连接不能超过1个:
<dubbo:service interface="com.harvey.samples.client.OrderService" ref="orderServiceImpl"
protocol="dubbo" group="one" connections="1"/>
如果<dubbo:service>和<dubbo:reference>都配置了connections,<dubbo:reference>优先。
延迟连接
延迟连接仅可以设置在消费者端,并且不能设置为方法级别。仅作用于Dubbo服务暴露协议。将长连接的建立推迟到消费者真正调用提供者时。 可以减少长连接的数量。
<!--设置当前消费者对接口中的每个方法发出链接采用延迟加载-->
<dubbo:reference id="orderService" interface="com.harvey.samples.client.OrderService"
protocol="dubbo" group="one" lazy="true"/>
附:源码分析
实际上上面的逻辑都是一个个Filter,所有的Filter会连接成一个过滤器链,每次请求都会经过整个链路中的每一个Filter。那它是在什么时候构造成一个过滤器链的呢。
1)ExecuteLimitFilter:它用于限制每个服务中每个方法的最大并发数,有接口级别和方法级别的配置方式。
基本原理:在框架中使用一个ConcurrentMap缓存了并发数的计数器,为每个请求URL生成一个IdentityString,并以此为key;再将每个IdentityString生成一个RpcStatus对象,将此作为value。RpcStatus对象用于记录对应的并发数。在调用开始之前,会通过URL获得RpcStatus对象,把对象中的并发数计数器原子+1,在finally中再将原子减1。只要在计数器+1的时候,发现当前计数器比设置的并发数大时,就会抛出异常。
2)TpsLimitFilter
TpsLimitFilter的限流是基于令牌的,即一段时间内只分配N个令牌,每次请求都会消耗一个令牌,耗完为止,后面再来的请求都会被拒绝。
具体的逻辑是在DefaultTPSLimiter#isAllowable,会用这个方法判断是否触发限流。
在DefaultTPSLimiter内部用一个ConcurrentHashMap缓存每个接口的令牌数,key是interface+group+version,value是一个StatItem对象,它包装了令牌刷新时间间隔、每次发放的令牌数等。首先判断当前时间减去上次发放令牌的时间是否超过了时间间隔,超过了就重新发放令牌,之前剩余的令牌会被直接覆盖掉。然后,通过CAS的方式减去1令牌,减掉后小于0就会触发限流。
3)ActiveLimitFilter
和服务提供者的ExecuteLimitFilter相似,它是消费者端的过滤器,限制的是客户端的并发量。
但是它与ExecuteLimitFilter有所不同,它不会直接抛出异常。而是当到达阈值的时候,会先加锁抢占当前接口的RpcStatus对象,然后通过wait方法进行等待,等待是有时间的,因为请求是有timeout属性的。然后如果某个Invoker在调用结束后,并发把计数器减-1并触发一个notify,此时会有一个在wait状态的线程被唤醒并继续执行,判断现在是否超时,如果超时则抛出异常。如果当前并发数仍然超出阈值,则继续执行wait方法;如果没有超出阈值在,则跳出循环,CAS+1,并调用invoke方法,调用结束后CAS-1,最后通过notify唤醒另外一个线程。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!