一、Dubbo概述

1.1 Dubbo概念

  • Dubbo是阿里巴巴公司开源的一个高性能、轻量级的Java RPC框架
  • 致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案
  • 官网:http://dubbo.apache.org

1.2 Dubbo架构说明

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

二、Dubbo快速入门

实现步骤

  1. 创建服务提供者Provider模块
  2. 创建服务消费者Consumer模块
  3. 在服务提供者模块编写UserServiceImpl提供服务
  4. 在服务消费者中的UserController远程调用UserServiceImpl提供的服务
  5. 分别启动两个服务进行测试

2.1 配置Zookeeper注册中心

  • Dubbo官方推荐使用Zookeeper作为注册中心

2.1.1 下载安装

1、环境准备

ZooKeeper服务器是用Java创建的,它运行在JVM之上。需要安装JDK 7或更高版本。

2、上传

将下载的ZooKeeper放到/opt/ZooKeeper目录下

#上传zookeeper alt+p
put f:/setup/apache-zookeeper-3.5.6-bin.tar.gz
#打开 opt目录
cd /opt
#创建zooKeeper目录
mkdir zooKeeper
#将zookeeper安装包移动到 /opt/zooKeeper
mv apache-zookeeper-3.5.6-bin.tar.gz /opt/zookeeper/

3、解压

将tar包解压到/opt/zookeeper目录下

tar -zxvf apache-ZooKeeper-3.5.6-bin.tar.gz 

2.1.2 配置启动

1、配置zoo.cfg

进入到conf目录拷贝一个zoo_sample.cfg并完成配置

#进入到conf目录
cd /opt/zooKeeper/apache-zooKeeper-3.5.6-bin/conf/
#拷贝
cp zoo_sample.cfg zoo.cfg

修改zoo.cfg

#打开目录
cd /opt/zooKeeper/
#创建zooKeeper存储目录
mkdir zkdata
#修改zoo.cfg
vim /opt/zooKeeper/apache-zooKeeper-3.5.6-bin/conf/zoo.cfg

修改存储目录:dataDir=/opt/zookeeper/zkdata

2、启动ZooKeeper

cd /opt/zooKeeper/apache-zooKeeper-3.5.6-bin/bin/
#启动
./zkServer.sh start

3、查看ZooKeeper状态

./zkServer.sh status

zookeeper启动成功。standalone代表zk没有搭建集群,现在是单节点

2.2 创建MVC项目【单体架构】

MVC架构:

  • 空项目dubbo-pro
  • maven项目:dubbo-service,dubbo-web

2.2.1 配置dubbo-service

① 配置pom

<properties>
<spring.version>5.1.9.RELEASE</spring.version>
<dubbo.version>2.7.4.1</dubbo.version>
<zookeeper.version>4.0.0</zookeeper.version>
</properties>
<dependencies>
<!-- servlet3.0规范的坐标 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--spring的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--springmvc的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</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>



<!--Dubbo的起步依赖,版本2.7之后统一为rg.apache.dubb -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!--ZooKeeper客户端实现 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<!--ZooKeeper客户端实现 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${zookeeper.version}</version>
</dependency>
</dependencies>

② 配置applicationContext.xml

目录:spring/applicationContext.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" 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://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.bamboo.service"/>

</beans>

③ 配置log4j.properties

# DEBUG < INFO < WARN < ERROR < FATAL
# Global logging configuration
log4j.rootLogger=info, stdout,file
# My logging configuration...
#log4j.logger.com.tocersoft.school=DEBUG
#log4j.logger.net.sf.hibernate.cache=debug
## Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n

log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=../logs/iask.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %m%n

④ 编写Service

// package com.bamboo.service;
public interface UserService {
String sayHello();
}

// package com.bamboo.service.impl;
@Service
public class UserServiceImpl implements UserService {

public String sayHello() {
return "hello dubbo!~";
}
}

2.2.2 配置dubbo-web

① 配置pom

<packaging>war</packaging>

<properties>
<spring.version>5.1.9.RELEASE</spring.version>
<dubbo.version>2.7.4.1</dubbo.version>
<zookeeper.version>4.0.0</zookeeper.version>
</properties>

<dependencies>
<!-- servlet3.0规范的坐标 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--spring的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--springmvc的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</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>
<!--Dubbo的起步依赖,版本2.7之后统一为rg.apache.dubb -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!--ZooKeeper客户端实现 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<!--ZooKeeper客户端实现 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<!--依赖service-->
<dependency>
<groupId>com.bamboo</groupId>
<artifactId>dubbo-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>


<build>
<plugins>
<!--tomcat插件-->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8000</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>

② 配置web.xml

目录:webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">

<!-- spring -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Springmvc -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

</web-app>

③ 配置springmvc.xml

目录:spring/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:dubbo="http://dubbo.apache.org/schema/dubbo"
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://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<mvc:annotation-driven/>
<context:component-scan base-package="com.bamboo.controller"/>
</beans>

④ 配置log4j.properties

# DEBUG < INFO < WARN < ERROR < FATAL
# Global logging configuration
log4j.rootLogger=info, stdout,file
# My logging configuration...
#log4j.logger.com.tocersoft.school=DEBUG
#log4j.logger.net.sf.hibernate.cache=debug
## Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n

log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=../logs/iask.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %m%n

⑤ 编写Controller

// package com.bamboo.controller;
@RestController
@RequestMapping("/user")
public class UserController {

@Autowired
private UserService userService;

@GetMapping("/sayHello")
public String sayHello() {
return userService.sayHello();
}
}

2.3 Provider服务提供者改造

2.3.1 修改pom

  • 打包方式使用war
  • 添加tomcat7-maven-plugin插件
<packaging>war</packaging>

<properties>
<spring.version>5.1.9.RELEASE</spring.version>
<dubbo.version>2.7.4.1</dubbo.version>
<zookeeper.version>4.0.0</zookeeper.version>
</properties>
<dependencies>
<!-- servlet3.0规范的坐标 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--spring的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--springmvc的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</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>



<!--Dubbo的起步依赖,版本2.7之后统一为rg.apache.dubb -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!--ZooKeeper客户端实现 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<!--ZooKeeper客户端实现 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${zookeeper.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!--tomcat插件-->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>9000</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>

2.3.2 修改@Service

// import org.apache.dubbo.config.annotation.Service;
@Service // 将这个类提供的方法(服务)对外发布,将访问的地址 ip,端口,路径注册到注册中心中
public class UserServiceImpl implements UserService {

public String sayHello() {
return "hello dubbo!~";
}
}

2.3.3 修改applicationContext.xml

  • 配置Spring的Dubbo配置
<?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" 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://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<!--dubbo配置-->
<!--配置项目的名称:唯一-->
<dubbo:application name="dubbo-service"/>
<!--配置注册中心地址-->
<dubbo:registry address="zookeeper://192.168.49.11:2181"/>
<!--配置dubbo包扫描-->
<dubbo:annotation package="com.bamboo.service.impl"/>
</beans>

2.3.4 添加web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">


<!-- spring -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

</web-app>

2.4 Consumer服务消费者改造

2.4.1 删除pom的Provider依赖

<!--依赖service-->
<dependency>
<groupId>com.bamboo</groupId>
<artifactId>dubbo-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

2.4.2 修改applicationContext.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"
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://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<mvc:annotation-driven/>
<!--扫描springmvc的注解-->
<context:component-scan base-package="com.bamboo.controller"/>

<!--dubbo配置-->
<!--配置项目的名称:唯一-->
<dubbo:application name="dubbo-web">
<!--单机器部署问题:Address already in use: bind,启动两个dubbo时会出现此问题-->
<!--ERROR 2023-08-30 17:57:49,656 org.apache.dubbo.qos.server.Server: [DUBBO] qos-server can not bind localhost:22222, dubbo version: 2.7.4.1, current host: 192.168.0.103-->
<dubbo:parameter key="qos.port" value="33333"/>
</dubbo:application>
<!--配置注册中心地址-->
<dubbo:registry address="zookeeper://192.168.49.11:2181"/>
<!--配置dubbo包扫描-->
<dubbo:annotation package="com.bamboo.controller"/>
</beans>

2.4.3 使用@Reference远程调用

  1. 从zookeeper注册中心获取userService的访问url
  2. 进行远程调用RPC
  3. 将结果封装为一个代理对象。给变量赋值
@RestController
@RequestMapping("/user")
public class UserController {

@Reference // 远程注入
private UserService userService;

@GetMapping("/sayHello")
public String sayHello() {
return userService.sayHello();
}
}

问题:找不到UserService接口

2.5 添加通用dubbo-interface模块

2.5.1 编写通用interface

package com.bamboo.service;

public interface UserService {
String sayHello();
}

2.5.2 Consumer和Provider导入模块

<dependency>
<groupId>com.bamboo</groupId>
<artifactId>dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

删除Provider中的重复Service接口

三、Dubbo高级特性

3.1 dubbo-admin管理平台

3.1.1 简介

  • dubbo-admin管理平台,是图形化的服务管理页面
  • 从注册中心获取到所有的提供者/消费者进行配置管理
  • 路由规则、动态配置、服务降级、访问控制、权重调整、负载均衡等管理功能
  • dubbo-admin是一个前后端分离的项目,前端使用vue,后端使用springboot
  • 安装dubbo-admin其实就是在部署该项目

3.1.2 安装

1、环境准备

dubbo-admin 是一个前后端分离的项目。前端使用vue,后端使用springboot,安装 dubbo-admin 其实就是部署该项目。我们将dubbo-admin安装到开发环境上。要保证开发环境有jdk,maven,nodejs

安装node**(如果当前机器已经安装请忽略)**

因为前端工程是用vue开发的,所以需要安装node.js,node.js中自带了npm,后面我们会通过npm启动

下载地址

https://nodejs.org/en/

2、下载 Dubbo-Admin

进入github,搜索dubbo-admin

https://github.com/apache/dubbo-admin

3、把下载的zip包解压到指定文件夹(解压到那个文件夹随意)

4、修改配置文件

解压后我们进入…\dubbo-admin-develop\dubbo-admin-server\src\main\resources目录,找到 application.properties 配置文件 进行配置修改zookeeper地址

# centers in dubbo2.7, if you want to add parameters, please add them to the url
admin.registry.address=zookeeper://192.168.49.11:2181
admin.config-center=zookeeper://192.168.49.11:2181
admin.metadata-report.address=zookeeper://192.168.49.11:2181
  • admin.registry.address注册中心
  • admin.config-center 配置中心
  • admin.metadata-report.address元数据中心

5、打包项目

在 dubbo-admin-develop 目录执行打包命令

mvn  clean package

6、启动后端

切换到目录

dubbo-Admin-develop\dubbo-admin-distribution\target>

执行下面的命令启动 dubbo-admin,dubbo-admin后台由SpringBoot构建。

java -jar .\dubbo-admin-0.1.jar

7、前台后端

dubbo-admin-ui 目录下执行命令

npm run dev

8、访问

浏览器输入。用户名密码都是root

http://localhost:38082

3.1.3 dubbo-admin简单使用

① 元数据开启

服务查询中无法直接查看元数据信息

dubo-admin查看详情

C区域:是元数据信息,注意看上面的图,元数据信息是空的

我们需要打开我们的生产者配置文件加入下面配置

<!--打开元数据-->
<dubbo:metadata-report address="zookeeper://192.168.49.11:2181" />

重新启动生产者,再次打开Dubbo-Admin

② 开启元数据的必要性

  • 服务查询中元数据可查看
  • 服务测试中可测试远程服务

3.2 dubbo 常用高级配置

3.2.1 序列化

两个机器传输数据,传输Java对象时使用,例如Class User

  • dubbo内部已经将序列化和反序列化的过程进行了内部封装
  • 只需要在定义pojo类时实现Serializable接口即可
  • 一般会定义一个公共的pojo模块,让生产者和消费者都依赖该模块

① 创建pojo模块

  • dubbo-pojo
package com.bamboo.pojo;
/**
* 将来所有的pojo类都需要实现Serializable接口
*/
public class User implements Serializable {
private int id;
private String username;
private String password;
}

② 在interface模块中导入pojo模块

<dependencies>
<dependency>
<groupId>com.bamboo</groupId>
<artifactId>dubbo-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
public interface UserService {
User findUserById(int id);
}

③ Provider调用

 @Service // 将这个类提供的方法(服务)对外发布,将访问的地址 ip,端口,路径注册到注册中心中
public class UserServiceImpl implements UserService {

public User findUserById(int id) {
User user = new User(1, "zhangsan", "123");
return user;
}
}

④ Consumer调用

@RestController
@RequestMapping("/user")
public class UserController {

@Reference // 远程注入
private UserService userService;

/**
* 根据id查询信息
* @param id
* @return
*/
@GetMapping("/find")
public User find(int id) {
return userService.findUserById(id);
}
}

⑤ 测试

// 20230830212654
// http://localhost:8000/user/find.do?id=1

{
"id": 1,
"username": "zhangsan",
"password": "123"
}

3.2.2 地址缓存

注册中心挂了,服务可以正常访问

  1. Dubbo服务消费者在第一次调用时,会将服务提供方地址缓存到本地,以后调用则不会访问注册中心。
  2. 当服务提供者地址发送变化时,注册中心才会通知服务消费者。

3.2.3 超时

建议配置在服务提供者Provider

@Service(timeout = 3000,retries = 0)
  • 服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一致等待下去。
  • 在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程大量堆积,势必会造成雪崩。
  • dubbo利用超时机制来解决这个问题,设置一个超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
  • 使用timeout属性配置超时时间,默认值1000,单位毫秒。

① Consumer应用【推荐】

@Service(timeout = 3000,retries = 0)
public class UserServiceImpl implements UserService {

public String sayHello() {
return "hello bamboo dubbo!~";
}

public User findUserById(int id) {
User user = new User(1, "zhangsan", "123");
return user;
}
}
  • timeout:三秒后超时
  • retries:重试0次

② Provider应用【不推荐】

@Reference(timeout = 3000,retries = 0) // 远程注入
private UserService userService;

3.2.4 重试

  • 设置了超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
  • 如果出现网络抖动,则这一次请求就会失败。
  • Duboo提供重试机制来避免类似问题的发送。
  • 通过retries属性来设置重试次数,默认为2
@Service(timeout = 3000,retries = 0)
public class UserServiceImpl implements UserService{}

3.2.5 多版本

灰度发布

  • 当出现新功能时,会让一部分用户先使用新功能,用户反馈没问题时,再将所有用户迁移到新功能。
  • dubbo中使用version属性来设置和调用同一接口的不同版本

① Provider端

1)旧功能

@Service(version = "v1.0")
public class UserServiceImpl implements UserService {

public String sayHello() {
return "hello bamboo dubbo!~";
}

public User findUserById(int id) {
System.out.println("old...");
User user = new User(1, "zhangsan", "123");
return user;
}
}

2)新功能

@Service(version = "v2.0")
public class UserServiceImpl2 implements UserService {

public String sayHello() {
return "hello bamboo dubbo!~";
}

public User findUserById(int id) {
System.out.println("new...");
User user = new User(1, "zhangsan", "123");
return user;
}
}

② Consumer端

@RestController
@RequestMapping("/user")
public class UserController {
// 使用旧功能version
@Reference(version = "v1.0") // 远程注入
private UserService userService;

@GetMapping("/sayHello")
public String sayHello() {
return userService.sayHello();
}

/**
* 根据id查询信息
*
* @param id
* @return
*/
int i = 1;

@GetMapping("/find")
public User find(int id) {
return userService.findUserById(id);
}
}

3.2.6 负载均衡

负载均衡策略:

  • Random:按权重随机,默认值。按权重设置随机概率。
  • RoundRobin:按权重轮询。
  • LeastActive:最少活跃调用数,相同活跃数的随机。
  • ConsistentHash:一致性Hash,相同参数的请求总是发到统一提供者。

① 搭建负载均衡——1

1)ServiceImpl

@Service(weight = 100)
public class UserServiceImpl implements UserService {

public String sayHello() {
return "1......";
}

public User findUserById(int id) {
System.out.println("old...");
User user = new User(1, "zhangsan", "123");
return user;
}
}

2)端口号

<build>
<plugins>
<!--tomcat插件-->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>9000</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>

3)注册中心端口

<dubbo:protocol port="20880"/>

② 搭建负载均衡——2

1)ServiceImpl

@Service(weight = 200)
public class UserServiceImpl implements UserService {

public String sayHello() {
return "2......";
}

public User findUserById(int id) {
System.out.println("old...");
User user = new User(1, "zhangsan", "123");
return user;
}
}

2)端口号

<build>
<plugins>
<!--tomcat插件-->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>9002</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>

3)注册中心端口

<dubbo:protocol port="20882"/>

4)qos端口

<dubbo:application name="dubbo-web">
<!--单机器部署问题:Address already in use: bind,启动两个dubbo时会出现此问题-->
<!--ERROR 2023-08-30 17:57:49,656 org.apache.dubbo.qos.server.Server: [DUBBO] qos-server can not bind localhost:22222, dubbo version: 2.7.4.1, current host: 192.168.0.103-->
<dubbo:parameter key="qos.port" value="44444"/>
</dubbo:application>

③ 搭建负载均衡——3

1)ServiceImpl

@Service(weight = 100)
public class UserServiceImpl implements UserService {

public String sayHello() {
return "3......";
}

public User findUserById(int id) {
System.out.println("old...");
User user = new User(1, "zhangsan", "123");
return user;
}
}

2)端口号

<build>
<plugins>
<!--tomcat插件-->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>9003</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>

3)注册中心端口

<dubbo:protocol port="20883"/>

4)qos端口

<dubbo:application name="dubbo-web">
<!--单机器部署问题:Address already in use: bind,启动两个dubbo时会出现此问题-->
<!--ERROR 2023-08-30 17:57:49,656 org.apache.dubbo.qos.server.Server: [DUBBO] qos-server can not bind localhost:22222, dubbo version: 2.7.4.1, current host: 192.168.0.103-->
<dubbo:parameter key="qos.port" value="55555"/>
</dubbo:application>

④ 远程调用

搜索AbstractLoadBalance类,查找对应的实现类,name作为参数值

  • ConsistentHashLoadBalance:NAME = "consistenthash"
  • LeastActiveLoadBalance:NAME = "leastactive"
  • RoundRobinLoadBalance:NAME = "roundrobin"
  • RandomLoadBalance:NAME = "random"【默认规则】
@RestController
@RequestMapping("/user")
public class UserController {

@Reference(loadbalance = "random") // 远程注入
private UserService userService;

@GetMapping("/sayHello")
public String sayHello() {
return userService.sayHello();
}

/**
* 根据id查询信息
*
* @param id
* @return
*/
int i = 1;

@GetMapping("/find")
public User find(int id) {
return userService.findUserById(id);
}
}

⑤ 测试

访问http://localhost:8000/user/sayHello.do

3.2.7 集群容错

① 集群容错模式

  • Failover Cluster:失败重试,默认值。
    • 当出现失败,重试其他服务器,默认重试两次,使用retries配置,一般用于读操作
  • Failfast Cluster:快速失败。
    • 只发起一次调用,失败立即报错。通常用于写操作。
  • Failsafe Cluster:失败安全。
    • 出现异常时,直接忽略,返回一个空结果。
  • Failback Cluster:失败自动恢复
    • 后台记录失败请求,定时重发。
  • Forking Cluster:并行调用多个服务器,只要一个成功即返回。
  • Broadcast Cluster:广播调用所有提供者,逐个调用,任意一台报错则报错。

② 顶级接口:Cluster

  • AvailableCluster NAME = "available"
  • FailsafeCluster String NAME = "failsafe"
  • FailfastCluster NAME = "failfast"
  • ForkingCluster NAME = "forking"
  • MergeableCluster NAME = "mergeable"
  • FailbackCluster NAME = "failback"
  • FailoverCluster NAME = "failover" 【默认规则】
  • RegistryAwareCluster NAME = "registryaware"
@RestController
@RequestMapping("/user")
public class UserController {

@Reference(cluster = "failover") // 远程注入
private UserService userService;

@GetMapping("/sayHello")
public String sayHello() {
return userService.sayHello();
}

/**
* 根据id查询信息
*
* @param id
* @return
*/
int i = 1;

@GetMapping("/find")
public User find(int id) {
return userService.findUserById(id);
}
}

3.2.8 服务降级

服务降级方式:

  • mock = "force:return null"表示消费方对该服务的方法调用都直接返回null值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。

    @Reference(mock = "force:return null") // 不在调用userService的服务
    private UserService userService;
  • mock = "fail:return null"表示消费方对该服务的方法调用在失败后,再返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

    @Reference(mock = "fail:return null") // 不在调用userService的服务
    private UserService userService;