Swagger、分布式架构部分
- 11、Swagger
- 11.1、Swagger简介
- 11.2、SpringBoot集成Swagger
- 11.3、配置Swagger
- 11.4、Swagger配置扫描接口
- 12、任务
- 12.1、异步任务
- 12.2、定时任务
- 12.3、邮件任务
- 13、分布式Dubbo + ZooKeeper + SpringBoot
- 13.1、分布式理论
- 13.2、RPC
- 13.3、Dubbo
- 13.4、安装ZooKeeper
- 13.5、安装Dubbo
- 13.6、安装测试Dubbo-admin
- 13.7、集中整合
11、Swagger
学习目标:
- 了解Swagger的作用
- 了解前后端分离
- 在SpringBoot中集成Swagger
11.1、Swagger简介
Swagger的作用
前后端分离:Vue + SpringBoot
前后端分离时代:
- 后端:后端控制层,服务层,数据访问层【后端团队】
- 前端:前端控制层,视图层【前端团队】
- 伪造后端数据,json。
- 前后端通过API接口进行交互
- 前后端相对独立,松耦合
- 前后端甚至可以部署在不同的服务器上
Swagger
- 号称世界上最流行的API框架
- RestFul API文档在线自动生成工具,API文档与API定义同不跟新
- 直接运行,可以在线测试API接口
- 支持多种语言(Java,PHP)
11.2、SpringBoot集成Swagger
让SpringBoot于Swagger结合在一起
在项目中使用Swagger需要相应的依赖
- springfox-swagger2
- springfox-swagger-ui
具体步骤:
1、新建一个含web的springboot项目
2、导入两个相关的依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
3、编写swagger2对应的配置类
package pers.mobian.config;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2//开启Swagger2
public class SwaggerConfig {
}
4、运行测试
访问路径为:http://localhost:8080/swagger-ui.html
11.3、配置Swagger
修改Swagger主界面显示的信息
编写配置类SwaggerConfig:
package pers.mobian.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
@Configuration
@EnableSwagger2//开启Swagger2
public class SwaggerConfig {
//配置了Swagger的Docket的bean实例
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}
//配置Swagger信息
private ApiInfo apiInfo(){
//作者信息
Contact contact = new Contact("默辨", "https://www.baidu.com", "[email protected]");
return new ApiInfo(
"默辨的Swagger",
"配置Swagger信息",
"1.6",
"https://www.baidu.com",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList()
);
}
}
配置信息来源于源码:
执行结果:
11.4、Swagger配置扫描接口
配置Swagger的信息
1、配置Swwagger,实例Docket.select()
//配置了Swagger的Docket的bean实例
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//RequestHandlerSelectors:配置要扫描接口的方式
//basePackage:指定要扫描的包
//any():扫描全部
//none() 不扫描
//withClassAnnotation:扫描类上的注解,参数是一个注解的反射对象
//withMethodAnnotation:扫描方法上的注解
.apis(RequestHandlerSelectors.basePackage("pers.mobian.controller"))
//paths():过滤什么路径
.paths(PathSelectors.ant("/mobian/**"))
.build();
}
2、配置Swagger的启动
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(false)//配置Swagger是否被启用,false为关闭
.select()
.apis(RequestHandlerSelectors.basePackage("pers.mobian.controller"))
.paths(PathSelectors.ant("/mobian/**"))
.build();
}
不启动以后效果图
问题:如何才能让我的swagger在生产环境中使用,在发布的时候不使用?
- 判断是不是生产环境
- 注入对应的enable(flag)
@Bean
public Docket docket(Environment environment) {
//设置要显示的swagger环境
Profiles profiles = Profiles.of("dev", "test");
//通过environment.acceptsProfiles判断是否处在自己设定的环境当中
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(flag)//配置Swagger是否被启用,false为关闭
.select()
.apis(RequestHandlerSelectors.basePackage("pers.mobian.controller"))
.paths(PathSelectors.ant("/mobian/**"))
.build();
}
3、配置API文档的分组
.groudName("默辨")
配置多个分组,只需要多个实例地Docket就行了
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("默辨1");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("默辨2");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2).groupName("默辨3");
}
4、配置测试的注释
实体类配置:
package pers.mobian.pojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//@APi(注释)
@ApiModel("用户实体类")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("密码")
private int age;
}
效果:
配置控制器类信息:
package pers.mobian.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import pers.mobian.pojo.User;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String helloTest() {
return "hello";
}
//只需要我们的接口。返回值中存在实体类,它就会被扫描到swagger中
@PostMapping(value = "/user")
public User user(){
return new User();
}
//Operation接口,不是放在类上,而是放在方法上
@ApiOperation("Hello控制器类")
@GetMapping(value = "/hello2")
public String hello2(@ApiParam("用户名") String username){
return "hello"+username;
}
@ApiOperation("Post测试类")
@PostMapping(value = "/post")
public User post(@ApiParam("用户名") User user){
int i=5/0;
return user;
}
}
效果:
@ApiModelProperty("密码") //给变量注释
@ApiModel("用户实体类") //给实体类注释
@ApiOperation("Hello控制器类") //给方法注释
@ApiParam("用户名") //给参数注释
Swagger好处总结:
- 我们可以通过Swagger给一些比较难以理解的属性或者接口添加注释信息
- 前后端的接口文档能够实时跟新,避免前后端信息不一致的情况
- 可以在对应的请求下进行在线测试
注意:在正式发布的时候,需要关闭Swagger
12、任务
12.1、异步任务
1、在servic层e新建一个异步服务
package pers.mobian.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsynService {
@Async
public void hello() throws InterruptedException {
Thread.sleep(3000);
System.out.println("数据正在处理中");
}
}
2、在controller层建立对应的映射
package pers.mobian.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import pers.mobian.service.AsynService;
@RestController
public class HelloController {
@Autowired
AsynService asynService;
@RequestMapping("/hello")
public String AsynController() throws InterruptedException {
asynService.hello();
return "OK";
}
}
3、修改SpringBoot的启动器类
package pers.mobian;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync
@SpringBootApplication
public class Springboot09PostApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot09PostApplication.class, args);
}
}
总结:在service层的服务和启动器类没有添加@EnableAsync
注解时,当访问/hello时,客户端会提前打印输出,服务器端在三秒后再进行显示相关信息。
12.2、定时任务
核心类:
TaskScheduler //任务调度者
TaskExecutor //任务执行者
@EnableScheduling //开启定时功能的注解
@Scheduled(cron = "") //什么时候执行
测试案例:
1、修改核心配置文件,添加
package pers.mobian;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
@SpringBootApplication
public class Springboot09PostApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot09PostApplication.class, args);
}
}
2、在service层新建ScheduledService类
package pers.mobian.service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class ScheduledService {
//在一个特定的时间执行这个方法
//cron 表达式
//秒 分 时 日 月 周几
@Scheduled(cron = "35 42 17 * * ? ")
public void hello(){
System.out.println("hello 被执行了");
}
}
3、在17时45分35秒,该方法被执行
补充cron表达式:(秒 分 时 日 月 周几)
域名 | 可取值 | 可取符号(仅列部分常用) |
秒域 | 0~59的整数 | * - , / |
分域 | 0~59的整数 | * - , / |
时域 | 0~23的整数 | * - , / |
日域 | 1~31的整数 | * - , / ? L |
月域 | 1-12的整数或JAN~DEC | * - , / |
周域 | 1-7的整数或SUN~SAT | * - , / ? L # |
年域 | 1970~2099的整数 | * - , / |
意义 | 表达式 |
每隔5秒钟执行一次 | */5 * * * * ? |
每隔1分钟执行一次 | 0 */1 * * * ? |
每天1点执行一次 | 0 0 1 * * ? |
每天23点55分执行一次 | 0 55 23 * * ? |
每月最后一天23点执行一次 | 0 0 23 L * ? |
每周六8点执行一次 | 0 0 8 ? * L |
每月最后一个周五,每隔2小时执行一次 | 0 0 */2 ? * 6L |
每月的第三个星期五上午10:15执行一次 | 0 15 10 ? * 5#3 |
在每天下午2点到下午2:05期间的每1分钟执行 | 0 0-5 14 * * ? |
表示周一到周五每天上午10:15执行 | 0 15 10 ? * 2-6 |
每个月的最后一个星期五上午10:15执行 | 0 15 10 ? * 6L |
每天上午10点,下午2点,4点执行一次 | 0 0 10,14,16 * * ? |
朝九晚五工作时间内每半小时执行一次 | 0 0/30 9-17 * * ? |
每个星期三中午12点执行一次 | 0 0 12 ? * 4 |
每年三月的星期三的下午2:10和2:44各执行一次 | 0 10,44 14 ? 3 4 |
每月的第三个星期五上午10:15执行一次 | 0 15 10 ? * 6#3 |
每月一日凌晨2点30执行一次 | 0 30 2 1 * ? |
每分钟的第10秒与第20秒都会执行 | 10,20 * * * * ? |
每月的第2个星期的周5,凌晨执行 | 0 0 0 ? * 6#2 |
12.3、邮件任务
1、在自己的邮件中开启对应的服务
2、引入邮件发送需要的maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
3、在核心配置文件中,进行对应的修改
[email protected]
spring.mail.password=utftyvglqmqebfbc
spring.mail.host=smtp.qq.com
#开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true
4、在测试类中进行测试(内含两个邮件发送的测试)
package pers.mobian;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
@SpringBootTest
class Springboot09PostApplicationTests {
@Autowired
JavaMailSenderImpl mailSender;
@Test
void contextLoads() {
//一个简单的邮件
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setSubject("默辨你好呀");
mailMessage.setText("我是正文内容");
mailMessage.setTo("[email protected]");
mailMessage.setFrom("[email protected]");
mailSender.send(mailMessage);
}
@Test
void contextLoad2() throws MessagingException {
//复杂的邮件
MimeMessage mimeMessage = mailSender.createMimeMessage();
//组装
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
//正文
helper.setSubject("默辨你好呀");
helper.setText("<h1>我是正文内容</h1>",true);
//附件
helper.addAttachment("1.jpg",new File("F:\\Users\\Mrpan\\Desktop\\1.jpg"));
helper.setTo("[email protected]");
helper.setFrom("[email protected]");
mailSender.send(mimeMessage);
}
}
5、测试结果
13、分布式Dubbo + ZooKeeper + SpringBoot
13.1、分布式理论
什么是分布式系统?
在《分布式系统原理与规范》书中有如下定义:“分布式系统是入肝独立计算机的集合,这些计算机对于用户来水就像单个相关系统”
分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。
分布式系统(distributed system)是建立在网络之上的软件系统。
首先需要明确的是,只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升(加内存、加磁盘、使用更好的CPU)高昂到得不偿失的时候,应用程序也不能进一步优化的时候,我们菜需要考虑分布式系统。因为,分布式下同要解决的问问题本身就是和单机系统一样的,而由于分布式系统多节点、通过网络通信的拓扑结构,会引入很多单机系统没有的问题,为了解决这些问题优惠引入更多的机制、协议,带来更多的问题。。。
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构及流计算架构势在必行,急需一个治理系统确保架构有条不紊的演进。
单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,提升效率的方法之一是将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
13.2、RPC
什么是RPC?
RPC(Remote Procedure Call)指远程过程调用,是一种进程间的通信方式,它不是一种技术思想,而是一种规范。它允许程序嗲用另一个地址空间(通常是共享网络的另一台机器上)的过程函数,而不是程序员显示编程这个远程调用的细节。即程序员无论是调用本地的还是远程的函数。本质上编写的调用代码基本相同。
也就是两台服务器A和B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不饿能直接调用,需要通过网络来表达调用的语义和传达调用的数据。为什么要用RPC呢?就是无法在一个进程内,甚至一个计算机内通过本地调用的方式完成的需求,不如不同的系统间的通讯,甚至不同的组织间的通讯,由于计算能力需要横向扩展,需要在多台机器组成的集群上部署应用。RPC就是要香调用本地的函数一样去调用远程函数。
RPC基本原理
RPC两个核心模块:通讯和序列化(方便数据传输。数据传输时,发送的一方需要序列化,接收方再反序列化)
13.3、Dubbo
什么是dubbo?
Apache Dubbo是一款高性能、轻量级的开源Java PRC框架,它提供了三个核心能力:面向接口的远程方法调用,只能容错和负载均衡,以及服务自动注册和发现
服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需要的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用
注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
13.4、安装ZooKeeper
下载地址:https://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.14/
1、解压文件
2、在bin目录下双击文件
3、程序会闪退,于是对文件进行修改,添加一个pause(打印闪退的信息)
4、再次双击
5、在conf路径下新建zoo_sample.cfg文件的副本,并且将文件名字修改为zoo.cfg即可
6、点击zoo.cfg即可查看zookeeper的对应端口号为2181
7、再次双击zkServer.cmd文件,此时连接成功
8、同时打开客户端和服务端
9、输入相关的执行语句
13.5、安装Dubbo
下载网址:https://github.com/apache/dubbo-admin/tree/master
1、解压文件
13.6、安装测试Dubbo-admin
1、查看对应目录下的配置文件的配置信息,将其与ZooKeeper的端口进行绑定
2、在E:\dubbo\dubbo-admin-master路径下使用cmd执行mvn clean package -Dmaven.test.skip=true
,系统会帮我们进行编译
3、编译成功后,在对应的目录下会生成对应的jar包
4、在ZooKeeper中开启服务后,运行生成的dubbo-admin.jar文件
5、在成功运行后,访问端口地址:http://localhost:7001/
用户名和密码都是:root
6、登录成功界面
总结:
dubbo-admin:类似于一个监管后台的网站,可以查看我们注册了哪些服务,以及哪些服务被消费。(非必要)
zookeeper:类似于一个注册中心(必要的)
dubbo:只是一个jar包
13.7、集中整合
1、新建两个不同的项目:consumer-server(消费者)和provider-server(提供者)
2、在两个项目中导入相关的依赖
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
<exclusions>
<!--怕出现日志冲突,所以关闭这个日志功能-->
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
3、在提供者的项目中的service层下,新建一个TicketService接口类
package pers.mobian.service;
public interface TicketService {
public String getTicket();
}
4、在同级目录下新建TicketService接口类的实现类
package pers.mobian.service;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
@Service //需要使用的是dubbo的service注解
@Component
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "2020东京奥运会门票 ";
}
}
5、修改核心提供者的配置文件
server.port=8001
#注册应用的名字
dubbo.application.name=provider-server
#注册中心的地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
#哪些服务被注册
dubbo.scan.base-packages=pers.mobian.service
6、运行zookeeper服务端,并且运行dubbo-admin-0.0.1-SNAPSHOT.jar文件,开启后台(此截图为成功部署后的最终截图)
7、运行我们的提供者项目,成功开启服务后,我们可以通过访问http://localhost:7001在后台查看执行效果以及对应的服务的详细信息。
8、编写我们的消费者。在service层下新建一个UserService的消费类
package pers.mobian.service;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
@Service//放入spring容器中
public class UserService {
//想要拿到provider-server提供的门票,我们需要去注册中心拿
@Reference//引用的方式有两种。 方式一:使用pom坐标 方式二:可以定义路径相同的接口名
TicketService ticketService;
public void buyTicket() {
String ticket = ticketService.getTicket();
System.out.println("在注册中心拿到了=>" + ticket);
}
}
9、由于我是使用的方式二拿取服务,所以在service层下新建一个与提供者相同的接口类
package pers.mobian.service;
public interface TicketService {
public String getTicket();
}
10、在消费者的核心配置文件中进行对应的配置
#新建自己的端口,提供者的端口改成了8001。只是为了区别这是两个不同的服务
server.port=8002
#将自己的程序名字注册到dubbo中
dubbo.application.name=consumer-server
#连接dubbo时,访问的端口号
dubbo.registry.address=zookeeper://127.0.0.1:2181
11、编写测试类
package pers.mobian;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import pers.mobian.service.UserService;
@SpringBootTest
class ConsumerServerApplicationTests {
@Autowired
UserService userService;
@Test
void contextLoads() {
userService.buyTicket();
}
}
12、开启消费者类的服务
13、测试类执行结果
14、在对应的后台中可以查看到对应的服务
15、至此,一个springboot + zookeeper + dubbo的项目搭建完成
提供者将自己的服务开启后,将自己的服务按照核心配置文件的设置,放到注册中心;消费者开启自己的服务后,依然根据核心配置文件的设置,去注册中心拿到自己需要的服务。至此远程间的通信完成。
总结:在整个的服务的搭建过程中。zookeeper就像一个连接性质的服务,可以帮助我们将不同的服务进行连接,在实现分布式的过程中,这是十分必要的;对于dubbo-admin,它就像一个后台的管理系统,可以帮助我们更加清楚的掌握每个进程开启以后的实时动态,但它本身只是一个监控的作用,非必要;至于我们新建的消费者和提供者,它们能够在zookeeper的带领下实现远程通信,如果这是两个不同服务器上的不同程序,就可以实现分布式系统。