Dubbo是一款高性能、轻量级的开源Java RPC框架,
它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
即实现了多个独立应用之间的解耦且可以远程调用对方的服务
很多时候,因为项目需要用到分布式架构,所以就引用了dubbo这项技术,但是至于为什么我们需要用到这个技术
可能自身并不是很了解,但是,其实了解技术的来由及背景知识,对于理解一项技术还是有帮助的,
在以前,我们只需要一个服务器,将程序全部打包好就可以,但是,随着流量的增大,常规的垂直应用架构已无法应对,所以,架构就发生了演变。
所需演变的方面
1 单一应用架构
2 应用和数据库单独部署
3 应用和数据库集群部署
4 数据库压力变大,读写分离
5 使用缓存技术加快速度
6 数据库分库分表
7 应用分为不同的类型拆分
发展到这个阶段的时候,我们发现,应用与应用之间的关系已经十分的复杂了,就会出现以下几个问题(以下摘录于官网):
① 当服务越来越多时,服务 URL 配置管理变得非常困难,F5 硬件负载均衡器的单点压力也越来越大。
② 当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。
③ 接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?
为了解决这由于架构的演变所产生的问题几个问题,于是,dubbo 产生了。当然,解决这个问题的技术不止 dubbo 。
1.注册与发现
Dubbo使用zookeeper做服务的注册中心,就是服务的提供者以临时节点的形式将服务Server信息注册保存到Zookeeper的dubbo目录下
的provider的节点下,供消费者发现调用。
2.负载均衡
Dubbo支持负载均衡策略,就是同一个Dubbo服务被多台服务器启用后,会在Zookeeper提供者节点下显示多个相同接口名称节点。
消费者在调用Dubbo负载均衡服务时,采用权重的算法策略选择具体某个服务器上的服务,权重策略以*2倍数设置。
3.容错机制
Dubbo的提供者在Zookeeper上使用的是临时节点,一旦提供者所在服务挂掉,该节点的客户端连接将会关闭,故节点自动消失。所以消费者调用接口时将不会轮询到已经挂掉的接口上(延迟例外)。
4.Dubbo协议
Dubbo常用协议有两种:dubbo、hessian
dubbo:
Dubbo 缺省协议是dubbo协议,采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。
hessian:
Hessian底层采用Http通讯(同步),采用Servlet暴露服务。适用于传入传出参数数据包较大,消费者并发量少,提供者较多,可传文件。
5.Dubbo容器
Dubbo在java jvm中有自己的容器,和Spring IOC的bean一样,将服务对象保存到自己的容器中。
6.监控中心
监控中心主要是用来服务监控和服务治理。
服务治理包含:负载均衡策略、服务状态、容错、路由规则限定、服务降级等。具体可以下载Dubbo监控中心客户端查看与设置。
dubbo监控中心下载和搭建启动参考网址https://blog.csdn.net/a704397849/article/details/91904842
节点 角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器
看了这几个概念后似乎发现,其实 Dubbo 的架构也是很简单的(其实现细节是复杂的),为什么这么说呢,有没有发现,
其实很像"生产者-消费者"模型。只是在这种模型上,加上了注册中心和监控中心,用于管理提供方提供的url,以及监控和管理整个过程
1、启动容器,加载,运行服务提供者。
2、服务提供者在启动时,在注册中心发布注册自己提供的服务。
3、服务消费者在启动时,在注册中心订阅自己所需的服务
即java中整合了dubbo,在spirngboot的启动类上加一个启动的注解,服务启动即自动开启容器
1、注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
2、服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
3、服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
这些均可在java配置文件中进行配置,下面在详细讲述
欲实现dubbo架构先要搭建zookeeper集群作为服务注册发现中心,安装集群步骤参考网址https://blog.csdn.net/weixin_43784880/article/details/104428651
此前就完成了dubbo-admin和zookepper集群的搭建,启动后进行下面步骤
这里创建了一个主工程dubbo-hotels,其下包含了api、dubbo-provider、dubbo-customer
api: 主要存放公共实体类、需要远程调用的服务接口、也可以放一些公用的工具类工程
dubbo-provider: 服务提供工程 将接口实现类的服务暴露出去
dubbo-customer: 服务调用工程 远程从zookeeper调用提供者暴露的服务
切记:因为服务接口只是写在api工程中,所以dubbo-provider、dubbo-customer两个工程都需要在pom文件中引入api的jar包,下面会一一阐述
父工程
1、先创建一个springboot主工程 dubbo-hotels
主工程添加依赖如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 添加springboot父级依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--自定义该工程的jar包的坐标-->
<groupId>com.hotels</groupId>
<artifactId>dubbo-hotels</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>dubbo-hotels</name>
<modules>
<!-- 服务消费者工程 -->
<module>dubbbo-customer</module>
<module>hotel-customer</module>
<!-- 服务提供者工程-->
<module>hotel-provider</module>
<module>dubbo-provider</module>
<!-- 主要放实体、接口、也可以放一些公用的工具类工程-->
<module>api</module>
</modules>
<!-- dependency依赖 版本号 的变量,也可以不要直接将版本号写在version中-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<dubbo-spring-boot>1.0.0</dubbo-spring-boot>
<dubbo.version>2.5.5</dubbo.version>
<zkclient.version>0.10</zkclient.version>
<lombok.version>1.16.18</lombok.version>
<spring-boot.version>1.5.7.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!--开启web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 使用lombok实现JavaBean的get、set、toString、hashCode、equals等方法的自动生成 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!-- Spring Boot Dubbo 依赖 -->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--zookeeper的客户端依赖-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.11</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
到这里父工程配置结束
服务接口工程 api
1、pom写法
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hotels</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>api</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、服务接口类
package com.hotel1.demo.api;
public interface DubboUserServer {
String getUser(Integer id);
}
跟普通接口没有两样,为了简单明了我这里只有一个方法,如果用到实体类操作数据库,可以创建实体类
无需其他过多配置,服务接口工程的配置结束
服务提供工程 dubbo-privoder
1、pom加入
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--子工程为了继承父工程的依赖,节省代码,可以在parent标签中加入父工程的jar包坐标-->
<parent>
<groupId>com.hotels</groupId>
<artifactId>dubbo-hotels</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.hotels</groupId>
<artifactId>dubbo-privoder</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>dubbo-privoder</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<!-- 为了引入api服务接口来实现接口类,需要引入api工程的jar包 这样可以引入api中的类-->
<dependency>
<groupId>com.hotels</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
父工程的依赖可以被子工程引入,即子工程无需再写一遍依赖,只需要parent父级依赖指定成子工程即可
dubbo-provider引入dubbo-hotels的pom,如图
A工程想要引入B工程的类,需要以依赖的形式引入B类的jar,如图
无论是dependency引入还是parent父级引入,关键在于要一一对应号groupId、artifactId、version等坐标和版本,否则出错
2、接口实现类
package com.provider.demo.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.hotel1.demo.api.DubboUserServer; //此处的DubboUserServer正是引入了api工程的接口,dubbo-provider中并不需要写此接口
import org.springframework.stereotype.Component;
//用到实体类对的话实体类要实现序列化接口
@Service(interfaceClass = DubboUserServer.class)//使用dubbo提供的service注解来暴露服务
@Component
public class DubboUserServerImpl implements DubboUserServer {
@Override
public String getUser(Integer id) {
String name = "";
if(1==id){
name = "董";
}else if(2==id){
name = "刘";
}else{
name = "杨";
}
return name;
}
}
3、启动类
package com.provider.demo;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo//添加此注解开启dubbo容器 必要
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
4、properties.yml
server:
port: 8083 //tomcat端口
dubbo:
application:
name: server-privoder //应用程序名
registry:
address: zookeeper://127.0.0.1:2181?backup=127.0.0.1:2182,127.0.0.1:2183 //我这里是zookeeper集群的写法
protocol:
name: dubbo
#修改默认端口要写成字符串形式,如果写20880数字将无法识别,暴露的服务使用的是默认端口20880
port: "20881"
scan: com.provider.demo.impl //用来扫描使用了dubbo暴露服务注解@Service的类所在的包
① 上面的文件其实就是类似 spring 的配置文件,而且,dubbo 底层就是 spring。
② 节点:dubbo:application
就是整个项目在分布式架构中的唯一名称,可以在 name 属性中配置,另外还可以配置 owner 字段,表示属于谁。
下面的参数是可以不配置的,这里配置是因为出现了端口的冲突,所以配置。
③ 节点:dubbo:monitor
监控中心配置, 用于配置连接监控中心相关信息,可以不配置,不是必须的参数。 本文就没有配置
④ 节点:dubbo:registry
配置注册中心的信息,比如,这里我们可以配置 zookeeper 作为我们的注册中心。address 是注册中心的地址,
也可以配置 N/A 表示由 dubbo 自动分配地址。或者说是一种直连的方式,不通过注册中心。
⑤ 节点:dubbo:protocol
name:服务发布的时候 dubbo 依赖什么协议,可以配置 dubbo、webserovice、Thrift、Hessain、http等协议,用name来指定。
这里仅解释两种协议:
dubbo:缺省协议是dubbo协议,采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。
hessian:Hessian底层采用Http通讯(同步),采用Servlet暴露服务。适用于传入传出参数数据包较大,消费者并发量少,提供者较多,可传文件。
port:服务暴露的端口用port来指定,此处的端口数字必须用字符串表示,否则无法识别,会使用dubbo默认端口20880
⑥ 节点:dubbo:scan:
用来扫描使用了dubbo暴露服务注解@Service的类所在的包
服务消费工程 dubbo-customer
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.hotels</groupId>
<artifactId>dubbo-hotels</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.hotels</groupId>
<artifactId>dubbo-customer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>dubbo-customer</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.hotels</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
5、测试web类
package com.customer.demo.web;
import com.hotel1.demo.api.DubboUserServer;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
//引入服务接口的注解 关键地方
@Reference
DubboUserServer dubboUserServer;
@RequestMapping(value = "/show", method = RequestMethod.GET)
public String shows() {
return dubboUserServer.getUser(2);
}
}
6、启动类同理加上@EnableDubbo
7、properties.yml
server:
port: 8084
dubbo:
application:
name: server-customer
registry:
address: zookeeper://127.0.0.1:2181?backup=127.0.0.1:2182,127.0.0.1:2183
protocol:
name: dubbo
#修改默认端口要写成字符串形式
port: "20880"
scan: com.customer.demo.web //扫描注解@Reference调用服务的类所在的包
启动dubbo-customer,在浏览器地址栏输入http://127.0.0.1:8084/test/show 即可测试