SpringBoot 1x 系列之(十三)Spring Boot与分布式
Spring Boot与分布式
分布式、Dubbo/Zookeeper、Spring Boot/Cloud
分布式与微服务:
微服务和分布式的区别什么?有什么特点?微服务设计是为了不因为某个模块的升级和BUG影响现有的系统业务。微服务与分布式的细微差别是,微服务的应用不一定是分散在多个服务器上也可以是同一个服务器。分布式属于微服务,将模块拆分成一个独立的服务单元通过接口来实现数据的交互。分布式和微服的架构很相似,只是部署的方式不一样而已。
参考网站1:https://baijiahao.baidu.com/s?id=1693823577020291048&wfr=spider&for=pc
参考网站2:https://blog.csdn.net/qq_43842093/article/details/122612264
参考网站3:http://www.uml.org.cn/wfw/202009042.asp
1. 分布式应用
单体应用转为分布式应用的过程:
将单体应用拆分为多个功能模块,将每个功能模块部署在不同的机器上,对于访问量和访问频率较高的可以单独部署该功能模块到多个机器上。
单体应用转为分布式应用的问题:
1)远程过程调用(RPC):比如有两个功能模块,用户模块和订单模块,用户模块要用订单模块的数据,就会涉及到远程过程调用(RPC),远程过程调用以前是通过WebService解决,但现在,引入了新的框架,分布式服务框架(Dubbo/Spring Cloud),用于解决远程过程调用
2)注册中心:比如订单模块,访问量和访问频率很高,我们把它部署在多台机器上,那用户模块调用订单模块时,应该调用哪台机器上的订单模块呢,这个时候就需要引入注册中心,注册中心中维护了被调用模块的机器位置等,用户模块可以先访问注册中心,注册中心返回可调用的订单模块的机器位置等信息,这样用户模块就可以调用订单模块了。
2. Dubbo与Zookeeper
Dubbo:分布式服务框架
负责功能模块间的远程过程调用(RPC)
Zookeeper:注册中心
负责维护被调用功能模块(如订单模块)与机器位置的映射关系,方便调用模块(如用户模块)进行功能调用
2.1 Dubbo 体系结构
角色:
Container:服务容器
Provider:服务提供者
Registry:注册中心
Consumer:服务消费者
Monitor:监控中心
流程:
- start:服务容器启动时启动、加载和运行服务提供者。
- register:服务提供者启动时将自己能提供的服务信息注册到注册中心。
- subscribe:服务消费者在启动的时候从注册中心中订阅自己所需要的服务。
- notify:注册中心把服务消费者需要的服务的地址列表返回给服务消费者,服务如果有变更,注册中心会基于长链接的方式将变更推送给服务消费者,相当于服务消费者手持着一份实时更新的服务提供者名单。
- invoke:当服务消费者需要调用服务提供者的功能时,从服务提供者地址列表中基于负载均衡找到服务提供者的位置,调用该服务提供者的服务;如果调用失败,再从服务提供者地址列表中找另外一个服务提供者继续调用,直到调用成功。
- count:服务消费者和服务提供者定时向监控中心发送调用次数、调用时间等监控信息。
2.2 Docke安装Zookeeper
docker pull zookeeper:3.4.11
# 2181 为Zookeeper的客户端端口
docker run --name zk01 -p 2181:2181 --restart always -d 56d414270ae3
将Zookeeper作为注册中心,创建服务提供者和服务消费者,使用Dubbo进行整合
2.3 SpringBoot、Dubbo、Zookeeper整合
创建两个模块,一个作为服务提供者,一个作为服务消费者
Dubbo要做的事儿:将服务提供者注册到注册中心;服务消费者调用服务提供者服务的过程
2.3.1 编写服务提供者要提供的服务
Service
public interface TicketService {
public String getTicket();
}
ServiceImpl
public class TicketServiceImpl implements TicketService{
@Override
public String getTicket() {
return "《厉害了,我的国》";
}
}
2.3.2 将服务提供者注册到注册中心
1)引入Dubbo及Zookeeper的客户端依赖
<!--整合Dubbo-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
2)编写Dubbo的相关配置
# 应用名称
dubbo.application.name=provider-ticket
# 注册中心地址,Dubbo要把服务发布到注册中心
dubbo.registry.address=zookeeper://192.168.37.128:2181
# 指定要发布哪些服务
dubbo.scan.base-packages=com.atguigu.ticket.service
3)将服务发布出去
这里的@Service注解是Dubbo包下的
应用启动以后,Dubbo会按照dubbo.scan.base-packages
配置的包,扫描包下的内容,将所有标注了@Service服务按照配置的dubbo.registry.address
注册中心地址发布出去。
2.3.3 服务消费者从注册中心订阅服务
1)引入Dubbo及Zookeeper的客户端依赖
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
2)编写Dubbo的相关配置
# 应用名称
dubbo.application.name=consumer-user
# 注册中心地址
dubbo.registry.address=zookeeper://192.168.37.128:2181
3)完整复制一份服务提供者的服务源码到消费者包内,只保留接口
4)远程引用服务
发布的时候是按照接口全类名进行发布的,引用的时候就会按照TicketService
的全类名进行引用
3. Spring Boot与Spring Cloud
3.1 Spring Cloud与Dubbo的区别
Dubbo:分布式服务框架,主要解决服务间的远程过程调用问题
Spring Cloud:分布式的整体解决方案,在分布式系统中需要考虑的所有问题都有对应的解决方案
3.2 SpringCloud分布式开发五大常用组件(五大神兽)
1)服务发现——Netflix Eureka
将服务注册到注册中心
2)客服端负载均衡——Netflix Ribbon
服务间互联互调
3)断路器——Netflix Hystrix
在服务调用的长链路中,会出现中间服务出错的情况,造成用户等待时间特别长,引入断路器,在几次调用失败后可以快速返回相应给用户,避免用户一直等待。
4)服务网关——Netflix Zuul
服务调用前过滤请求
5)分布式配置——Spring Cloud Config
服务间的配置
3.3 整合SpringCloud
深度剖析服务发现组件Netflix Eureka:https://zhuanlan.zhihu.com/p/24829766/
3.3.1 使用Eureka作为注册中心
项目介绍:
一共有三个角色,服务消费者,服务提供者,注册中心,这里将Eureka作为注册中心。
服务提供者和服务消费者都是在注册中心中的,服务提供者是在注册中心中注册自己,服务消费者是从注册中心获取服务提供者(去注册中心发现服务)
服务消费者和服务提供者都要在注册中心注册(婚介所登记)
1)依赖情况
注册中心
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu</groupId>
<artifactId>eureka-server</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>1.5.9.RELEASE</version>
</parent>
<properties>
<spring-cloud.version>Edgware.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
服务提供者和服务消费者
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu</groupId>
<artifactId>consumer-users</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>1.5.9.RELEASE</version>
</parent>
<properties>
<spring-cloud.version>Edgware.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2)配置Eureka信息
server:
port: 8761
eureka:
instance:
hostname: eureka-server # Eureka实例的主机名
client: # Eureka客户端的信息
register-with-eureka: false # Eureka本身不在Eureka注册中心中注册,不做高可用的情况下置为false
fetch-registry: false # 不从Eureka中获取服务的注册信息
service-url: # 指定Eureka注册中心服务注册的地址,其他服务就是要在这注册
defaultZone: http://localhost:8761/eureka/
3)启用注册中心
//主配置类
@EnableEurekaServer //启用注册中心
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
Eureka注册中心启动后,访问本地的8761端口会来到Web管理页面
3.3.2 将服务提供者注册到服务中心【服务注册】
1)编写服务提供者提供的服务
TicketService
import org.springframework.stereotype.Service;
@Service
public class TicketService {
public String getTicket(){
return "《厉害了,我的国》";
}
}
Controller【Spring Cloud在整合微服务的时候是通过轻量级HTTP进行通信的,我们这里就是通过HTTP的方式暴露出去的】
@RestController
public class TicketController {
@Autowired
TicketService ticketService;
@GetMapping("/ticket")
public String getTicket(){
return ticketService.getTicket();
}
}
2)配置注册服务提供者到注册中心
server:
port: 8002 # 当前应用的运行端口
spring:
application:
name: provider-tickets # 服务提供者名字
eureka:
instance:
prefer-ip-address: true # 注册服务的时候使用IP进行注册
client:
service-url: # 注册中心的注册地址
defaultZone: http://localhost:8761/eureka/
3)测试启动
Eureka注册中心已经显示服务提供者注册了
4)将同一个服务提供者部署多个实例注册在注册中心中
修改应用的端口表示同一个服务提供者的多个实例
分别打包,然后在本地运行
可以看到,同一个服务提供者的多个实例也成功的注册到注册中心了
3.3.3 服务消费者发现并消费服务【服务发现与服务消费】
1)配置注册服务消费者到注册中心
server:
port: 8200
spring:
application:
name: consumer-users
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://localhost:8761/eureka/
2)配置服务消费者从注册中心中发现服务
//主配置类
@EnableDiscoveryClient //开启服务发现,从而获取到Eureka注册中心中的服务并进行调用
@SpringBootApplication
public class ConsumerUserApplication {
//RestTemplate:用于发送HTTP请求,通过发送HTTP请求调用服务
//@LoadBalanced:发送HTTP请求时启用负载均衡机制
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerUserApplication.class, args);
}
}
3)编写服务消费者消费服务
@RestController
public class UserController {
@Autowired
RestTemplate restTemplate;
/**
* 访问/buy时,通过restTemplate请求远程的http://PROVIDER-TICKETS/ticket获取请求的返回值
* @param name
* @return
*/
@GetMapping("/buy")
public String buyTicket(String name){
//restTemplate.getForObject("http://PROVIDER-TICKETS/ticket", String.class)
//第一个参数:请求的某一个服务提供者的服务URL,SpringCloud是通过HTTP暴露服务的,所以通过HTTP请求的方式请求即可
//第二个参数:将返回值转换为String
String s = restTemplate.getForObject("http://PROVIDER-TICKETS/ticket", String.class);
return name + "购买了" + s;
}
}
4)测试启动
服务消费者也注册到了注册中心
服务消费者消费服务也是没有问题的
并且服务消费者在请求服务提供者的服务时是启用负载均衡机制的
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术