⼀、背景
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。
1、单体架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
2、垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,提升效率的方法之一是将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
3、分布式应用架构阶段
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
二、RPC及Dubbo
1、什么是RPC
dubbo是⼀款⾼性能的rpc框架。什么是rpc呢?
rpc是⼀种协议:是⼀种远程过程调⽤(remote procudure call)协议
2、什么是dubbo
Apache Dubbo 是⼀款⾼性能、轻量级的开源服务框架。
Apache Dubbo |ˈdʌbəʊ| 提供了六⼤核⼼能⼒:⾯向接口代理的⾼性能RPC调⽤,智能容错和负载均衡,服务自动注册和发现,高度可扩展能⼒,运⾏期流量调度,可视化的服务治理与运维。
3、dubbo怎么实现远程通信
服务消费者去注册中⼼订阅到服务提供者的信息。然后通过dubbo进⾏远程调⽤。
4、快速开始
- 创建接口层项⽬
直接创建了⼀个项⽬。项⽬⾥有⼀个接口。接口中定义了⼀个服务的内容。
public interface SiteService {
String getName(String name);
}
- 创建服务提供者
- 创建⼀个服务提供者项⽬。引入依赖
<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-dubbo-demo</artifactId>
<groupId>com.dx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-demo-site-provider</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.8.0-alpha2</version>
</dependency>
<!--dubbo-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
<!--zk-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
</dependency>
<!--接⼝层-->
<dependency>
<groupId>com.dx</groupId>
<artifactId>dubbo-demo-site-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
- 编写具体的提供服务的实现类
import com.dx.api.SiteService;
public class SiteServiceImpl implements SiteService {
@Override
public String getName(String name) {
return "name:"+name;
}
}
- 编写bean配置⽂件,将dubbo和spring ioc整合,把服务提供到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://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="site-service"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:protocol name="dubbo" port="20881"/>
<bean id="siteService" class="com.dx.provider.service.impl.SiteServiceImpl"/>
<dubbo:service interface="com.dx.api.SiteService" ref="siteService"/>
</beans>
- 启动ioc容器,关联bean配置⽂件
public class Provider {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"provider.xml"});
context.start();
System.in.read();
}
}
- 创建服务消费者
- 引⼊依赖
<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-dubbo-demo</artifactId>
<groupId>com.dx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-demo-site-consumer</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.8.0-alpha2</version>
</dependency>
<dependency>
<groupId>com.dx</groupId>
<artifactId>dubbo-demo-site-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
<!--zk-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
</dependency>
</dependencies>
</project>
- 编写bean的配置⽂件
<?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://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="site-consumer"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:reference interface="com.dx.api.SiteService" id="siteService"/>
</beans>
- 启动消费者,调⽤服务提供者
package com.dx.site.consumer;
import com.dx.api.SiteService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Consumer {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"consumer.xml"});
context.start();
SiteService service = (SiteService)context.getBean("siteService");
String result = service.getName("hellodubbo");
System.out.println(result);
}
}
5、注解版
- 服务提供者
<dubbo:application name="site-service"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:protocol name="dubbo" port="20881"/>
<dubbo:annotation package="com.dx.provider.service.impl"/>
import com.dx.api.SiteService;
import com.alibaba.dubbo.config.annotation.Service;
@Service //使用dubbo提供的service注解,注册暴露服务
public class SiteServiceImpl implements SiteService {
@Override
public String getName(String name) {
return "name:"+name;
}
}
- 服务消费者
<dubbo:application name="site-consumer"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:annotation package="com.dx.dubbo.site.consumer.controller"/>
package com.dx.dubbo.site.consumer.controller;
import com.dx.api.SiteService;
import com.dx.entity.Site;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/site")
public class SiteController {
@Reference
private SiteService service;
@GetMapping("/get/{id}")
public Site getSiteById(@PathVariable Long id){
return service.getSiteById(id);
}
}
6、dubbo内部结构
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。
三、dubbo用法示例
1、version版本号
版本号⽤处是对于同⼀个接口,具有不同的服务实现。
- 服务提供者1
@Service(version = "default")
public class DefaultSiteServiceImpl implements SiteService {
@Override
public String siteName(String name) {
return "default:"+name;
}
}
- 服务提供者2
@Service(version = "async")
public class AsyncSiteServiceImpl implements SiteService {
@Override
public String siteName(String name) {
return "async:" + name;
}
}
- 服务消费者
@Reference(id = "siteService",version = "async")
private SiteService siteService;
2、指定protocol协议
dubbo框架可以对协议进⾏扩展,⽐如使⽤:
- rest
- http
- dubbo
- ⾃定义协议
在配置⽂件中配置协议:
# 应⽤名称
spring.application.name=my-dubbo-provider
# 应⽤服务 WEB 访问端⼝
server.port=8080
# Base packages to scan Dubbo Component:
@org.apache.dubbo.config.annotation.Service==>@EnableDubbo
dubbo.scan.base-packages=com.dx.my.dubbo.provider
dubbo.application.name=${spring.application.name}
## Dubbo Registry
dubbo.registry.address=zookeeper://127.0.0.1:2181
# Dubbo Protocol
#dubbo.protocol.name=dubbo
#dubbo.protocol.port=20880
# @Path
#dubbo.protocol.name=rest
#dubbo.protocol.port=8083
dubbo.protocols.protocol1.id=rest
dubbo.protocols.protocol1.name=rest
dubbo.protocols.protocol1.port=8090
dubbo.protocols.protocol1.host=0.0.0.0
dubbo.protocols.protocol2.id=dubbo1
dubbo.protocols.protocol2.name=dubbo
dubbo.protocols.protocol2.port=20882
dubbo.protocols.protocol2.host=0.0.0.0
dubbo.protocols.protocol3.id=dubbo2
dubbo.protocols.protocol3.name=dubbo
dubbo.protocols.protocol3.port=20883
dubbo.protocols.protocol3.host=0.0.0.0
在暴露服务时指明要使⽤的协议:
@Service(version = "default",protocol = "protocol2")
public class DefaultSiteServiceImpl implements SiteService {
@Override
public String siteName(String name) {
return "default:"+name;
}
}
3、使用rest访问dubbo的服务
- 服务提供者暴露⽤rest协议制定的服务
import com.dx.site.SiteService;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.rpc.protocol.rest.support.ContentType;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
@Service(version = "rest", protocol = "protocol1")
@Path("site")
public class RestSiteService implements SiteService {
@Override
@GET
@Path("name")
@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_PLAIN_UTF_8})
public String siteName(@QueryParam("name") String name) {
return "rest:" + name;
}
}
- 在浏览器中使⽤restful调⽤服务
http://localhost:8090/site/name?name=abc
4、消费者通过url直连指定的服务提供者
- 配置⽂件中声明三个dubbo协议
dubbo.protocols.protocol1.id=dubbo1
dubbo.protocols.protocol1.name=dubbo
dubbo.protocols.protocol1.port=20881
dubbo.protocols.protocol1.host=0.0.0.0
dubbo.protocols.protocol2.id=dubbo2
dubbo.protocols.protocol2.name=dubbo
dubbo.protocols.protocol2.port=20882
dubbo.protocols.protocol2.host=0.0.0.0
dubbo.protocols.protocol3.id=dubbo3
dubbo.protocols.protocol3.name=dubbo
dubbo.protocols.protocol3.port=20883
dubbo.protocols.protocol3.host=0.0.0.0
- 服务提供者暴露服务,未指定协议,则会暴露三个服务,每个协议对应⼀个服务
@Service(version = "default")
public class DefaultSiteServiceImpl implements SiteService {
@Override
public String siteName(String name) {
return "default:"+name;
}
}
- 消费者端通过url指定某⼀个服务
@Reference(id = "siteService",version = "default",url = "dubbo://127.0.0.1:20881/com.dx.site.SiteService:default")
private SiteService siteService;
5、服务超时
服务提供者和服务消费者都可以配置服务超时时间(默认时间为1秒):
- 服务提供者的超时时间:执行该服务的超时时间。如果超时,则会打印超时⽇志(warn),但服务会正常执行完。
@Service(version = "timeout", timeout = 4000)
public class TimeoutSiteServiceImpl implements SiteService {
@Override
public String siteName(String name) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("serving...");
return "timeout site service:"+name;
}
}
- 服务消费者的超时时间:从发起服务调用到收到服务响应的整个过程的时间。如果超时,则进⾏重试,重试失败抛异常
@EnableAutoConfiguration
public class TimeoutDubboConsumer {
@Reference(version = "timeout", timeout = 3000)
private SiteService siteService;
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(TimeoutDubboConsumer.class);
SiteService siteService = (SiteService)context.getBean(SiteService.class);
String name = siteService.siteName("face");
System.out.println(name);
}
}
6、集群容错
dubbo为集群调⽤提供了容错⽅案:
-
failover:(默认,推荐)当出现失败时,会进⾏重试,默认重试2次(不含第一次),⼀共三次调⽤。
-
failfast:只发起一次调用,失败立即报错。
-
failsafe:出现异常时,直接忽略。通常用于写入审计日志等操作。
-
failback:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
-
forking:并行调用多个服务器,只要一个成功即返回。
7、服务降级
服务消费者通过Mock指定服务超时后执行的策略:
@EnableAutoConfiguration
public class MockDubboConsumer {
@Reference(version = "timeout", timeout = 1000, mock = "fail:return timeout")
private SiteService siteService;
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(MockDubboConsumer.class);
SiteService siteService = (SiteService)context.getBean(SiteService.class);
String name = siteService.siteName("q-face");
System.out.println(name);
}
}
mock=force:return+null
表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。- 还可以改为
mock=fail:return+null
表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
8、本地存根
远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。
- 服务提供者的接口包下创建:
import com.dx.site.SiteService;
public class SiteServiceStub implements SiteService {
private final SiteService siteService;
public SiteServiceStub(SiteService siteService) {
this.siteService = siteService;
}
@Override
public String siteName(String name) {
try {
return siteService.siteName(name);
} catch (Exception e) {
return "stub:"+name;
}
}
}
- 服务消费者调⽤服务,开启本地存根
import com.dx.site.SiteService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
@EnableAutoConfiguration
public class StubDubboConsumer {
@Reference(version = "timeout", timeout = 1000, stub = "true")
private SiteService siteService;
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(StubDubboConsumer.class);
SiteService siteService = (SiteService)context.getBean(SiteService.class);
String name = siteService.siteName("q-face");
System.out.println(name);
}
}
9、参数回调
参数回调方式与调用本地 callback 或 listener 相同,只需要在 Spring 的配置文件中声明哪个参数是 callback 类型即可。Dubbo 将基于长连接生成反向代理,这样就可以从服务器端调用客户端逻辑。
简而⾔之,就是服务端可以调用客户端的逻辑。
- 接口层
public interface SiteService {
//同步调⽤⽅法
String siteName(String name);
//回调⽅法
default String siteName(String name, String key, SiteServiceListener siteServiceListener){
return null;
}
}
- 服务提供者
import com.dx.site.SiteService;
import com.dx.site.SiteServiceListener;
import org.apache.dubbo.config.annotation.Argument;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.annotation.Service;
@Service(version = "callback", methods = {@Method(name = "siteName", arguments = {@Argument(index = 2, callback = true)})}, callbacks = 3)
public class CallbackSiteServiceImpl implements SiteService {
@Override
public String siteName(String name) {
return null;
}
@Override
public String siteName(String name, String key, SiteServiceListener siteServiceListener) {
siteServiceListener.changed("provider data");
return "callback:"+name;
}
}
- 创建回调接口
public interface SiteServiceListener {
void changed(String data);
}
- 创建回调接口的实现类
import com.dx.site.SiteServiceListener;
import java.io.Serializable;
public class SiteServiceListenerImpl implements SiteServiceListener,
Serializable {
@Override
public void changed(String data) {
System.out.println("changed:" + data);
}
}
- 创建服务消费者
import com.dx.site.SiteService;
import com.dx.site.SiteServiceListenerImpl;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
@EnableAutoConfiguration
public class CallbackDubboConsumer {
@Reference(version = "callback")
private SiteService siteService;
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(CallbackDubboConsumer.class);
SiteService siteService = (SiteService)context.getBean(SiteService.class);
// key ⽬的是指明实现类在服务提供者和消费者之间保证是同⼀个
System.out.println(siteService.siteName("q-face", "c1", new SiteServiceListenerImpl()));
System.out.println(siteService.siteName("q-face", "c2", new SiteServiceListenerImpl()));
System.out.println(siteService.siteName("q-face", "c3", new SiteServiceListenerImpl()));
}
}
10、异步调用
从 2.7.0 开始,Dubbo 的所有异步编程接口开始以 CompletableFuture 为基础基于 NIO 的非阻塞实现并⾏调⽤,客户端不需要启动多线程即可完成并行调⽤多个远程服务,相对多线程开销较⼩。
简而⾔之,消费者通过异步调⽤,不⽤等待服务提供者返回结果就立即完成任务,待有结果后再执行之前设定好的监听逻辑。
- 接口层
import java.util.concurrent.CompletableFuture;
public interface SiteService {
//同步调⽤⽅法
String siteName(String name);
//回调⽅法
default String siteName(String name, String key,SiteServiceListener siteServiceListener){
return null;
}
//异步调⽤⽅法
default CompletableFuture<String> siteNameAsync(String name){
return null;
}
}
- 服务提供者
import com.dx.site.SiteService;
import org.apache.dubbo.config.annotation.Service;
import java.util.concurrent.CompletableFuture;
@Service(version = "async")
public class AsyncSiteServiceImpl implements SiteService {
@Override
public String siteName(String name) {
return "async:" + name;
}
@Override
public CompletableFuture<String> siteNameAsync(String name) {
System.out.println("异步调⽤:" + name);
return CompletableFuture.supplyAsync(() -> {
return siteName(name);
});
}
}
- 服务消费者
import com.dx.site.SiteService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.concurrent.CompletableFuture;
@EnableAutoConfiguration
public class AsyncDubboConsumer {
@Reference(version = "async")
private SiteService siteService;
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(AsyncDubboConsumer.class);
SiteService siteService = (SiteService)context.getBean(SiteService.class);
//调⽤异步⽅法
CompletableFuture<String> future =
siteService.siteNameAsync("q-face");
//设置监听,非阻塞
future.whenComplete((v, e) -> {
if (e != null) {
e.printStackTrace();
} else {
System.out.println("result:" + v);
}
});
System.out.println("异步调⽤结束");
}
}
四、dubbo的负载均衡策略
1、负载均衡策略
在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random
随机调用。
- 随机(默认的策略):random
- 轮询: roundrobin
- 最小活跃调用数:leastactive
- ⼀致性hash: consistenthash
2、dubbo中如何配置负载均衡策略
- 服务提供者:
@Service(version = "default",loadbalance = "roundrobin")
public class DefaultSiteServiceImpl implements SiteService {
@Override
public String siteName(String name) {
return "default:"+name;
}
}
- 服务消费者:如果两边都配置了负载均衡策略,则以消费者端为准。
@EnableAutoConfiguration
public class DefaultDubboConsumer {
@Reference(version = "default", loadbalance = "roundrobin")
private SiteService siteService;
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(DefaultDubboConsumer.class);
SiteService siteService = (SiteService)context.getBean(SiteService.class);
String name = siteService.siteName("q-face");
System.out.println(name);
}
}
五、安装Dubbo admin监管平台
1、zookeeper安装
下载解压,将conf下的zoo_sample.cfg复制一份改名为zoo.cfg,启动命令:./zkServer.sh start …/conf/zoo.cfg
2、dubbo安装
- 下载dubbo-admin
- 修改dubbo-admin配置:src\main\resources\application.properties 指定zookeeper地址
- 打包dubbo-admin:mvn clean package -Dmaven.test.skip=true
- 运行dubbo-admin:java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
3、访问
http://127.0.0.1:7001
默认使用root/root 登陆