guide-rpc-framework vs Dubbo 实现

70 阅读3分钟

📍 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
- 编码响应数据,序列化执行结果

调用链路:
业务方法执行完成返回ResultDubboCodec.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 框架完整调用链路

用户调用 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 完整调用链路

用户调用 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面试题:没看明白,定坑

github.com/apache/dubb…