【Pigeon源码阅读】高可用之服务限流实现原理(十二)

本文详细解析了Pigeon服务限流的实现,包括应用限流、应用方法级别限流、单机总限流和方法线程数限制。通过流量统计原理和流量桶定义,阐述了如何在不同维度进行限流,并展示了关键代码实现。
摘要由CSDN通过智能技术生成

pigeon服务限流

pigeon支持4个纬度的限流策略,当客户端请求达到服务端统计的限流阈值时,会抛出RejectedException。具体限流策略包括:

  1. 应用限流:限制某个客户端应用的最大QPS
  2. 应用方法限流:限制某个客户端应用访问某个服务方法的最大QPS
  3. 单机总限流:限制服务端单机的最大QPS
  4. 方法线程数限流:限制单个方法最大访问线程数,避免因为单个方法异常流量过大阻塞线程池,导致其他方法没有线程去执行导致饥饿。

流量统计原理

限流实现源码定义在GatewayProcessFilter,是pigeon服务端处理客户端RPC请求拦截器链中的一员。在拦截器方法invoke的入口和出口,有专门的计数器会对请求处理的流入流出进行统计,相关代码行实现为:

try {
   
    // 流量流入计数
    ProviderStatisticsHolder.flowIn(request);
    if (Constants.MESSAGE_TYPE_SERVICE == request.getMessageType()) {
   
        // 省略具体的限流检测逻辑,在下面展开分析
        // ……代码省略
        
        // 交由下一个拦截器处理
        response = handler.handle(invocationContext);
        return response;
    }
} finally {
   
    // 请求方法处理计数减一
    if (Constants.MESSAGE_TYPE_SERVICE == request.getMessageType() && enableMethodThreadsLimit) {
   
        decrementRequest(requestMethod);
    }
    // 流量流出,异步和手动响应需要在别的地方处理
    if (!(Constants.REPLY_MANUAL || invocationContext.isAsync())) {
   
        ProviderStatisticsHolder.flowOut(request);
    }
}

流量的流入流出逻辑主要通过ProviderStatisticsHolder的flowIn和flowOut方法实现:

public static void flowIn(InvocationRequest request) {
   
    // messageType=MESSAGE_TYPE_SERVICE & statEnable配置允许
    if (checkRequestNeedStat(request)) {
   
        // app level,根据app name从appCapacityBuckets中获取,如果没有则初始化一个
        ProviderCapacityBucket barrel = getCapacityBucket(request);
        if (barrel != null) {
   
            barrel.flowIn(request);
        }

        // method level,根据requestMethod从methodCapacityBuckets中获取,如果没有则初始化一个
        final String requestMethod = request.getServiceName() + "#" + request.getMethodName();
        ProviderCapacityBucket methodBarrel = getCapacityBucket(requestMethod);
        if (methodBarrel != null) {
   
            methodBarrel.flowIn(request);
        }

        // method app level,基于特定方法从methodAppCapacityBuckets拿到指定桶Map,再根据请求app拿到具体桶,中间如果没有都会初始化一个
        ProviderCapacityBucket methodAppBarrel = getMethodAppCapacityBucket(request);
        if (methodAppBarrel != null) {
   
            methodAppBarrel.flowIn(request);
        }

        // global level 全局流量桶
        globalCapacityBucket.flowIn(request);
    }
}

public static void flowOut(InvocationRequest request) {
   
    // messageType=MESSAGE_TYPE_SERVICE & statEnable配置允许
    if (checkRequestNeedStat(request)) {
   
        // app level
        ProviderCapacityBucket barrel = getCapacityBucket(request);
        if (barrel != null) {
   
            barrel.flowOut(request);
        }

        // method level
        final String requestMethod = request.getServiceName() + "#" + request.getMethodName();
        ProviderCapacityBucket methodBarrel = getCapacityBucket(requestMethod);
        if (methodBarrel != null) {
   
            methodBarrel.flowOut(request);
        }

        // method app level
        ProviderCapacityBucket methodAppBarrel = getMethodAppCapacityBucket(request);
        if (methodAppBarrel != null) {
   
            methodAppBarrel.flowOut(request);
        }

        // global level
        globalCapacityBucket.flowOut(request);
    }
}

从上面的流量统计中,可以看到流量桶都是基于ProviderCapacityBucket实现的,并且对应有4种类型流量桶变量:

  1. appCapacityBuckets:统计指定应用流量
  2. methodCapacityBuckets: 统计指定服务方法流量,服务方法通过serviceName + "#" + methodName定义,不在当前限流逻辑中使用。
  3. methodAppCapacityBuckets:统计指定服务方法下,特定应用请求的流量
  4. globalCapacityBucket: 全局流量桶

流量桶定义

流量桶的实现类为ProviderCapacityBucket,具体以三个纬度的成员变量来存储统计流量:

// 流经流量桶的总请求量
private AtomicInteger requests = new AtomicInteger();
// 秒级请求量,容量固定为60,对应一分钟每秒
private Map<Integer, AtomicInteger> totalRequestsInSecond = new ConcurrentHashMap<Integer, AtomicInteger>();
// 分钟级请求量,容量固定为60,对应一小时每分钟
private Map<Integer, AtomicInteger> totalRequestsInMinute = new ConcurrentHashMap<Integer, AtomicInteger>()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值