Dubbo的服务调用的过程是什么样的?详细一点。

3 个回答

  • 小白
    世界上有两个我,一个想去远方,一个身不由己。
    Dubbo 的服务调用过程包含多个步骤,涉及动态代理、负载均衡、序列化和网络通信等操作,以下是一次完整服务调用的简化过程。 ### 1. 调用开始 - 动态代理(Proxy) - **动态代理**:调用过程从代理对象(Proxy)开始。Dubbo 使用 JDK 动态代理或 Javassist 字节码增强生成代理对象,模拟本地方法调用。 - **缓存和 Mock 处理**:调用前会经过一个 `filter`,判断是否有接口的缓存或本地 `mock` 数据,如果有则直接返回,否则进入下一步。 ### 2. 服务调用者订阅服务 - 服务列表订阅与聚合 - **服务订阅**:服务调用者在启动时会从注册中心订阅目标服务的列表信息。通过 Cluster,将拉取的服务列表聚合成一个 `Invoker` 列表。 ### 3. 负载均衡选择服务 - 负载均衡与 Invoker - **获取可用服务列表**:在 Invoker 执行时,Dubbo 会通过 `Directory` 获取所有可调用的服务提供者列表。 - **负载均衡**:根据负载均衡策略(如轮询、随机等)从服务列表中选出一个具体的 Invoker,进行服务调用。 ### 4. 调用过滤 - 过滤器与限流 - **过滤规则**:在调用 `Invoker` 的 `invoke` 方法前,会应用过滤器进行一系列检查,如上下文处理、限流和计数等,以确保调用符合系统策略。 ### 5. 远程调用 - 序列化与网络通信 - **序列化**:Dubbo 将请求参数和数据进行序列化,以便在网络上传输。序列化协议可以是 Hessian2、Protobuf、Kryo 等。 - **网络通信**:Dubbo 客户端使用指定的网络框架(如 Netty)进行远程通信,并封装请求数据,将其发送给服务提供方。 ### 6. 服务端处理请求 - **反序列化**:服务提供方收到请求后,会反序列化请求数据,恢复方法参数。 - **线程池调度**:请求被分配到线程池中的某个线程处理,按请求的服务名、方法名等找到对应的 `Exporter`。 - **调用具体实现**:找到并调用服务的具体实现方法,执行业务逻辑,并将执行结果返回给客户端。 ### 7. 返回结果 - **返回路径**:服务端将执行结果通过原路径返回给客户端。 - **反序列化结果**:客户端将收到的结果数据反序列化,返回给代理对象(Proxy),完成一次调用。 ### 总结 Dubbo 的服务调用通过动态代理、负载均衡、序列化、网络通信和反序列化等步骤,确保在透明、平滑的调用过程中实现高效、可靠的远程服务调用。Dubbo 通过注册中心、负载均衡等机制增强了服务的可用性,并通过序列化和网络优化实现了低延迟的调用体验。
    编辑于 2024-11-09 20:22 •IP属地 美国
    举报
    评论
    收藏

  • 小王子-B727
    能治愈生活的良方,是保持对生活的热爱。
    ![image.png](https://images.codewd.com/0516a508c52ebb038317c1ce8064f3b3.png) 过程说明 dubbo消费者调用接口,将请求封装为Request; 每个Request都有一个ID,是自增的,此ID会关联下面生成的Future,用于收到接口响应后的回调,对应步骤21。 2. 发送请求,直接返回ResponseFuture(实现为DefaultFuture); dubbo调用默认为同步方式,即future.get()。 3. 此步骤默认使用Netty API,将请求发送到队列; 4. 从队列中取出请求后由Netty IO线程处理,发送TCP请求到缓冲区; 5. 发送数据到Socket缓冲区; 6. 数据传输,操作系统层面; 7. 从Socket缓冲区读取数据,IO线程进行处理; 8. 根据Dubbo配置到消息分发机制,交由对应到Dispatcher处理; > dispatcher:这个字段代表的是IO线程池和业务线程池的边界 all:所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。对应的是AllChannelHandler direct:所有消息都不派发到线程池,全部在IO线程上直接执行。(这种做法在绝大多数情况下都不合理,因为毕竟业务逻辑相关对IO事件都是复杂的)。具体的实现方式就是在装饰者的层级上直接下调,不再包装线程池。 message:只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在IO线程上执行。 execution:官方的说法是:只请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在IO线程上执行。 connection:在IO线程上,将连接建立以及断开事件放入队列,有序逐个执行,其它消息派发到线程池。 9. 以AllDispathcer为例,使用Dubbo 线程池进行处理; 10. 根据请求从Map获取之前暴露到Exporter; 11. 从Exporter中获取对应到Invoker; 12. 调用invoker.invoke,通过代理调用接口; 13. 调用接口后将返回结果发送给客户端; 步骤14-18参考步骤4-8 20. DubboClientHandler线程池处理收到到结果; 21. 通过Response的ID获取到对应到Future,执行future.doReceive来响应对应到线程结果;
    发布于 2024-10-17 20:19 •IP属地 贵州
    举报
    评论
    收藏

  • 小五
    有些东西不需要答案,态度就是答案。
    ### Dubbo服务调用过程 #### 消费者端 1. **发送请求**: - 通过服务接口的代理对象执行目标方法,该方法被`InvokerInvocationHandler#invoke`拦截。经过路由过滤与负载均衡后,选择一个`DubboInvoker`对象。 - 创建一个`RpcInvocation`对象,并通过`doInvoke`方法发送请求。`RpcInvocation`封装了目标方法的信息。 - 生成全局唯一的请求ID,创建一个`DefaultFuture`对象,将请求ID作为key,保存到`ConcurrentHashMap`中。 - 通过`NettyClient`将序列化后的请求发送出去。 2. **接收响应**: - 根据响应ID(即请求ID)从缓存中找到对应的`Future`对象,调用`doReceived`方法保存结果。 - 唤醒请求线程并处理响应结果。 #### 提供者端 1. **接收请求**: - `NettyServer`接收到请求,通过协议解析并反序列化成对象。 - 将请求封装成`ChannelEventRunnable`对象,交由线程池处理。线程池中的线程会执行`DubboProtocol#reply`方法,找到对应的服务实现类并调用目标方法,返回执行结果。 ### Dubbo客户端调用源码分析 1. **本地调用被拦截**: - 消费者在调用服务接口时,实际是调用了代理类,`InvokerInvocationHandler#invoke`拦截了调用,通过远程客户端发起请求。 - 在`MockClusterInvoker#invoke`中,通过`AbstractClusterInvoker#invoke`选择一个合适的Invoker进行调用。 2. **执行远程调用**: - 通过`DubboInvoker#doInvoke`方法,客户端会根据负载均衡策略选择一个`ExchangeClient`,并根据请求方式(同步、异步或oneway)发送请求。 - 对于同步请求,会阻塞等待结果返回。 3. **请求发送流程**: - 创建一个`Request`对象,并生成唯一请求ID。 - 创建并缓存`DefaultFuture`对象,发送请求。 4. **接收响应**: - 通过`DefaultFuture#received`方法,根据请求ID找到对应的`Future`对象,调用`doReceived`保存结果并唤醒请求线程。 ### Dubbo服务端源码分析 1. **接收并分发请求**: - `NettyServer`接收到请求后,将其封装成`ChannelEventRunnable`对象,交由业务线程池处理。 - 线程池执行`HeaderExchangeHandler#handleRequest`方法,找到请求对应的服务实现类,并执行目标方法。 2. **查找并调用服务实现**: - 在`DubboProtocol#reply`中,构建`serviceKey`,从`exporterMap`缓存中找到对应的`Exporter`,并调用其封装的Invoker,最终执行目标方法并返回结果。 ### 关键过程总结 1. 消费者端通过代理对象发起调用,生成请求ID,将请求通过Netty发送到提供者端。 2. 提供者端接收到请求后,将其分发到业务线程池,找到对应的服务实现并执行,最终返回结果。
    发布于 2024-10-17 18:47 •IP属地 甘肃
    举报
    评论
    收藏