Dubbo(二):实现细节

初始化过程

解析服务

当项目启动时,扫描到dubbo名称空间时,Spring会扫描spring.handlers配置文件,回调 DubboNamespaceHandler。
image.png
所有的dubbo标签,统一用 DubboBeanDefinitionParser 进行解析,基于一对一属性映射,将 XML 标签解析为 Bean 对象。
image.png
当Spring容器实例化bean完成,走到最后一步发布ContextRefreshEvent事件的时候,ServiceBean会执行onApplicationEvent方法,该方法调用ServiceConfig的export方法。
image.png
此外,ReferenceAnnotationBeanPostProcessor引用注解后置处理器加载ReferenceBeanInvocationHandler时会调用ReferenceConfig.get()开启引用服务。
image.png

在 ServiceConfig.export() 或 ReferenceConfig.get() 初始化时,将 Bean 对象转换 URL 格式,所有 Bean 属性转成 URL 的参数。
然后将 URL 传给 协议扩展点,基于扩展点的 扩展点自适应机制,根据 URL 的协议头,进行不同协议的服务暴露或引用。

简单来讲:项目启动,Spring扫描dubbo相关配置文件进行回调,加载并解析相关的配置类(eg.ServiceBean和ReferenceBean等),并通过后置处理器调用这些配置类中相应的方法,来实现服务的暴露或引用。

服务发布与引用

服务发布

Dubbo主要采用XML配置方式,如下为服务提供者的XML配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- 提供方应用信息,用于计算依赖关系 -->
    <dubbo:application name="hello-world-app"  />

    <!-- 使用 multicast 广播注册中心暴露服务地址 -->
    <dubbo:registry address="multicast://224.5.6.7:1234" />

    <!-- 用 dubbo 协议在 20880 端口暴露服务 -->
    <dubbo:protocol name="dubbo" port="20880" />

    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" />

    <!-- 和本地 bean 一样实现服务 -->
    <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />
</beans>

其中“dubbo:service”开头的配置项声明了服务提供者要发布的接口,“dubbo:protocol”开头的配置项声明了服务提供者要发布的接口的协议以及端口号。
Dubbo 会把以上配置项解析成下面的 URL 格式:

dubbo://host-ip:20880/com.alibaba.dubbo.demo.DemoService

然后基于扩展点自适应机制,通过 URL 的“dubbo://”协议头识别,就会调用 DubboProtocol 的 export() 方法,打开服务端口 20880,就可以把服务 demoService 暴露到 20880 端口了。

服务引用

如下为服务端消费者的XML配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
    <dubbo:application name="consumer-of-helloworld-app"  />

    <!-- 使用 multicast 广播注册中心暴露发现服务地址 -->
    <dubbo:registry address="multicast://224.5.6.7:1234" />

    <!-- 生成远程服务代理,可以和本地 bean 一样使用 demoService -->
    <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" />
</beans>

其中“dubbo:reference”开头的配置项声明了服务消费者要引用的服务,Dubbo 会把以上配置项解析成下面的 URL 格式:

dubbo://com.alibaba.dubbo.demo.DemoService

然后基于扩展点自适应机制,通过 URL 的“dubbo://”协议头识别,就会调用 DubboProtocol 的 refer() 方法,得到服务 demoService 引用,完成服务引用过程。

服务注册与发现

服务提供者注册服务

继续以前面服务提供者的 XML 配置为例,其中“dubbo://registry”开头的配置项声明了注册中心的地址,Dubbo 会把以上配置项解析成下面的 URL 格式:

registry://multicast://224.5.6.7:1234/com.alibaba.dubbo.registry.RegistryService?
export=URL.encode("dubbo://host-ip:20880/com.alibaba.dubbo.demo.DemoService")

然后基于扩展点自适应机制,通过 URL 的“registry://”协议头识别,就会调用 RegistryProtocol 的 export() 方法,将 export 参数中的提供者 URL,注册到注册中心。

服务消费者发现服务

同样以前面服务消费者的 XML 配置为例,其中“dubbo://registry”开头的配置项声明了注册中心的地址,跟服务注册的原理类似,Dubbo 也会把以上配置项解析成下面的 URL 格式:

registry://multicast://224.5.6.7:1234/com.alibaba.dubbo.registry.RegistryService?
refer=URL.encode("consummer://host-ip/com.alibaba.dubbo.demo.DemoService")

然后基于扩展点自适应机制,通过 URL 的“registry://”协议头识别,就会调用 RegistryProtocol 的 refer() 方法,基于 refer 参数中的条件,查询服务 demoService 的地址

服务调用

发起一次服务调用需要解决四个问题:

  • 客户端和服务端如何建立网络连接?
  • 服务端如何处理请求?
  • 数据传输采用什么协议?
  • 数据该如何序列化和反序列化?

网络传输

建立网络连接以及处理请求主要由通信框架来实现。Dubbo支持多种通信框架,比如Netty4等。
客户端和服务端之间的调用通过Netty4来建立连接,服务端采用NIO方式来处理客户端的请求。

数据传输协议

Dubbo 不仅支持私有的 Dubbo 协议,还支持其他协议比如 Hessian、RMI、HTTP、Web Service、Thrift 等。下面这张图描述了私有 Dubbo 协议的协议头约定。

序列化方式

Dubbo 同样也支持多种序列化格式,比如 Dubbo、Hession 2.0、JSON、Java、Kryo 以及 FST 等,可以通过在 XML 配置中添加下面的配置项。
例如:

<dubbo:protocol name="dubbo" serialization="kryo"/>

服务监控

服务监控主要包括四个流程:数据采集、数据传输、数据处理和数据展示,其中服务框架的作用是进行埋点数据采集,然后上报给监控系统。
在 Dubbo 框架中,无论是服务提供者还是服务消费者,在执行服务调用的时候,都会经过 Filter 调用链拦截,来完成一些特定功能,比如监控数据埋点就是通过在 Filter 调用链上装备了 MonitorFilter 来实现的

服务治理

服务治理手段包括:节点管理、负载均衡、服务路由、服务容错等,下图为dubbo服务治理的具体实现:

图中的 Invoker 是对服务提供者节点的抽象,Invoker 封装了服务提供者的地址以及接口信息。

  • 节点管理:Directory 负责从注册中心获取服务节点列表,并封装成多个 Invoker,可以把它看成“List<invoker>” ,它的值可能是动态变化的,比如注册中心推送变更时需要更新。</invoker>
  • 负载均衡:LoadBalance 负责从多个 Invoker 中选出某一个用于发起调用,选择时可以采用多种负载均衡算法,比如 Random、RoundRobin、LeastActive 等。
  • 服务路由:Router 负责从多个 Invoker 中按路由规则选出子集,比如读写分离、机房隔离等。
  • 服务容错:Cluster 将 Directory 中的多个 Invoker 伪装成一个 Invoker,对上层透明,伪装过程包含了容错逻辑,比如采用 Failover 策略的话,调用失败后,会选择另一个 Invoker,重试请求。

一次服务调用的流程


Dubbo 框架下一次服务调用的过程
1.客户端发起调用的过程

  • 首先根据接口定义,通过 Proxy 层封装好的透明化接口代理,发起调用。
  • 然后在通过 Registry 层封装好的服务发现功能,获取所有可用的服务提供者节点列表。
  • 再根据 Cluster 层的负载均衡算法从可用的服务节点列表中选取一个节点发起服务调用,如果调用失败,根据 Cluster 层提供的服务容错手段进行处理。
  • 同时通过 Filter 层拦截调用,实现客户端的监控统计。
  • 最后在 Protocol 层,封装成 Dubbo RPC 请求,发给服务端节点。

这样的话,客户端的请求就从一个本地调用转化成一个远程 RPC 调用,经过服务调用框架的处理,通过网络传输到达服务端。其中服务调用框架包括通信协框架 Transporter、通信协议 Codec、序列化 Serialization 三层处理。

2.服务端从网络中接收到请求后的处理过程

  • 首先在 Protocol 层,把网络上的请求解析成 Dubbo RPC 请求。
  • 然后通过 Filter 拦截调用,实现服务端的监控统计。
  • 最后通过 Proxy 层的处理,把 Dubbo RPC 请求转化为接口的具体实现,执行调用。
全部评论

相关推荐

一共一个小时,面试难度以及自己的回答算是最近的面试压力比较大的,实习问了30分钟,中间穿插八股。1.redis数据结构2.redis持久化机制3.mysql索引底层4.聚簇索引与非聚簇索引5.索引优化6.索引失效7.mysql执行一条sql8.那么多索引mysql怎么选(不会)9.tcp与udp区别10.tcp为什么可靠11.消息队列作用12.kafka怎么保证消息有序性13.mcp是什么?14.skills是什么?15.jvm内存分配与回收过程(我讲了从创建对象到判断垃圾对象到垃圾回收我全说了一遍,是这个吗?)16.fullgc触发机制17.tcp的拥塞控制流程(不会了)18.分布式事务解决方案,说了2pc,3pc,tcc。算法是反转双向链表,没有按格式输出,但是面试官没让继续写了,面完以为挂了,结果晚上秒过,看看复试什么情况吧。今天百度打电话准备发offer了,业务跟在手子的差不多,很垂,并且说不分日常暑期,只看表现,会有转正机会,但是考虑再三还是拒绝了,百度实习薪资确实有点低,title也不如之前了,但是面试的二位业务老师我很喜欢,对我的评价也不错,希望之后能有机会共事。从三月份到现在一共面了六家,面试次数总共是8场,情况如下:脉脉二面(无答复,默认挂)百度二面已oc美团一面过,下周一二面shein一面过直接HR面游族一面过直接HR面腾讯一面过等待约二面滴滴明天一面面试通过率还是蛮高的,但是大部分都是日常,感觉对我现在的加成不大,大概率不会去,不知道暑期会是什么情况呢唉,希望能有面试吧,继续加油。字节被无hc直接取消了,现在还没人捞,有没有字节HR救救我
不管什么都不想跳动了:本人美团百度快手都待过,建议肯定是直接留快手多一点产出后转正or直接冲字节腾讯暑期吧。一是快手从福利到基建都吊打另外两家。美团现在这个业务比较惨,本来毛利就很低,亏损严重,今年很可能要优化人力降低成本,去了别说日常,就算暑期后面都很可能被优化。百度其实实习生权限挺高的,可以接触到一些含金量高的项目,但是现在的风评不如之前了,薪资也不高。二是转正概率和薪资是跟产出挂钩的,你都在手子已经积累产出了,去其他家日常实习产出都是从0开始,肯定不可能有你在手子转正可能性大啊,现在日常压根没必要去,而且我有两个师弟都是在快手日常转正的,不用太担心,安心留在手子一边多做一点产出然后一边冲字节腾讯暑期,字节腾讯今年实习岗位非常多的,不如好好把握这个,加油。
今天你投了哪些公司?
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务