Dubbo服务提供端处理请求的过程剖析

1 处理请求的过程概述

(1)消费端发起TCP连接后,服务提供方的NettyServer的connected方法将被调用;

(2)因为Netty默认的线程模型为All,因此AllChannelHandler类把接收到的所有消息(包括请求事件、响应事件、连接事件、断开事件,心跳事件等)包装成ChannelEventRunnable任务,并将其投递到线程池中;

(3)接着执行线程池中的任务,并最终调用DubboProtocol的connected方法来执行请求的方法。

2 处理请求的实现细节

2.1 NettyServer的connected方法被调用

消费端发起TCP连接后,服务提供方的NettyServer的connected方法将被调用。connected方法为NettyServer父类AbstractServer的connected方法。

其中的依次调用关系为:AbstractServer的connected()->AbstractPeer的connected()->ChannelHandler的connected()。具体实现如下所示。

(1)AbstractServer的connected()

    public void connected(Channel ch) throws RemotingException {
        // If the server has entered the shutdown process, reject any new connection
        if (this.isClosing() || this.isClosed()) {
            logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "Close new channel " + ch + ", cause: server is closing or has been closed. For example, receive a new connect request while in shutdown process.");
            ch.close();
            return;
        }

        if (accepts > 0 && getChannelsSize()> accepts) {
            logger.error(INTERNAL_ERROR, "unknown error in remoting module", "", "Close channel " + ch + ", cause: The server " + ch.getLocalAddress() + " connections greater than max config " + accepts);
            ch.close();
            return;
        }
        super.connected(ch);
    }

(2)AbstractPeer的connected()

    private final ChannelHandler handler;

    public void connected(Channel ch) throws RemotingException {
        if (closed) {
            return;
        }
        handler.connected(ch);
    }

2.2 消息被投递到线程池中

调用ChannelHandler的connected()时,因为Netty默认的线程模型为All,因此AllChannelHandler类(ChannelHandler的子类)把接收到的所有消息包装成ChannelEventRunnable任务,并将其投递到线程池中。具体实现如下所示。

public class AllChannelHandler extends WrappedChannelHandler {

    public AllChannelHandler(ChannelHandler handler, URL url) {
        super(handler, url);
    }

    @Override
    public void connected(Channel channel) throws RemotingException {
        ExecutorService executor = getSharedExecutorService();
        try {
            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.CONNECTED));
        } catch (Throwable t) {
            throw new ExecutionException("connect event", channel, getClass() + " error when process connected event .", t);
        }
    }

    @Override
    public void disconnected(Channel channel) throws RemotingException {
        ExecutorService executor = getSharedExecutorService();
        try {
            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.DISCONNECTED));
        } catch (Throwable t) {
            throw new ExecutionException("disconnect event", channel, getClass() + " error when process disconnected event .", t);
        }
    }

    @Override
    public void received(Channel channel, Object message) throws RemotingException {
        ExecutorService executor = getPreferredExecutorService(message);
        try {
            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
        } catch (Throwable t) {
            if(message instanceof Request && t instanceof RejectedExecutionException){
                sendFeedback(channel, (Request) message, t);
                return;
            }
            throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
        }
    }

    @Override
    public void caught(Channel channel, Throwable exception) throws RemotingException {
        ExecutorService executor = getSharedExecutorService();
        try {
            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.CAUGHT, exception));
        } catch (Throwable t) {
            throw new ExecutionException("caught event", channel, getClass() + " error when process caught event .", t);
        }
    }
}

2.3 执行线程池中的任务

2.3.1 ChannelEventRunnable的run方法

执行线程池中的任务时,将执行ChannelEventRunnable的run方法,其实现细节具体如下所示。

    public void run() {
        InternalThreadLocalMap internalThreadLocalMap = InternalThreadLocalMap.getAndRemove();
        try {
            if (state == ChannelState.RECEIVED) {
                try {
                    handler.received(channel, message);
                } catch (Exception e) {
                    logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel
                        + ", message is " + message, e);
                }
            } else {
                switch (state) {
                    case CONNECTED:
                        try {
                            handler.connected(channel);
                        } catch (Exception e) {
                            logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
                        }
                        break;
                    case DISCONNECTED:
                        try {
                            handler.disconnected(channel);
                        } catch (Exception e) {
                            logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
                        }
                        break;
                    case SENT:
                        try {
                            handler.sent(channel, message);
                        } catch (Exception e) {
                            logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel
                                + ", message is " + message, e);
                        }
                        break;
                    case CAUGHT:
                        try {
                            handler.caught(channel, exception);
                        } catch (Exception e) {
                            logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "ChannelEventRunnable handle " + state + " operation error, channel is " + channel
                                + ", message is: " + message + ", exception is " + exception, e);
                        }
                        break;
                    default:
                        logger.warn(INTERNAL_ERROR, "unknown error in remoting module", "", "unknown state: " + state + ", message is " + message);
                }
            }
        } finally {
            InternalThreadLocalMap.set(internalThreadLocalMap);
        }
    }

2.3.2 执行connected方法

执行handler.connected(channel)时,将调用HeaderExchangeHandler#connected方法,具体实现如下所示。

    public void connected(Channel channel) throws RemotingException {
        ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
        handler.connected(exchangeChannel);
        channel.setAttribute(Constants.CHANNEL_SHUTDOWN_TIMEOUT_KEY,
            ConfigurationUtils.getServerShutdownTimeout(channel.getUrl().getOrDefaultApplicationModel()));
    }

接着在执行handler.connected(exchangeChannel)时,将调用DubboProtocol#connected方法,实现如下所示。

public void connected(Channel channel) throws RemotingException {
    invoke(channel, ON_CONNECT_KEY);
}

private void invoke(Channel channel, String methodKey) {
    Invocation invocation = createInvocation(channel, channel.getUrl(), methodKey);
    if (invocation != null) {
        try {
            if (Boolean.TRUE.toString().equals(invocation.getAttachment(STUB_EVENT_KEY))) {
                tryToGetStubService(channel, invocation);
            }
            received(channel, invocation);
        } catch (Throwable t) {
            logger.warn(PROTOCOL_FAILED_REFER_INVOKER, "", "", "Failed to invoke event method " + invocation.getMethodName() + "(), cause: " + t.getMessage(), t);
        }
    }
}

public void received(Channel channel, Object message) throws RemotingException {
    if (message instanceof Invocation) {
        reply((ExchangeChannel) channel, message);

    } else {
        super.received(channel, message);
    }
}

执行接口请求最终将调用DubboProtocol#reply方法,具体实现如下所示。

public CompletableFuture<Object> reply(ExchangeChannel channel, Object message) throws RemotingException {

    if (!(message instanceof Invocation)) {
        throw new RemotingException(channel, "Unsupported request: "
            + (message == null ? null : (message.getClass().getName() + ": " + message))
            + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
    }

    Invocation inv = (Invocation) message;

    // 1、获取调用方法对应的Invoker
    Invoker<?> invoker = inv.getInvoker() == null ? getInvoker(channel, inv) : inv.getInvoker();
    // switch TCCL
    if (invoker.getUrl().getServiceModel() != null) {
        Thread.currentThread().setContextClassLoader(invoker.getUrl().getServiceModel().getClassLoader());
    }
    // need to consider backward-compatibility if it's a callback
    if (Boolean.TRUE.toString().equals(inv.getObjectAttachmentWithoutConvert(IS_CALLBACK_SERVICE_INVOKE))) {
        String methodsStr = invoker.getUrl().getParameters().get("methods");
        boolean hasMethod = false;
        if (methodsStr == null || !methodsStr.contains(",")) {
            hasMethod = inv.getMethodName().equals(methodsStr);
        } else {
            String[] methods = methodsStr.split(",");
            for (String method : methods) {
                if (inv.getMethodName().equals(method)) {
                    hasMethod = true;
                    break;
                }
            }
        }
        if (!hasMethod) {
            logger.warn(PROTOCOL_FAILED_REFER_INVOKER, "", "", new IllegalStateException("The methodName " + inv.getMethodName()
                + " not found in callback service interface ,invoke will be ignored."
                + " please update the api interface. url is:"
                + invoker.getUrl()) + " ,invocation is :" + inv);
            return null;
        }
    }

    // 2、获取上下文对象,并设置对端地址
    RpcContext.getServiceContext().setRemoteAddress(channel.getRemoteAddress());
    // 3、执行invoker调用链
    Result result = invoker.invoke(inv);
    // 4、返回结果
    return result.thenApply(Function.identity());
}

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果您下载了本程序,但是该程序存在问题无法运行,那么您可以选择退款或者寻求我们的帮助(如果找我们帮助的话,是需要追加额外费用的)。另外,您不会使用资源的话(这种情况不支持退款),也可以找我们帮助(需要追加额外费用) 包含文字识别、语音识别、图片识别;后台管理系统使用vue-element-admin搭建页面,SpringBoot+Dubbo搭建后服务。 爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的工作流程包括以下几个关键步骤: URL收集: 爬虫从一个或多个初始URL开始,递归或迭代地发现新的URL,构建一个URL队列。这些URL可以通过链接分析、站点地图、搜索引擎等方式获取。 请求网页: 爬虫使用HTTP或其他协议向目标URL发起请求,获取网页的HTML内容。这通常通过HTTP请求库实现,如Python中的Requests库。 解析内容: 爬虫对获取的HTML进行解析,提取有用的信息。常用的解析工具有正则表达式、XPath、Beautiful Soup等。这些工具帮助爬虫定位和提取目标数据,如文本、图片、链接等。 数据存储: 爬虫将提取的数据存储到数据库、文件或其他存储介质中,以备后续分析或展示。常用的存储形式包括关系型数据库、NoSQL数据库、JSON文件等。 遵守规则: 为避免对网站造成过大负担或触发反爬虫机制,爬虫需要遵守网站的robots.txt协议,限制访问频率和深度,并模拟人类访问行为,如设置User-Agent。 反爬虫应对: 由于爬虫的存在,一些网站采取了反爬虫措施,如验证码、IP封锁等。爬虫工程师需要设计相应的策略来应对这些挑战。 爬虫在各个领域都有广泛的应用,包括搜索引擎索引、数据挖掘、价格监测、新闻聚合等。然而,使用爬虫需要遵守法律和伦理规范,尊重网站的使用政策,并确保对被访问网站的服务器负责。
Dubbo 提供者出现过载时,可能会导致性能下降、请求超时、服务不可用等问题。以下是一些解决提供者过载的常见方法: 1. 调整线程池配置:提供者使用线程池来处理请求,可以适当增加线程池的核心线程数和最大线程数,以增加并发能力。同时,可以调整队列容量和拒绝策略,避免请求被拒绝或丢失。 2. 优化服务实现逻辑:检查服务实现逻辑是否存在性能瓶颈,例如耗时操作、大量的锁竞争等。通过异步化处理、缓存优化、减少锁竞争等方式,优化服务实现逻辑,提高并发能力。 3. 水平扩展提供者实例:通过增加提供者实例的数量,可以分摊负载,提高系统的并发处理能力。可以考虑在多台机器上部署相同的提供者实例,并通过负载均衡算法将请求分发到不同的实例上。 4. 限流和熔断机制:使用限流和熔断机制可以避免过载情况下系统的崩溃。可以使用限流算法(如令牌桶、漏桶算法)控制请求的流量,或者使用熔断器来临时屏蔽不可用的服务。 5. 监控和调优:通过监控提供者的性能指标(如响应时间、吞吐量、CPU、内存等),及时发现并解决性能瓶颈。可以使用监控工具(如Dubbo Admin、Prometheus等)来收集和分析性能数据,进行调优。 6. 升级硬件和网络:如果提供者过载是由于硬件资源或网络带宽不足引起的,可以考虑升级硬件设备或增加网络带宽,以提供更好的并发性能。 综上所述,要解决 Dubbo 提供者过载问题,需要综合考虑线程池配置、服务实现优化、水平扩展、限流熔断、监控调优等方面的调整和优化措施,以提高系统的并发处理能力和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值