【Pigeon源码阅读】服务提供响应流程解析(七)

本文深入剖析了Pigeon服务提供方的响应流程,从NettyServerHandler接收请求开始,详细讲解了RequestThreadPoolProcessor的工作原理,包括拦截器链初始化、线程池选取策略、流量控制机制。同时,介绍了SecurityFilter的IP黑白名单、APP黑白名单和Token鉴权等安全措施,以及GateWayProcessFilter的流量计数和限流策略。最后,探讨了BusinessProcessFilter如何通过反射调用业务方法并找到最佳匹配。
摘要由CSDN通过智能技术生成

Netty接收调用方请求过程

作为服务提供方,需要接收来自调用方的请求,这一步在NettyServerHandler内完成。NettyServerHandler继承了netty的SimpleChannelUpstreamHandler接口,在NettyServerPipelineFactory中创建,作为netty处理连接pipeline的最后一个处理器,先看看NettyServerPipelineFactory的实现:

public class NettyServerPipelineFactory implements ChannelPipelineFactory {
   

    private NettyServer server;

    private static CodecConfig codecConfig = CodecConfigFactory.createClientConfig();

    public NettyServerPipelineFactory(NettyServer server) {
   
        this.server = server;
    }

    public ChannelPipeline getPipeline() {
   
        ChannelPipeline pipeline = pipeline();
        pipeline.addLast("framePrepender", new FramePrepender());
        pipeline.addLast("frameDecoder", new FrameDecoder());
        pipeline.addLast("crc32Handler", new Crc32Handler(codecConfig));
        pipeline.addLast("compressHandler", new CompressHandler(codecConfig));
        pipeline.addLast("providerDecoder", new ProviderDecoder());
        pipeline.addLast("providerEncoder", new ProviderEncoder());
        pipeline.addLast("serverHandler", new NettyServerHandler(server));
        return pipeline;
    }

}

从源码上看,请求从进入netty服务器到NettyServerHandler,已经完成了请求数据解压缩、校验、解密等流程,进入到了真正的处理逻辑。最终调用了NettyServerHandler#messageReceived方法,来处理消息接收请求,具体源码

public void messageReceived(ChannelHandlerContext ctx, MessageEvent message) {
   
    // 解密获取真正的InvocationRequest
    CodecEvent codecEvent = (CodecEvent) (message.getMessage());

    if (!codecEvent.isValid() || codecEvent.getInvocation() == null) {
   
        return;
    }

    InvocationRequest request = (InvocationRequest) codecEvent.getInvocation();
    // 用DefaultProviderContext包装InvocationRequest请求
    ProviderContext invocationContext = new DefaultProviderContext(request, new NettyServerChannel(ctx.getChannel()));
    try {
   
        // 处理请求
        this.server.processRequest(request, invocationContext);

    } catch (Throwable e) {
   
        String msg = "process request failed:" + request;
        // 心跳消息只返回正常的, 异常不返回
        if (request.getCallType() == Constants.CALLTYPE_REPLY
                && request.getMessageType() != Constants.MESSAGE_TYPE_HEART) {
   
            ctx.getChannel().write(ProviderUtils.createFailResponse(request, e));
        }
        log.error(msg, e);
    }
}

RequestThreadPoolProcessor 请求线程池处理器

紧接上面,调用了NettyServer的processRequest方法:

public abstract class AbstractServer implements Server {
   
    // ……省略部分代码
    public Future<InvocationResponse> processRequest(InvocationRequest request, ProviderContext providerContext) {
   
        // 这里requestProcessor的具体实例是RequestThreadPoolProcessor
        return requestProcessor.processRequest(request, providerContext);
    }
    // ……省略部分代码
}

从上面源码看,processRequest方法定义在NettyServer的父类AbstractServer中,内部又调用了RequestProcessor#processRequest方法。而具体requestProcessor的初始化逻辑是通过RequestProcessorFactory实现的:

public class RequestProcessorFactory {
   
    
    public static RequestProcessor selectProcessor() {
   
        // 先尝试加载用户定义在文件里的
        RequestProcessor requestProcessor = ExtensionLoader.getExtension(RequestProcessor.class);
        if (requestProcessor != null) {
   
            return requestProcessor;
        } else {
   
            // 默认返回
            return new RequestThreadPoolProcessor();
        }
    }
}

在实际访问中,如果没有自定义处理器,使用的就是RequestThreadPoolProcessor。RequestThreadPoolProcessor继承自AbstractRequestProcessor,而AbstractRequestProcessor又实现了RequestProcessor的方法。
RequestThreadPoolProcessor用于管理请求相关的线程池,可以根据不同请求找到特定的poolConfig,再通过poolConfig定位到相应的线程池来处理特定的请求,以完成不同方法请求的定制管理如刷新、隔离等特性。
先看AbstractRequestProcessor#processRequest方法:

public Future<InvocationResponse> processRequest(final InvocationRequest request, final ProviderContext providerContext) {
   
    
    if (request.getCreateMillisTime() == 0) {
   
        request.setCreateMillisTime(System.currentTimeMillis());
    }
    Future<InvocationResponse> invocationResponse = null;
    try {
   
        // 在子类实现,完成具体的请求处理逻辑
        invocationResponse = doProcessRequest(request, providerContext);
    } catch (Throwable e) {
   
        String msg = "process request failed:" + request;
        // 心跳消息只返回正常的, 异常不返回
        if (request.getCallType() == Constants.CALLTYPE_REPLY
                && request.getMessageType() != Constants.MESSAGE_TYPE_HEART) {
   
            providerContext.getChannel().write(providerContext, ProviderUtils.createFailResponse(request, e));
        }
        // logger.error(msg, e);
    }
    providerContext.setFuture(invocationResponse);
    return invocationResponse;
}

再看子类RequestThreadPoolProcessor#doProcessRequest方法实现:

public Future<InvocationResponse> doProcessRequest(final InvocationRequest request, final ProviderContext providerContext) {
   
    requestContextMap.put(request, providerContext);
    // 开启数据监控
    startMonitorData(request, providerContext);
    // 创建一个Callable对象,在下面选取合适的线程池执行
    Callable<InvocationResponse> requestExecutor = new Callable<InvocationResponse>() {
   

        @Override
        public InvocationResponse call() throws Exception {
   
            providerContext.getTimeline().add(new TimePoint(TimePhase.T));
            try {
   
                // 根据消息类型,选择相应的拦截器链来处理请求
                ServiceInvocationHandler invocationHandler = ProviderProcessHandlerFactory .selectInvocationHandler(providerContext.getRequest().getMessageType());
                if (invocationHandler != null) {
   
                    providerContext.setThread(Thread.currentThread());
                    // 交由具体的拦截器链开始处理
                    return invocationHandler.handle(providerContext);
                }
            } catch (Throwable t) {
   
                logger.error("Process request failed with invocation handler, you should never be here.", t);
            } finally {
   
                requestContextMap.remove(request);
            }
            return null;
        }
    };
    // 选取特定的线程池
    final ThreadPool pool = selectThreadPool(request);

    try {
   
        // 通过GatewayProcessFilter的流量桶,判断特定请求池有没到达配置阈值,如果到达则触发限流拒绝请求
        checkRequest(pool, request);
        providerContext.getTimeline().add(new TimePoint(TimePhase.T));
        // 线程池执行请求
        return pool.submit(requestExecutor);
    } catch (RejectedExecutionException e) {
   
        requestContextMap.remove(request);
        endMonitorData(request, providerContext);
        throw new RejectedException(getProcessorStatistics(pool), e);
    }

}

拦截器链初始化原理

在选择特定的拦截器链一步,对于正常的业务请求,选取的是bizInvocationHandler,里面的拦截器链初始化如下:

// 调用链追踪拦截器,记录分布式链路追踪上下文
registerBizProcessFilter(new TraceFilter());
if (Constants.MONITOR_ENABLE) {
   
    // 调用监控拦截器,添加调用上下文信息打点
    registerBizProcessFilter(new MonitorProcessFilter());
}
// 记录当前处理流程,处理自定义拦截器逻辑,在拦截器回调时调用ProviderProcessInterceptor的postInvoke方法
registerBizProcessFilter(new WriteResponseProcessFilter());
// 调用链上线文信息传递处理拦截器
registerBizProcessFilter(new ContextTransferProcessFilter());
// 异常处理拦截器
registerBizProcessFilter(new ExceptionProcessFilter());
// 鉴权处理拦截器
registerBizProcessFilter(new SecurityFilter());
// 网关处理拦截器,限制调用来源等
registerBizProcessFilter(new GatewayProcessFilter());
// 业务逻辑拦截器,先调用ProviderProcessInterceptor的preInvoke方法,再调用实际的服务提供方方法
registerBizProcessFilter(new BusinessProcessFilter());
bizInvocationHandler = createInvocationHandler(bizProcessFilters);

最终创建调用了createInvocationHandler方法:

private static <K, V extends ServiceInvocationFilter> ServiceInvocationHandler createInvocationHandler(
        List<V> internalFilters) {
   
    ServiceInvocationHandler last = null;
    List<V> filterList = new ArrayList<V>();
    filterList.addAll(internalFilters);
    for (int i = filterList.size() - 1; i >= 0; i--) {
   
        final V filter = filterList.get(i);
        final ServiceInvocationHandler next = last;
        last = new ServiceInvocationHandler() {
   
            @SuppressWarnings("unchecked")
            @Override
            public InvocationResponse handle(InvocationContext invocationContext) throws Throwable {
   
                return filter.invoke(next, invocationContext);
            }
        };
    }
    return last;
}

类似于服务调用方请求流程分析,拦截器链的执行流程和上面的添加顺序是一致的。

线程池选取原理

先看看代码的具体实现:

private ThreadPool selectThreadPool(final InvocationRequest request) {
   
    ThreadPool pool = null;
    String serviceKey = request.getServiceName();
    String methodKey = serviceKey + "#" + request.getMethodName();

    // 根据请求的serviceName获取指定的服务ProviderConfig
    // 如果配置了useSharedPool=true,会进一步根据是否存在方法级配置为每个服务获取一个独立的线程池
    pool = getConfigThreadPool(request);

    // 服务的poolConfig方式配置
    if (pool == null && !CollectionUtils.isEmpty(methodThreadPools)) {
   
        pool = methodThreadPools.get(methodKey);
    }
    // 方法级设置方式线程池获取
    if (pool == null && !CollectionUtils.isEmpty(serviceThreadPools)) {
   
        pool = serviceThreadPools.get(serviceKey);
    }

    // lion 线程池配置
    if (pool == null && poolConfigSwitchable && !CollectionUtils.isEmpty(apiPoolNameMapping)) {
   
        PoolConfig poolConfig = null;
        String poolName = apiPoolNameMapping.get(methodKey);
        if (StringUtils.isNotBlank(poolName)) {
    // 方法级别
            poolConfig = poolConfigs.get(poolName);
            if (poolConfig != null) {
   
                pool = DynamicThreadPoolFactory.getThreadPool(poolConfig);
            }
        } else {
    // 服务级别
            poolName = apiPoolNameMapping.get(serviceKey);
            if (StringUtils.isNotBlank(poolName)) {
   
                poolConfig = poolConfigs.get(poolName);
                if (poolConfig != null) {
   
                    pool = DynamicThreadPoolFactory.getThreadPool(poolConfig);
                }
            }
        }
    }

    // 默认方式,针对是否慢请求,为其选择相应的线程池
    if (pool == null) {
   
        if (enableSlowPool && requestTimeoutListener.isSlowRequest(request)) {
   
            pool = slowRequestProcessThreadPool;
        } else {
   
            pool = sharedRequestProcessThreadPool;
        }
    }

    return pool;
}

private ThreadPool getConfigThreadPool(InvocationRequest request) {
   
    String serviceName = request.getServiceName();
    String methodName = request.getMethodName();
    // 根据请求的serviceName获取指定的服务ProviderConfig
    if (StringUtils.isNotBlank(serviceName) && StringUtils.isNotBlank(methodName)) {
   
        ProviderConfig providerConfig = ServicePublisher.getServiceConfig(serviceName);
        // 配置是否需要为每个方法分配独立线程池
        if (providerConfig != null && needStandalonePool(providerCo
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值