分布式应用
分布式应用(distributed application)指的是应用程序分布在不同计算机上,通过网络来共同完成一项任务的工作方式。
为什么需要分布式:
- 单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。 - 垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。 - 分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。- 当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
在分布式系统中,国内常用zookeeper+dubbo
组合,而Spring Boot
推荐使用全栈的Spring
,Spring Boot
+Spring Cloud
。
Zookeeper和Dubbo
概述
ZooKeeper
ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
Dubbo
Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。
1、当服务启动得时候 容器(Container)就会启动一个Provider
2、将自身得服务发布到注册中心ZooKeeper
(ZooKeeper非常强大不止有注册中心这一种功能)
3、客户端订阅注册中心
4、客户端通过注册中心得知服务位置以后,调用远程服务
5、Monitor会监控整个流程。
整合springboot
我们创建两个项目,一个充当Provider,一个充当Consumer。
我们在Provider中编写服务,并且将服务注册到zookeeper中,Consumer订阅zookeeper,使用服务。
在pom文件中添加依赖
依赖在provider和consumer都要加入
|
比较简单的,我们可以直接使用dubbo的启动器和客户端即可实现
<!-- 导入dubbo与springboot整合启动器 --> |
添加Provider项目配置文件
#应用项目名 |
生产者Provider代码编写
@EnableDubbo
:
可以在指定的包名下(通过 dubbo.scan.base-packages
)扫描 Dubbo
的服务提供者(以 @Service
标注)以及 Dubbo 的服务消费者(以 Reference
标注)。@Service
:
表示服务的具体实现,被注解的类会被dubbo扫描
//路径为:com.zenshin.providerticket.service.TicketService |
//开启对dubbo支持 |
添加Consumer项目配置文件
#配置应用名 |
消费者Consumer代码编写
编写与分布式服务类相同的接口(不必实现),并保证包结构相同,可以直接把生产者包直接拷贝过来,只保留接口
这是简单使用,如果想要真正使用的话,直接把接口打包一下引用即可。
//路径为:com.zenshin.providerticket.service.TicketService,与生产者的接口保持一致 |
然后我们进行编写调用接口的类 UserService@Reference
可以定义在类中的一个字段、方法上,表示一个服务的引用。通常 @Reference 定义在一个字段上
|
我们在测试类中对消费者进行测试,注意在测试的时候,我们的生产者必须运行着,因为生产者是真正的功能提供者
|
运行后,我们就可以在控制台看到输出:买到票了《厉害了,我的国》
Spring Cloud
概述
Spring Cloud是一个分布式的整体解决方案。Spring Cloud为开发者提供了在分布式系统(配置管理、服务发现、熔断、路由、微代理、控制总线、一次性token,全局锁,leader选举、分布式session、集群状态)中快速构建的工具,使用Spring Cloud的开发者可以快速的启动服务或构建应用、同时能够快速和云平台资源进行对接。
- SpringCloud分布式开发五大常用组件
- 服务发现——Netflix Eureka
- 客户端负载均衡——Netflix Ribbon
- 断路器——Netflix Hystrix
- 服务网关——Netflix Zuul
- 分布式配置——Spring Cloud Config
入门尝鲜
SpringBoot后面更多的是整合案例,应该学习相应的知识结合使用,这里只是简单介绍,做一个小实例
1、首先我们创建一个功能,作为我们的注册中心——利用Eureka实现(使用spring初始化器选择springcloud eureka server模块)
2、创建一个服务提供者项目(选择eureka-client模块:用来服务注册)
3、创建一个服务消费者项目(选择eureka-client模块:用来调用服务)
Eureka注册中心
- pom依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> - 配置文件
server:
port: 8761
eureka:
instance:
hostname: eureka-server # eureka实例的主机名
client:
register-with-eureka: false # 不将自己注册到eureka上,不是高可用不需要
fetch-registry: false # 不从eureka上来获取服务的注册信息,因为这个本身就是注册中心,不需要获取
service-url:
defaultZone: http://localhost:8761/eureka/ # 注册中心服务注册的地址 - 需要在主程序入口添加一个注解
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
} - 浏览器访问http://localhost:8761/,可以看到界面化操作
服务注册
- pom依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--通过http暴露服务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> - 编写一个service层的TicketService类编写一个controller,将我们的服务暴露出来,因为SpringCloud在整合微服务的时候,是通过http来进行通信的,所以我们需要编写一个controller
public class TicketService {
public String getTicket()
{
return "《厉害了,我的国》";
}
}
public class TicketController {
TicketService ticketService;
"/ticket") (
public String getTicket()
{
return ticketService.getTicket();
}
} - 生产者配置运行起来以后,我们就会发现,在eureka上注册了一个实例
server:
port: 8001
spring:
application:
name: provider-ticket
eureka:
instance:
prefer-ip-address: true #注册服务的时候使用ip进行注册
client:
service-url:
defaultZone: http://localhost:8761/eureka/ # 注册中心服务注册的地址
我们来来注册多个应用:
修改不同的端口,利用maven的打包工具打成一个包,然后多次启动,将服务注册到eureka中
消费者
消费者的pom文件与生产者相同
- 配置文件
spring:
application:
name: consumer-user
server:
port: 8200
eureka:
instance:
prefer-ip-address: true #注册服务的时候使用ip进行注册
client:
service-url:
defaultZone: http://localhost:8761/eureka/ # 注册中心服务注册的地址 - 程序主入口加入注解往容器中注入一个
//开启发现服务功能
public class ConsumerUserApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerUserApplication.class, args);
}
//发送请求的时候加上负载均衡机制
public RestTemplate restTemplate()
{
return new RestTemplate();
}
}RestTemplate
类,这个类用发送Rest请求,@LoadBalanced
开启负载均衡,如果创建不同端口的provider应用,则访问会被均衡到各个应用,@EnableDiscoveryClient
开启发现服务 - 编写一个controller运行以后我们可以往浏览器中输入:
public class UserController {
RestTemplate restTemplate;
"/buy") (
public String buyTicker(String name)
{
String template = restTemplate.getForObject("http://PROVIDER-TICKET/ticket", String.class);//发送服务的url写容器名字就可以。
return name+"购买了"+template;
}
}http://localhost:8200/buy?name=zhangsan
发请求,则会响应
浏览器中会出现如下结果:
zhangsan购买了《厉害了,我的国》
我们可以看一下启动的两个生产者的控制台,都会有调用,因为开启的负载均衡。
这里是只是简单的尝试,更多的可以在Springcloud中进行学习