SpringBoot 从入门到光头 —— 第十六章 SpringBoot 与分布式
1. 分布式应用
在分布式系统中,国内常用 Zookeeper + Dubbo 组合,而 SpringBoot 则推荐使用全栈的 SpringCloud,也就是 SpringBoot + SpringCloud
分布式子系统:
单一应用架构:
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
垂直应用架构:
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的 Web 框架(MVC)是关键。
分布式服务架构:
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
流动计算架构:
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
2. Zookeeper 和 Dubbo
Zookeeper(注册中心)
Zookeeper 是一个分布式的,开放源码的分布式应用程序协调服务。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
Dubbo(分布式服务框架)
Dubbo 是 Alibaba 开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦(或者最大限度地松耦合),从服务模型的角度来看,Dubbo 采用的是种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider) 和服务消费方(Consumer)两个角色。
Dubbo 架构:
使用步骤:
- 将服务提供者注册到注册中心中
- 引入 Dubbo 和 Zookeeper 相关依赖
- 配置 Dubbo 的扫描包和注册中心地址
- 使用
@Service
(Dubbo 3.0 之后使用@DubboService
)发布服务 - Dubbo 3.0 以后的版本需要在 SpringBoot 引导类上加上
@EnableDubbo
才能启用 Dubbo 服务
- 将消费者注册到注册中心中
- 引入 Dubbo 和 Zookeeper 相关依赖
- 配置 Dubbo 的注册中心地址
- 使用
@Reference
(Dubbo 3.0 之后使用@DubboReferecce
)引用服务
3. SpringBoot 和 SpringCloud
3.1. SpringCloud
SpringCloud 是一个分布式的整体解决方案。SpringCloud 为开发者提供了 在分布式系统(配置管理,服务发现,熔断,路由,微代理,控制总线,一次性 Token,全局锁,Leader 选举,分布式 Session,集群状态)中快速构建的工具 ,使用 SpringCloud 的开发者可以快速地启动服务或者是构建应用、同时能够快速和云平台资源进行对接
SpringCloud 分布式开发五大常用组件:
- 服务发现:NetflixEureka
- 服务器负载均衡:NetflixRibbon
- 断路器:NetflixHystrix
- 服务网关:NetflixZuul
- 分布式配置:SpringCloudConfig
3.2. SpringCloud Eureka 注册中心使用
注册中心的使用方法:
引入 Eureka 注册中心依赖
pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
编写配置文件
application.yaml
,配置 Eureka 信息
application.yaml
server: port: 8761 eureka: instance: hostname: eureka-server # Eureka instance hostname client: register-with-eureka: false # Don't register itself with Eureka fetch-registry: false # Do not get service registration information from Eureka service-url: defaultZone: http://127.0.0.1:8761/eureka/
在引导类中使用
@EnableEureka
启用 Eureka 注册中心
com.yourname.eurekaserver.EurekaServerApplication
/** * Registration Center * @author gregperlinli */ @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
启动后打开浏览器输入地址
http://127.0.0.1:8761
(端口号可以在配置文件中设置)即可进入 Eureka 注册中心管理页面
3.3. SpringCloud 服务注册
SpringCloud 注册服务方法
引入相关依赖
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
编写服务注册配置
application.yaml
server: port: 8001 spring: application: name: provider-ticket eureka: instance: prefer-ip-address: true # Use the IP address of the service when registering the server client: service-url: defaultZone: http://127.0.0.1:8761/eureka/
编写要注册的服务
com.yourname.ticket.service.TicketService
/** * @author gregPerlinLi * @since 2022-01-21 */ public interface TicketService { /** * Get ticket * * @return ticket */ String getTicket(); }
com.yourname.ticket.service.impl.TicketServiceImpl
/** * @author gregPerlinLi * @since 2022-01-21 */ @Service public class TicketServiceImpl implements TicketService { @Override public String getTicket() { System.out.println("8001"); return "This is an ticket"; } }
编写 Controller 暴露接口
com.yourname.ticket.controller.TicketController
/** * @author gregPerlinLi * @since 2022-01-21 */ @RestController public class TicketController { @Autowired TicketService ticketService; @GetMapping(value = "/ticket") public String getTicket() { return ticketService.getTicket(); } }
3.4. SpringCloud 服务发现 & 消费
SpringCloud 发现服务并消费的方法:
引入相关依赖
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
编写服务发现配置
application.yaml
spring: application: name: consumer-user server: port: 8200 eureka: instance: prefer-ip-address: true # Use the IP address of the service when registering the server client: service-url: defaultZone: http://127.0.0.1:8761/eureka/
使用
@EnableDiscoveryClient
启用发现服务功能,并使用RestTemplate
发送 HTTP 请求(通过@LoadBalance
可以实现负载均衡)
com.yourname.user.ConsumerUserApplication
/** * {@code @EnabledDiscoveryClient}: Enable service discovery function * * @author gregperlinli */ @SpringBootApplication @EnableDiscoveryClient public class ConsumerUserApplication { public static void main(String[] args) { SpringApplication.run(ConsumerUserApplication.class, args); } /** * {@code @LoadBalanced}: Enable load balancing */ @LoadBalanced @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
编写 Controller 调用远程服务
com.yourname.user.controller.UserController
/** * @author gregPerlinLi * @since 2022-01-21 */ @RestController public class UserController { @Autowired RestTemplate restTemplate; @GetMapping(value = "buy") public String buyTicket(String name) { return name + " bought ticket: " + restTemplate.getForObject("http://PROVIDER-TICKET/ticket", String.class); } }