
环境准备
dubbo-admin 是一个前后端分离的项目。前端使用vue,后端使用springboot,安装 dubbo-admin 其实就是部署该项目。我们将dubbo-admin安装到开发环境上。要保证开发环境有jdk,maven,node.js
安装node**(如果当前机器已经安装请忽略)**
因为前端工程是用vue开发的,所以需要安装node.js,node.js中自带了npm,后面我们会通过npm启动

下载 Dubbo-Admin
进入github,搜索dubbo-admin

git clone git@github.com:apache/dubbo-admin.git


# centers in dubbo2.7
admin.registry.address=zookeeper://192.168.91.200:2181
admin.config-center=zookeeper://192.168.91.200:2181
admin.metadata-report.address=zookeeper://192.168.91.200:2181admin.registry.address注册中心 admin.config-center 配置中心 admin.metadata-report.address元数据中心
在 dubbo-admin-develop 目录执行打包命令
mvn clean package
切换到目录
dubbo-Admin-develop\dubbo-admin-distribution\target>执行下面的命令启动 dubbo-admin,dubbo-admin后台由SpringBoot构建。
java -jar .\dubbo-admin-0.1.jar
前台后端
dubbo-admin-ui 目录下执行命令
npm run dev

注意:Dubbo Admin【服务Mock】【服务统计】将在后续版本发布....
在上面的步骤中,我们已经进入了Dubbo-Admin的主界面,在【快速入门】章节中,我们定义了服务生产者、和服务消费者,下面我们从Dubbo-Admin管理界面找到这个两个服务

我们查看com.frx01.service.UserService (服务提供者)的具体详细信息,包含【元数据信息】


从【详情】界面查看,主要分为3个区域
A区域:主要包含服务端 基础信息比如服务名称、应用名称等
B区域:主要包含了生产者、消费者一些基本信息
C区域:是元数据信息,注意看上面的图,元数据信息是空的
我们需要打开我们的生产者配置文件加入下面配置
<!-- 元数据配置 -->
<dubbo:metadata-report address="zookeeper://192.168.91.200:2181" />
两个机器传输数据,如何传输Java对象?

//注意:将来所有的pojo都需要实现Serializable接口
public class User implements Serializable {
private int id;
private String username;
private String password;
//+set()与get()方法,和AllArgsConstructor
} <dependencies>
<dependency>
<groupId>com.frx01</groupId>
<artifactId>dubbo-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies> //查询用户
public User findUserById(int id); @Override
public User findUserById(int id) {
//查询User对象
User user = new User(1, "zhangsan", "123");
return user;
}
注册中心挂了,服务是否可以正常访问?


//将这这类提供的方法(服务)对外发布,将访问的地址,ip,端口,路径注册到注册中心中
@Service(timeout = 3000)//当前服务3秒超时
public class UserServiceImpl implements UserService {
@Override
public String sayHello() {
return "hello,dubbo~";
}
@Override
public User findUserById(int id) {
//查询User对象
User user = new User(1, "zhangsan", "123");
//假如数据库查询很慢,查了5秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return user;
}
}org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. start time: 2022-08-11 00:18:54.577, end time: 2022-08-11 00:18:57.606, client elapsed: 0 ms, server elapsed: 3029 ms, timeout: 3000 ms, request: Request [id=2, version=2.0.2, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=findUserById, parameterTypes=[int], arguments=[1], attachments={path=com.frx01.service.UserService, remote.application=dubbo-web, interface=com.frx01.service.UserService, version=0.0.0, timeout=3000}]], channel: /10.19.242.91:56864 -> /10.19.242.91:20880
at org.apache.dubbo.remoting.exchange.support.DefaultFuture.doReceived(DefaultFuture.java:189)
at org.apache.dubbo.remoting.exchange.support.DefaultFuture.received(DefaultFuture.java:153)
at org.apache.dubbo.remoting.exchange.support.DefaultFuture$TimeoutCheckTask.run(DefaultFuture.java:258)
at org.apache.dubbo.common.timer.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:648)
at org.apache.dubbo.common.timer.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:727)
at org.apache.dubbo.common.timer.HashedWheelTimer$Worker.run(HashedWheelTimer.java:449)
at java.lang.Thread.run(Thread.java:748)注意
@Reference//远程注入,也有超时属性
@Reference(timeout = 1) //远程注入@RestController
@RequestMapping("/user")
public class UserController {
/**
* 1.从zookeeper注册中心获取userService的访问url
* 2.远程的调用RPC
* 3.将结果封装为代理的对象,给变量赋值
*/
@Reference(timeout = 1000) //远程注入,当前服务一秒超时
private UserService userService;
@RequestMapping("/sayHello")
public String sayHello(){
return userService.sayHello();
}
/**
* 根据id查询用户信息
* @param id
* @return
*/
@RequestMapping("/find")
public User findUserById(int id){
return userService.findUserById(id);
}
}问题
可以发现,出现了个问题,究竟是@Service注解超时3秒生效,还是@Reference注解超时1秒生效。
经过测试,服务生产方的超时时间覆盖了消费方的超时时间,但是超时时间在服务的生产方或者消费方单独地都生效,建议把超时时间配置在服务的生产方

//将这这类提供的方法(服务)对外发布,将访问的地址,ip,端口,路径注册到注册中心中
@Service(timeout = 3,retries = 2)//当前服务3秒超时,重试两次,一共三次
public class UserServiceImpl implements UserService {
@Override
public String sayHello() {
return "hello,dubbo~";
}
int i =1;
@Override
public User findUserById(int id) {
System.out.println("服务被调用了:"+i+++"次");
//查询User对象
User user = new User(1, "zhangsan", "123");
//假如数据库查询很慢,查了5秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return user;
}
}服务被调用了:1
服务被调用了:2
服务被调用了:3
WARN 2022-08-11 00:20:22,923 org.apache.dubbo.rpc.filter.TimeoutFilter$TimeoutListener: [DUBBO] invoke time out. method: findUserById arguments: [1] , url is dubbo://10.19.242.91:20880/com.frx01.service.UserService?anyhost=true&application=dubbo-service&bean.name=ServiceBean:com.frx01.service.UserService&bind.ip=10.19.242.91&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.frx01.service.UserService&methods=sayHello,findUserById&pid=22460&release=2.7.4.1&revision=1.0-SNAPSHOT&side=provider&timeout=3000×tamp=1660148406833, invoke elapsed 5009 ms., dubbo version: 2.7.4.1, current host: 10.19.242.91
@Service(version = "v1.0")
public class UserServiceImpl implements UserService {
@Override
public String sayHello() {
return "hello,dubbo~";
}
@Override
public User findUserById(int id) {
System.out.println("old...");
//查询User对象
User user = new User(1, "zhangsan", "123");
return user;
}
}@Service(version = "v2.0")
public class UserServiceImpl2 implements UserService {
@Override
public String sayHello() {
return "hello,dubbo~";
}
@Override
public User findUserById(int id) {
System.out.println("new...");
//查询User对象
User user = new User(1, "zhangsan", "123");
return user;
}
}@RestController
@RequestMapping("/user")
public class UserController {
/**
* 1.从zookeeper注册中心获取userService的访问url
* 2.远程的调用RPC
* 3.将结果封装为代理的对象,给变量赋值
*/
@Reference(version = "v1.0") //远程注入
private UserService userService;
@RequestMapping("/sayHello")
public String sayHello(){
return userService.sayHello();
}
/**
* 根据id查询用户信息
* @param id
* @return
*/
@RequestMapping("/find")
public User findUserById(int id){
return userService.findUserById(id);
}
}old...new...


@Service(weight = 100)
public class UserServiceImpl implements UserService {
@Override
public String sayHello() {
return "1.......";
}
@Override
public User findUserById(int id) {
//查询User对象
User user = new User(1, "zhangsan", "123");
return user;
}
}@Service(weight = 200)
public class UserServiceImpl implements UserService {
@Override
public String sayHello() {
return "2......";
}
@Override
public User findUserById(int id) {
//查询User对象
User user = new User(1, "zhangsan", "123");
return user;
}
} <!--<context:component-scan base-package="com.frx01.service"/>-->
<!--dubbo的配置-->
<dubbo:protocol port="20882"/>
<!--1.项目的名称-->
<dubbo:application name="dubbo-service">
<dubbo:parameter key="qos.port" value="4444"/>
</dubbo:application>
<!--2.配置一下注册中心的地址-->
<dubbo:registry address="zookeeper://192.168.91.200:2181"/>
<!--3.配置dubbo包扫描-->
<dubbo:annotation package="com.frx01.service.impl"/>
<dubbo:metadata-report address="zookeeper://192.168.91.200:2181" />
@RestController
@RequestMapping("/user")
public class UserController {
/**
* 1.从zookeeper注册中心获取userService的访问url
* 2.远程的调用RPC
* 3.将结果封装为代理的对象,给变量赋值
*/
@Reference(loadbalance = "random") //远程注入 //random:按权重随机
private UserService userService;
@RequestMapping("/sayHello")
public String sayHello(){
return userService.sayHello();
}
/**
* 根据id查询用户信息
* @param id
* @return
*/
@RequestMapping("/find")
public User findUserById(int id){
return userService.findUserById(id);
}
}
集群容错模式:
@Service
public class UserServiceImpl implements UserService {
@Override
public String sayHello() {
return "hello dubbo Test~";
}
@Override
public User findUserById(int id) {
System.out.println("1...");
//查询User对象
User user = new User(1, "zhangsan", "123");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return user;
}
}@Service
public class UserServiceImpl implements UserService {
@Override
public String sayHello() {
return "hello dubbo Test~";
}
@Override
public User findUserById(int id) {
System.out.println("2...");
//查询User对象
User user = new User(1, "zhangsan", "123");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return user;
}
} <!--dubbo的配置-->
<dubbo:protocol port="20882"/>
<!--<!–1.项目的名称–>-->
<dubbo:application name="dubbo-service">
<dubbo:parameter key="qos.port" value="4445"/>
</dubbo:application>
<!--2.配置一下注册中心的地址-->
<dubbo:registry address="zookeeper://192.168.91.200:2181"/>
<!--3.配置dubbo包扫描-->
<dubbo:annotation package="com.frx01.service.impl"/>
<dubbo:metadata-report address="zookeeper://192.168.91.200:2181" />@Service
public class UserServiceImpl implements UserService {
@Override
public String sayHello() {
return "hello dubbo Test~";
}
@Override
public User findUserById(int id) {
System.out.println("3...");
//查询User对象
User user = new User(1, "zhangsan", "123");
return user;
}
} <dubbo:protocol port="20888"/>
<!--<!–1.项目的名称–>-->
<dubbo:application name="dubbo-service">
<dubbo:parameter key="qos.port" value="4446"/>
</dubbo:application>
<!--2.配置一下注册中心的地址-->
<dubbo:registry address="zookeeper://192.168.91.200:2181"/>
<!--3.配置dubbo包扫描-->
<dubbo:annotation package="com.frx01.service.impl"/>
<dubbo:metadata-report address="zookeeper://192.168.91.200:2181" />
@RestController
@RequestMapping("/user")
public class UserController {
/**
* 1.从zookeeper注册中心获取userService的访问url
* 2.远程的调用RPC
* 3.将结果封装为代理的对象,给变量赋值
*/
@Reference(cluster = "failover") //重试 并且重试两次
private UserService userService;
@RequestMapping("/sayHello")
public String sayHello(){
return userService.sayHello();
}
/**
* 根据id查询用户信息
* @param id
* @return
*/
@RequestMapping("/find")
public User findUserById(int id){
return userService.findUserById(id);
}
}

服务降级方式:
@RestController
@RequestMapping("/user")
public class UserController {
/**
* 1.从zookeeper注册中心获取userService的访问url
* 2.远程的调用RPC
* 3.将结果封装为代理的对象,给变量赋值
*/
@Reference(mock = "force:return null")//不再去调用userService的服务了
private UserService userService;
@RequestMapping("/sayHello")
public String sayHello(){
return userService.sayHello();
}
/**
* 根据id查询用户信息
* @param id
* @return
*/
@RequestMapping("/find")
public User findUserById(int id){
return userService.findUserById(id);
}
}
返回为null,也不报错,一个空白的页面