📍 RPC 框架实现对比
🚀 服务启动阶段对比
流程步骤 | 简化版 RPC 框架实现 | Dubbo 实现 |
---|---|---|
1. 服务扫描 | github.javaguide.provider.ServiceProvider#publishService - 手动注册 @RpcService 注解的服务 - 扫描指定包下的服务实现类 调用链路: NettyRpcServerMain.main() → NettyRpcServer.start() → ServiceProvider.publishService() → 扫描@RpcService注解 → 注册到本地服务映射 |
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor#scanServiceBeans - 扫描 @DubboService 注解 - 使用 DubboClassPathBeanDefinitionScanner 扫描指定包 调用链路: Spring容器启动 → BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry() → scanServiceBeans() → DubboClassPathBeanDefinitionScanner.scan() → processScannedBeanDefinition() |
2. 服务注册 | github.javaguide.registry.ServiceRegistry#registerService - 将服务信息注册到 Zookeeper - 创建服务节点和数据 调用链路: ServiceProvider.publishService() → ServiceRegistry.registerService() → ZkServiceRegistryImpl.registerService() → CuratorFramework.create() → Zookeeper节点创建 |
org.apache.dubbo.registry.integration.RegistryProtocol#export - 导出服务到注册中心 org.apache.dubbo.registry.integration.RegistryProtocol#register - 注册服务到注册中心 调用链路: ServiceBean.export() → ServiceConfig.export() → RegistryProtocol.export() → doLocalExport() → register(registry, registeredProviderUrl) → registry.register(url) |
3. 服务器启动 | github.javaguide.remoting.transport.netty.server.NettyRpcServer#start - 启动 Netty 服务器监听请求 - 配置编解码器和处理器 调用链路: NettyRpcServerMain.main() → NettyRpcServer.start() → ServerBootstrap.bind() → ChannelInitializer.initChannel() → pipeline.addLast(handlers) |
org.apache.dubbo.remoting.transport.netty4.NettyServer#doOpen - 初始化和启动 Netty 服务器 org.apache.dubbo.remoting.transport.netty4.NettyServer#initServerBootstrap - 配置服务器参数 调用链路: DubboProtocol.export() → createServer() → Transporters.bind() → NettyTransporter.bind() → new NettyServer() → doOpen() → initServerBootstrap() → bootstrap.bind() |
🔄 RPC 调用阶段对比
流程步骤 | 简化版 RPC 框架实现 | Dubbo 实现 |
---|---|---|
4. 代理拦截 | github.javaguide.proxy.RpcClientProxy#invoke - 拦截方法调用,构建 RpcRequest - 调用 RpcRequestTransport.sendRpcRequest() 调用链路: 用户调用接口方法 → JDK动态代理拦截 → RpcClientProxy.invoke() → new RpcRequest() → rpcRequestTransport.sendRpcRequest() |
org.apache.dubbo.rpc.proxy.InvokerInvocationHandler#invoke - 拦截方法调用,构建 RpcInvocation - 调用 InvocationUtil.invoke(invoker, rpcInvocation) 调用链路: 用户调用接口方法 → JDK动态代理拦截 → InvokerInvocationHandler.invoke() → new RpcInvocation() → InvocationUtil.invoke() |
5. 服务发现 | github.javaguide.registry.ServiceDiscovery#lookupService - 从 Zookeeper 获取服务提供者列表 - 返回可用的服务地址 调用链路: RpcClientProxy.invoke() → ServiceDiscovery.lookupService() → ZkServiceDiscoveryImpl.lookupService() → CuratorFramework.getChildren() → 解析服务地址列表 |
org.apache.dubbo.registry.integration.RegistryDirectory#notify - 接收注册中心通知 org.apache.dubbo.registry.integration.RegistryDirectory#refreshOverrideAndInvoker - 更新服务提供者列表 调用链路: InvocationUtil.invoke() → clusterInvoker.invoke() → AbstractClusterInvoker.invoke() → list(invocation) → directory.list() → RegistryDirectory.doList() |
6. 负载均衡 | github.javaguide.loadbalance.LoadBalance#selectServiceAddress - 从服务地址列表中选择一个 - 支持随机、轮询等算法 调用链路: ServiceDiscovery.lookupService() → LoadBalance.selectServiceAddress() → RandomLoadBalance.selectServiceAddress() → 返回选中的服务地址 |
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#select - 选择服务实例 org.apache.dubbo.rpc.cluster.LoadBalance#select - 负载均衡算法接口 调用链路: AbstractClusterInvoker.invoke() → initLoadBalance() → doInvoke() → select(loadbalance, invocation, invokers, selected) → doSelect() → loadbalance.select() |
7. 请求编码 | github.javaguide.serialize.Serializer#serialize - 序列化 RpcRequest 对象 - 支持 Kryo、Protostuff 等序列化 调用链路: LoadBalance.selectServiceAddress() → NettyRpcClient.sendRpcRequest() → RpcMessageEncoder.encode() → Serializer.serialize() → 序列化RpcRequest |
org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#encodeRequestData - 编码请求数据 - 序列化 RpcInvocation 对象 调用链路: selectedInvoker.invoke() → DubboInvoker.doInvoke() → currentClient.request() → HeaderExchangeClient.request() → HeaderExchangeChannel.request() → NettyChannel.send() → DubboCodec.encode() → encodeRequestData() |
8. 网络传输 | github.javaguide.remoting.transport.netty.client.NettyRpcClient#sendRpcRequest - 通过 Netty 发送请求到服务端 调用链路: Serializer.serialize() → NettyRpcClient.sendRpcRequest() → Channel.writeAndFlush() → NettyClientHandler.channelRead() → CompletableFuture.complete() |
org.apache.dubbo.remoting.transport.netty4.NettyChannel#send - 通过 Netty 发送请求 调用链路: DubboCodec.encode() → NettyChannel.send() → writeQueue.enqueue() → channel.writeAndFlush() → Netty网络传输 |
9. 请求处理 | github.javaguide.remoting.handler.RpcRequestHandler#handle - 处理 RPC 请求,反射调用目标方法 调用链路: Netty接收数据 → NettyRpcServerHandler.channelRead() → RpcMessageDecoder.decode() → RpcRequestHandler.handle() → ServiceProvider.getService() → Method.invoke() |
org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#reply - 处理请求,解码反序列化,执行反射调用 调用链路: Netty接收数据 → NettyServerHandler.channelRead() → DubboCodec.decode() → DecodeableRpcInvocation.decode() → DubboProtocol.reply() → getInvoker() → invoker.invoke() → 反射调用业务方法 |
10. 响应返回 | github.javaguide.remoting.handler.RpcRequestHandler#handle - 构建 RpcResponse 并序列化返回 调用链路: Method.invoke() → new RpcResponse() → RpcMessageEncoder.encode() → Serializer.serialize() → Channel.writeAndFlush() |
org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#encodeResponseData - 编码响应数据,序列化执行结果 调用链路: 业务方法执行完成 → 返回Result → DubboCodec.encode() → encodeResponseData() → 序列化结果 → NettyChannel.send() |
11. 结果解析 | github.javaguide.remoting.transport.netty.client.NettyRpcClient#sendRpcRequest - 接收响应并反序列化结果 调用链路: 客户端接收响应 → NettyClientHandler.channelRead() → RpcMessageDecoder.decode() → Serializer.deserialize() → CompletableFuture.complete() → 返回结果给用户 |
org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcResult#decode - 解码响应,反序列化结果 调用链路: 客户端接收响应 → NettyClientHandler.channelRead() → DubboCodec.decode() → DecodeableRpcResult.decode() → AsyncRpcResult.complete() → InvokerInvocationHandler返回结果 |
🔄 完整端到端调用链路对比
简化版 RPC 框架完整调用链路
scss
用户调用 demoService.sayHello("world")
↓
JDK动态代理拦截
↓
RpcClientProxy.invoke()
↓
new RpcRequest(interfaceName, methodName, parameters, paramTypes, requestId)
↓
ServiceDiscovery.lookupService(rpcServiceName)
↓
ZkServiceDiscoveryImpl.lookupService() → CuratorFramework.getChildren()
↓
LoadBalance.selectServiceAddress(serviceAddresses)
↓
RandomLoadBalance.selectServiceAddress() → 返回选中地址
↓
NettyRpcClient.sendRpcRequest(rpcRequest, targetServiceUrl)
↓
RpcMessageEncoder.encode() → Serializer.serialize(rpcRequest)
↓
Channel.writeAndFlush(encodedRequest)
↓
【网络传输】
↓
NettyRpcServerHandler.channelRead()
↓
RpcMessageDecoder.decode() → Serializer.deserialize()
↓
RpcRequestHandler.handle(rpcRequest)
↓
ServiceProvider.getService(rpcRequest.getInterfaceName())
↓
Method.invoke(service, rpcRequest.getParameters())
↓
new RpcResponse(requestId, result)
↓
RpcMessageEncoder.encode() → Serializer.serialize(rpcResponse)
↓
Channel.writeAndFlush(encodedResponse)
↓
【网络传输】
↓
NettyClientHandler.channelRead()
↓
RpcMessageDecoder.decode() → Serializer.deserialize()
↓
CompletableFuture.complete(rpcResponse.getData())
↓
返回结果给用户
Dubbo 完整调用链路
scss
用户调用 demoService.sayHello("world")
↓
JDK动态代理拦截
↓
InvokerInvocationHandler.invoke()
↓
new RpcInvocation(serviceModel, methodName, interfaceName, protocolServiceKey, parameterTypes, args)
↓
InvocationUtil.invoke(invoker, rpcInvocation)
↓
AbstractClusterInvoker.invoke(invocation)
↓
list(invocation) → RegistryDirectory.doList()
↓
routerChain.route() → 返回可用invokers列表
↓
initLoadBalance(invokers, invocation)
↓
doInvoke(invocation, invokers, loadbalance)
↓
select(loadbalance, invocation, invokers, selected)
↓
doSelect() → loadbalance.select(invokers, url, invocation)
↓
selectedInvoker.invoke(invocation)
↓
DubboInvoker.doInvoke()
↓
currentClient.request(inv, timeout)
↓
HeaderExchangeClient.request() → HeaderExchangeChannel.request()
↓
NettyChannel.send() → writeQueue.enqueue()
↓
DubboCodec.encode() → encodeRequestData()
↓
channel.writeAndFlush()
↓
【网络传输】
↓
NettyServerHandler.channelRead()
↓
DubboCodec.decode() → decodeBody()
↓
DecodeableRpcInvocation.decode()
↓
DubboProtocol.reply(channel, message)
↓
getInvoker(channel, inv) → invoker.invoke(inv)
↓
反射调用业务方法
↓
返回Result
↓
DubboCodec.encode() → encodeResponseData()
↓
NettyChannel.send()
↓
【网络传输】
↓
NettyClientHandler.channelRead()
↓
DubboCodec.decode() → decodeBody()
↓
DecodeableRpcResult.decode()
↓
AsyncRpcResult.complete()
↓
CompletableFuture返回结果
↓
InvokerInvocationHandler返回结果给用户
References
绯闻女友想看很久的Dubbo面试题:没看明白,定坑