1. Dubbo架构

 

 

 

 

节点角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器
 

 Dubbo Consumer并不是直接通过https等方式直接调用Provider,而是Provider接口实现代理方式,让Consumer像调用本地方法一样进行远程调用Provider。这样通过代理方式好处:

a) Provider和Consumer解耦

b) 代理类中新增过滤操作、服务降级、容错等机制

c) 调用的负载均衡

d) 接口调用数据统计

2. Dubbo整体架构设计

Business Service层:业务层,日常开发中的业务逻辑层

Config 层:对外配置接口

proxy层:服务代理层,provider和consumer都会生成动态代理类。生成provider端Stub和consumer端Skeleton,负责远程调用和数据返回

registry层:注册中心,封装服务地址的注册和发现,注册中心保存provider的ip、port以及调用方式(proxy)

protocol层:远程调用层,封装rpc调用的具体过程

Cluster层:路由层,封装多个provider的路由和负载均衡

monitor层:监控中心,rpc调用次数和调用时间监控

serialize层:数据序列化层,负责provider和consumer网络传输数据的序列化与反序列化。一般是将需要传输的数据类implements Serializable

 3. Dubbo原理

Dubbo远程调用是通过动态代理实现的,使用动态代理来屏蔽远程调用的细节。

Provider Consumer都是通过代理类实现,Invoker 就是 Dubbo 对远程调用的抽象。在服务提供方,Invoker用于调用服务提供类。在服务消费方,Invoker用于执行远程调用

 

 

 3.1 Provider端:生成代理类、注册

首先provider启动,Protocol通过Proxy代理将需要暴露的接口封装成Invoker,是一个可执行体。然后通过Exporter包装发送到注册中心完成注册,至此provider端服务暴露完成。具体如下

  • 服务提供者在启动的时候,会通过读取一些配置将服务实例化。
  • Proxy 封装服务调用接口,方便调用者调用。客户端获取 Proxy 时,可以像调用本地服务一样,调用远程服务。
  • Proxy 在封装时,需要调用 Protocol 定义协议格式,例如:Dubbo Protocol。
  • 将 Proxy 封装成 Invoker,它是真实服务调用的实例。
  • 将 Invoker 转化成Exporter,Exporter 只是把 Invoker 包装了一层,是为了在注册中心中暴露自己,方便消费者使用。
  • 将包装好的Exporter 注册到注册中心。

3.2 Consumer端:服务调用

  •  

     

  • 服务消费者建立好实例,会到服务注册中心订阅服务提供者的元数据(元数据包括服务 IP 和端口以及调用方式(Proxy)),并保存到本地缓存,这样及时所有注册中心宕机,provider和consumer也可以通过本地缓存进行通讯,只是其中一方信息变更另一方无法感知。
  • 消费者会生成一个代理类,通过Proxyfactory生成一个Proxy代理类,Proxy持有一个Invoker可执行对象
  • 调用 Invoker之后,通过 Directory 获取服务提供者的Invoker 列表。在分布式的服务中有可能出现同一个服务,分布在不同的节点上。
  • 通过路由规则了解,服务需要从哪些节点获取。
  • Invoker 调用过程中,通过 Cluster 进行容错,如果遇到失败策略进行重试。
  • 调用中,由于多个服务可能会分布到不同的节点,就要通过 LoadBalance 来实现负载均衡。
  • Invoker 调用之前还需要经过Filter,它是一个过滤链,用来处理上下文,限流和计数的工作。
  • 接下来用 Client 进行数据传输,一般用Netty进行传输
  • Codec 会根据 Protocol 定义的协议,进行协议的构造。
  • 构造完成的数据,通过序列化 Serialization 传输给服务提供者。
  • 3.3 Provider收到Consumer调用处理

  • Request 已经到达了服务提供者,它会被分配到线程池(ThreadPool)中进行处理。
  • Server 拿到请求以后查找对应的 Exporter(包含有 Invoker)。
  • 由于 Export 也会被 Filter 层层包裹,通过Filter 后获得 Invoker最后,对服务提供者实体进行调用。
  • 最终将结果原路返回

4 MDC

 MDC可理解为线程安全的存放诊断日志的容器

MDC数据结构是key-value格式,api有MDC.put(k,v) MDC.remove(k), MDC.get(k)

MDC值是与线程绑定在一起的,不同线程间互不影响。其线程安全原因是底层使用ThreadLocal

MDC使用场景:

a) Web应用中,如果想在日志中输出请求用户IP、请求URL、系统耗时等,MDC都成支撑

b)借助MDC保存用户请求时requestId,当请求完成后再将这个requestId移除。这样通过grep requestId就可以轻松获取整个请求流程的日志轨迹

c)微服务中,链路追踪是一个难题,借助MDC去埋点,巧妙实现链路追踪

 

5 SPI

https://blog.csdn.net/yangbaggio/article/details/97617750

 

 

 

https://blog.csdn.net/JavaShark/article/details/125210297

参考文献:

https://huaweicloud.csdn.net/63a568d6b878a54545946c16.html?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2~default~ESLANDING~activity-4-125233339-blog-120353520.235^v27^pc_relevant_landingrelevant&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~ESLANDING~activity-4-125233339-blog-120353520.235^v27^pc_relevant_landingrelevant

https://blog.csdn.net/ChenRui_yz/article/details/127438988

 https://blog.csdn.net/TaylorSwiftiiln/article/details/120353520

posted on 2023-03-29 21:09  colorfulworld  阅读(39)  评论(0编辑  收藏  举报