Dubbo的原理和整合(一)

发布于 2021-06-29  1.35k 次阅读


一,Dubbo概述和作用

Apache Dubbo 是一款高性能,轻量级的来源java RPC框架,它提供了三大核心能力:
  • 面向接口的远程服务调用
  • 智能的容错和负载均衡
  • 服务的注册和发现
          功能
                                                   描述
服务开发(RPC应用开发)
RMI或Hessian只能简单的暴露和引用远程服务,进行开发,通过配置服务
服务软负载均衡
通过服务注册中心,动态地注册发生服务,使服务的位置透明 ,实现软负载均衡和容错机制,降低对硬件负载均衡的依赖,减少部分成本
服务依赖管理
服务间依赖关系复杂时,人工难以描述,需要自动画出出应用间的依赖关系图
服务监控
统计每天的服务调用量,响应时间,做为容量规划的参考指标,将某台机器的权重一直加大,并在加大的过程记录响应时间变化,直到响应时间到阈值
服务治理
可在线动态调整机器权重,服务分组隔离,禁启动服务
注:在现在的java分布式开发中有两套主流的解决方案
  • Dubbo+Zookeeper
  • Springboot+SpringClould(已经成为主流
 
Dubbo的主要作用:协调分布式程序之间的远程调用,服务监控,服务注册,服务治理问题

二,Dubbo架构设计

Dubbo的总体架构:

init:初始化
 
async:异步
 
sync:同步
Provider服务提供者:相当于service,实际执行业务逻辑的服务层
 
Consumer服务消费者:专门调用service的,不关注service具体实现的应用层
 
Registry注册中心:存储provider,consumer信息的中介
 
Monitor:Dubbo负责收集服务调用信息的监控中心
调用流程:
  1. 服务容器负责启动,加载,运行服务提供者
  2. 服务提供者在启动时,向注册中心注册自己提供的服务
  3. 服务消费者在启动时,向注册中心注册自己提交的需求
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更的数据给消费者
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用
  6. 服务消费者和提供者,在内存中累计调用的次数和时间,定时每分钟发送一次统计数据到监控中心

Dubbo的架构设计:

  • config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类
  • proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 ServiceProxy 为中心,扩展接口为 ProxyFactory
  • registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory, Registry, RegistryService
  • cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance
  • monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService
  • protocol 远程调用层:封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter
  • exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
  • transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec
  • serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool
Dubbo的架构的特定:
dubbo架构有以下几个特点:
  • 连通性
  • 健壮性
  • 伸缩性
  • 升级拓展性
       特点
                                                   说明
连通性
注册中心,监控中心宕机不影响连通性,两个组件可选,服务消费端可直连
健壮性
服务提供者无状态,任意一台宕机不影响使用,全宕机,无线重连
伸缩性
注册中心集群,可动态的增加部署实例,客户端自动发现新的注册中心,可动态增减服务提供者实例,注册中心将推送新的服务提供者信息给消费者
升级拓展性
升级拓展功能简单方便,服务可以拆分重组

三,Dubbo的依赖和配置方式

必要依赖:JDK1.6+,理论上Dubbo可以只依赖JDK,不依赖于任何第三方库运行,只需要配置使用JDK相关实现策略即可(Dubbo和Spring可以直接整合,一般还需要配置Spring)
 
缺省依赖:通过 mvn dependency:tree > dep.log 命令分析
       
可选依赖:其他依赖jar包需要整合则添加
Dubbo的三种配置方式:
 
1)使用Dubbo自带注解:使用简单,有一定的侵入性,实现类依赖注解
 
2)集成Spring XML(或者集成Spring yml):使用稍显麻烦,无侵入性,方便以后改用其他RPC框架
 
3)使用原生API:编程开发麻烦,一般用于测试,开发API的场景
 
大致使用步骤:
  1. 引入Dubbo依赖
  2. 配置Dubbo环境
  3. 开发服务
  4. 配置服务
  5. 启动,调用

四,使用dubbo对SSM框架的模块进行服务拆分

dubbo主要用于分布式服务的部署与远程通信,dubbo的功能只能在多模块分布式中才能真正被体现,这里我们模块使用SSM框架
注:Dome在个人github上有分享

一,无dubbo多模块之间的本地调用

不使用dubbo我们两模块之间的调用,我们使用SSM框架做多个模块
模块(module)和项目(project)的异同:
  • 同:模块有项目的所有的组成成分,它独立出来就是一个项目,一个项目也包含多个模块,本质上module和project并没有根本上的区别,只是宏观上整体和部分的区别
  • 异:在传统单体项目中我们一个项目就是一个模块,在分布式和微服务中一个完整项目的多模块必须要都能独立部署运行,模块将互相远程通信
操作步骤:
  1. 新建一个空的project,在空的project中新建两module
  2. module中导入Spring和SpringMVC的pom依赖
  3. 一个moulde调用另一个moulde的方法接口,他们共用一个Spring配置文件
注:这里不使用mybatis了,它不影响多模块调用的还原,我不使用数据库
步骤1:新建一个空的project,在空的project中新建两module
新建一个空project
在空项目中建两个module:file -> new -> module

 

步骤2:导入Spring和SpringMVC的坐标

<groupId>org.example</groupId>
<artifactId>bubbo-server</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<spring-version>5.1.9.RELEASE</spring-version>
</properties>

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-version}</version>
</dependency>

<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>

步骤3:在模块中构建SSM

因为dubbo-web依赖于dubbo-server,所以在dubbo-web的pom加入dubbo-server的依赖(运行是dubbo-server需要install一下)

<dependency>
<groupId>org.example</groupId>
<artifactId>bubbo-server</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
dubbo-server的Springconf.xml:
dubbo-web的Springmvc.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!--注解扫描,只扫描Controller-->
<context:component-scan base-package="wql"/>

<!--配置视图解析器-->

<bean name="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>

<!--MVC驱动-->
<mvc:annotation-driven/>
</beans>
dubbo-web的web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">

<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>

<load-on-startup>1</load-on-startup>
</servlet>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!--设置Spring配置文件这里依赖于dubbo-server的Spring配置文件,跨模块依赖-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springconf.xml</param-value>
</context-param>

<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>

<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
服务代码很简单,自己写
步骤4:Tomcat运行dubbo-web看是否可以调用dubbo-server并返回结果
调用成功
上面的dome说明在没有dubbo时,多模块之间也是可以调用的,但它只是普通的本地调用,本质它其实还是一个单体的,因为它不能独立启动部署提供服务,但在分布式项目中多模块需要独立部署远程调用,显然本地调用不能满足需求,需要一个强有力的框架来完成这个功能,然后就产生了dubbo(底层通信是netty实现)