SpringCloud
本博客参照了韩顺平老师的 Sping Cloud 课程讲义!
1 Spring Cloud 基本介绍
1.1 官方文档
1.1.1
地址**: https://spring.io/projects/spring-cloud**
1.2 微服务引出
1.没有微服务技术**,是不是程序员就不能开发大型项目?**
是可以的, 对大型项目进行模块划分,对各个模块进行实现, 模块之间更多的是以API调用完成,耦合度较高, 不利于扩展和维护。
2.标准的微服务解决方案(springcloud 和cloud alibaba)出现原因和价值是什么?
(1) **微服务可以根据业务不同,将一个大项目 , 分解成不同的服务(微服务,比如搜 索服务/网关服务/配置服务/存储服务/发现服务等等) **
(2)各个服务通过分布式方式进行工 作,从而可以高效,快速,稳定的完成复杂的功能
(3) 如果小伙伴还不理解, 你也可以理解成就 将原来大项目的某些模块->抽出形成微服务->配合分布式工作方式->从而高效,快速,稳定的完成复杂业务功能。
3. 一图胜千言
1.3 系统架构的演变过程
1.3.1单体架构:
仅适合少量用户的情况
如果用户量大,server无法响应大量请求;大量操作数据库的语句冲垮DB
1.3.2动静分离架构:
静态缓存+文件存储
动静分离:
1.对静态资源、动态资源的请求进行分离过滤,对于静态资源的请求,直接找资源服务器响应;对于动态服务器的请求才找到应用服务器进行响应。
2.对请求的数据进行缓存,使用redis等,降低数据库等负荷。
1.3.3分布式架构:
业务拆分+负载均衡
1.3.4微服务架构:
使用Spring Cloud
“微服务” 一词源于 Martin Fowler 的名为Microservices 的博文,简单地说, 微服 务是系统架构上的一种设计风格,它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间通过基于HTTP 的 RESTful API 进行通信协作。
被拆分成的每一个小型服务都国绕着系统中的某一项或一些耦合度较高的业务功能进行构建, 并且每个服务都维护着自身的数据存储、业务开发、自动化测试案例以及独立部署机制。 由于有轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写,这里我们使用 java。
1.4 Spring Colud全面说明
1.Springcloud 来源于 Spring,是更高层次的、 架构视角的综合性大型项目, 目标旨在构建一套标准化的微服务解决方案,让架构师在使用微服务理念构建系统的时, 面对各环节的问题都可以找到相应的组件来处理
2.Spring Cloud 是Spring 社区为微服务架构提供的一个 “全家桶” 套餐。套餐中各个组件之间的配合,可以减少在组件的选型和整合上花费的精力,可以快速构建起基础的微服务架构系统,是微服务架构的最佳落地方案
3.Spirng Cloud 天然支持 spring Boot(有版本对应要求),使用门槛较低
4.解决与分布式系统相关的复杂性 一网络问题,延迟开销,带宽向题,安全问题
5.处理服务发现的能力 一 服务发现允许集群中的进程和服务找到彼此并进行通信
6.解決冗余问题 一 元余问题经常发生在分布式系统中
7.解决负载均衡 一 改进跨多个计算资源(例如计算机集群,网络链接,中央处理单元)的工作负载分布
1.5 Spring Cloud 核心组件图
1.5.1 文档 : https://spring.io/projects/spring-cloud
1.5.2一图胜千言
1.6 Spring Cloud 分布式示意图
1.6.1 文档 : https://spring.io/microservices
1.6.2 一图胜千言
Spring cloud 是微服务的落地
Spring cloud 体现了微服务的弹性设计
微服务的工作方式一般是基于分布式的。
Spring Cloud 仍然是 Spring 家族一员,可以解决微服务的分布式工作方式带来的各种问题
Spring Cloud 提供很多组件,比如 服务发现,负载均街,链路中断,分布式追踪和监控,甚至提供 API gateway 功能.
1.6.3 SpringCloud和SpringBoot版本对应关系
1.7 Spring Cloud 组件选型
2 Spring Cloud Alibaba 基本介绍
2.1 官方文档
2.1.1 英文地址**: https://github.com/alibaba/spring-cloud-alibaba**
2.1.2英 文 地 址 : 中 文 文 档 : https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
2.2 SpringCloudAlibaba是什么
2.3 主要功能一览
2.4 Spring Cloud Alibaba 核心组件
2.5: 分布式微服务技术选型
•Spring Cloud 原生组件的几大痛点
1.Spring Cloud 部分组件停止维护和更新,给开发带来不便
2.Spring cioud 部分环境搭建复杂,没有完善的可视化界面,我们需要大量的二次开发和定制
3.Spring Cloud 配置复杂,难以上手
•Spring Cloud Alibaba 的优势
- 阿里使用过的组件经历了考验(高并发,高性能,高可用,性能强悍,设计合理,现在开源
出来供大家使用。
- 搭配完善的可视化界面,给开发运维带来极大的便利搭建简单,学习曲线低。
以Spring Cloud Alibaba为主,以Spring Cloud 原生组件为辅。
3 微服务基础环境搭建
3.1 创建父工程 ,用于聚合其它微服务模块
3.1.1 需求说明**/**图解
3.1.2 实现步骤
3.1.2.1 创建父项目, 作为聚合其它微服务模块
###我们先创建一个父项目**,** 该父项目会去管理多个微服务模块(module)
Maven创建项目 使用webapp Maven工件
3.1.2.2 项目设置
3.父项目本身不写代码,是用来进行管理的
3.1.2.4 配置父工程 pom.xml, 作为聚合其它模块
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
3.1.3 注意事项和细节
3.1.3.1 Maven的dependencyManagement说明
1、Maven 使用 dependencyManagement 元素来提供了一种管理依赖版本号的方式。通常在项目
packaging 为 POM,中使用dependencvManadement 元素。
2、使用pom.xml 中的dependencyManagement 元素能让所有在子项目中引用一个依赖, Maven 会沿着父子层次向上走,直到找到一个拥有dependencyManagement 元素的项目,然后它就会使用这个dependencyManagement 元素中指定的版本号。
3、好处:如果有多个子项目都号1用同一样依赖,则可以避免在每个使用的子项目里都声明一个版本号,当开级或切换到另一个版本时,只需要在顶层父容器里更新,而不需要分别在子项目的修改;另外如果某个子项目需要另外的一个版本,只需要声明version 就可。
4、dependency Management 里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。
5、如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version 和 scope 都读取自父 pom
6、如果子项目中指定了版本号,那么会使用子项目中指定的 jar 版本
3.2 创建会员中心微服务模块 -service provider
3.2.1 需求说明
1、通过浏览器可以获取会员信息**(通过会员中心微服务模块)**
3.2.2 思路分析
1、创建 Moduel & 完成配置
2、创建数据库/表
3、创建 entity-dao/Mapper.xml-service-controller
4、完成测试
3.2.3 实现步骤
application.yml:
1 | server: |
MemberMapper.xml
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
3.2.4 🌟注意事项和细节
传输javabean时
1、我们的前端如果是以 json 格式来发送添加信息Member,那么我们需要使用@RequestBody,
才能将数据封裝到对应的 bean,同时保证 http 的请求头的 content-type 是对应的
2、如果前端是以 表单 或者 parameters 形式提交, 则一定不能使用@RequestBody, 才
会进行对象参数封装,同时保证http 的请求头的 content-type 是对应
3、在进行 SpringBoot 应用程序测试时,引入的 jUnit 是ore.junit.jupiter.api.Test
4、 在运行程序时,一定要确保你的 XxxxMapper.xml 文件被自动放到的 target 目录的
classes 指定目录。
3.3 创建使用会员微服务模块 -service consumer
3.3.1 需求说明**/**图解
-浏览器: http://localhost/member/consumer/get/1
-测试添加会员 : http://localhost/member/consumer/save
3.3.2 思路分析**/**图解
1、创建 Moduel(member-service-consumer-80) & 完成配罝
2、创建 controller
3、完成测试
3.3.3 实现步骤
3.3.3.1 创建 Moduel & 完成配置
创建Moduel:
在创建Moduel后,其父工程的 pom.xml 会做相应变化,在
完成配置:
pom.xml / application.yaml 可参考之前写的,取自己需要的即可。
注入 RestTemplate:
RestTemplate基本介绍:
1、RestTemplate 是Spring 提供的用于访问 Rest 服务的模板类
2、RestTerplate 提供了多种便捷访问远程 Http 服务的方法
3、说明:可以这样理解,通过 RestTemplate,我们可以发出 http 请求(支持Restful 风格),去调用Controller 提供的 API 接口,就像我们使用浏览器发出http 请求调用该 API接口一样。
4、使用简单便捷
官网地址:
创建配置类: com/hspedu/springcloud/config/CustomizationBean.java
1 |
|
创建:com/hspedu/springcloud/controller/MemberConsumerController.java
1 |
|
3.3.3.2 注意事项和使用细节
添加会员数据库中为 null 的解决方案
开启 Run DashBoard
当springcloud 的服务有多个时,管理多个服务的启动使用run会不好管理,这样我们就可以使用
RunDashboard.
找到 你的项目/.idea/workspace.xml 文件在其中添加下面的代码即可
添加在:原本第二行
1 | <component name="RunDashboard"> |
重启项目
视图-工具窗口-服务 即可方便管理各个主程序!
3.4 创建共用模块-供其它模块使用
3.4.1 需求说明**/**图解
3.4.2 思路分析**/**图解
1、创建 Moduel & 完成配置
2、创建entity,把共用的实体类放到对应的包下
3、完成测试
3.4.3 实现步骤
3.4.3.1 创建 Moduel & 完成配置
3.4.3.1.1 创建 e_commerce_center-common-api
在pom.xml中提取公共依赖
1 | <dependency> |
抽取共用 API/类
写入公共的entity
使用 Maven 打包成 jar
会在test目录中生成对应jar包
工程重构
1.在 member-service-consumer-80 引入 e_commerce_center-common-api-1.0-SNAPSHOT.jar
删除原来的 entity 包
修改 pom.xml
1 | <!-- 引入 e_commerce_center-common-api --> |
这样就完成了!
4 SpringCloud Eureka 服务注册中心
4.1 Eureka介绍
4.1.1 学 Eureka 前的说明
1、Spring Cloud 组件选型图
![image-20230519190901580](/Users/donn/Library/Application Support/typora-user-images/image-20230519190901580.png)
2、从上图可以看出,目前主流的服务注册&发现的组件是 Nacos, 但是 Eureka 作为一个老牌经典的 服务注册&发现技术还是有必要学习一下,原因:
(1) 一些早期的分布式 微服务项目使用的是 Eureka, 小伙伴在工作中,完全有可能遇到这种情况。
(2) 后期的服务注册&发现组件/技术,都参考了 Eureka 设计和理念,学习了Eureka 后,我们上手Nacos容易很多,而且理解的更深刻。
4.1.2 当前项目架构问题分析 **-**引出 Eureka
一图胜千言
1.在企业级项目中,服务消费访问请求会存在高并发 (一个服务提供模块可能无法承受)
2.如果只有一个会员中心-提供服务模块,可用性差 (如果只有一个服务提供模块,如果故障,系统将无法使用,可用性差)
3.所以,会员中心提供服务往往是一个集群,也就是说会有多个会员中心提供服务微服务模块 ( 高可用 )
4.那么这个时候,就存在一个问题:服务消费方,怎么去发现可以使用的服务
5,当服务消费方,发现了可以使用的服务后(可能是多个,又存在一个问题:到底调用 A服务,还是B服务? 这就引出了服务注册和负载均衡)
6.Eureka 就可以解决上述问题
4.1.3 引入 Eureka 项目架构
一图胜千言
会员中心-是提供服务的模块,在项目中,会做成集群,提供高可用
Eureka Server 有必要的话,也可以做成集群
Eureka 包含两个组件:Eureka Server和 Eureka Client
Eureka Server 提供注册服务,各个微服务节点通过配置启动后,会在 Eureka Server中迸行注册,这样 EurekaServer 中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
Euretka Client 通过注册中心进行访问,是一个Java 客户端,用于简化 Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin) 负载算法的负载均衡器。在应用启动后,将会向 Eureka Server 发送心跳(默认周期为 30秒)。如果 Eureka Server 在多个心跳周期内没有接收到某个节点的心跳,EurekaServer 将会从服务注册表中把这个服务节点移除(默认90秒)
4.1.4 服务治理介绍
4.1.4.1 Eureka实现服务治理
4.1.4.2 在传统的 rpc 远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理困难,所以 需要治理服务之间依赖关系
4.1.4.3 服务治理实现服务调用、负载均衡、容错等,实现服务发现与注册。
4.1.4.4 二说分布式开发: https://jingyan.baidu.com/article/46650658def479f549e5f83e.html
4.1.5 服务注册和发现
Eureka采用了CS [client-server-java基础我们讲过一个多人聊天项目] 的设计架构,Eureka Server 作为服务注册功能的服务器,它是服务注册中心。
系统中的其他微服务,使用 Eureka的客户端连接到 Eureka Server并维持心跳连接,通过 Eureka Server 来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息 比如 服务地址通讯地址等以别名方式注册到注册中心上。
服务消费者或者服务提供者,以服务别名的方式去注册中心上获取到实际的服务提供者通讯地址,然后通过RPC调用服务。
4.2 创建单机 Eureka Server-注册中心
4.2.1 需求说明**/**图解
4.2.2 实现步骤
4.2.2.1 创建 Moduel & 完成配置
4.2.2.1.1 创建 e-commerce-eureka-server-9001 微服务模块**[**作为注册中心]
创建 module
4.2.2.1.2 修改 e-commerce-eureka-server-9001 的 pom.xml , 加入依赖
4.2.2.1.3 创建 resources/application.yml
1 | server: |
4.2.2.1.4 创建主启动类 com/hspedu/springcloud/EurekaApplication.java
记得添加@EnableEurekaServer,表示该程序作为EurekaServer
4.2.3 将 member-service-provider-10000 作 为 EurekaClient 注 册 到 e-commerce-eureka-server-9001 成为服务提供者
4.2.3.1 架构示意图
4.2.3.2 修改 member-service-provider-10000 的 pom.xml
1 | <!-- 引入eureka-client场景启动器starter--> |
4.2.3.3 修改 member-service-provider-10000 的 resources/application.yml
1 | server: |
4.2.3.4 修改 member-service-provider-10000 的 com/hspedu/springcloud/MemberApplication.java
添加注解:
1 | //@EnableEurekaClient,将该程序标识为Eureka-client |
4.2.3.5 完成测试
4.2.3.5.1 启动 **e-commerce-eureka-server-9001 **
4.2.3.5.2 启动 **member-service-provider-10000 **
4.2.3.5.3 浏览器**: http://localhost:9001**
4.2.3.5.4 微服务注册名配置说明
4.2.4 配 置 member-service-consumer-80 作 为 EurekaClient, 可 以 拉取 / 获 取e-commerce-eureka-server-9001 提供的服务信息
4.2.4.1 架构示意图
4.2.4.2 修改 pom.xml
1 | <!-- 引入eureka-client场景启动器starter--> |
4.2.4.3 修改 application.yml
1 | 在原本的配置在增加: |
4.2.4.4 修改 MemberConsumerApplication.java
添加注解:@EnableEurekaClient 将该程序标识为Eureka-client
4.2.4.5 完成测试
4.2.4.5.1 启动 **e-commerce-eureka-server-9001 **
4.2.4.5.2 启动 **member-service-consumer-80 **
4.2.4.5.3 浏览器**: http://localhost:9001**
4.2.5 Service Consumer 、Service Provider 、EurekaServer 的维护机制
EurekaServer中维护了服务信息——一个键值对:key是服务名,value是 调用服务的地址
4.2.6 Eureka自我保护模式
4.2.6.1 自我保护模式理论
在默认情况下, Eureka 启动了自我保护模式
自我保证机制/模式说明
默认情況下Eurekaclient定时向EurekaServer端发送心跳包。
如果Eureka在server端在一定时间内(默认90秒)没有收到Eurekaclient发送心跳包,便会直接从服务注册列表中剔除该服务。
如果Eureka 开启了自我保护模式/机制,那么在短时间 (90秒中)内丢失了大量的服务实例心跳,这时候EurekaServer会开启自我保护机制,不会剔除该服务(该现象可能出现在如果网络不通或者阻鑫) 因为客户端还能正常发送心跳,只是网络延迟问题,而保护机制是为了解决此问题而产生的。
自我保护是属于 CAP 里面的 AP 分支, 保证高可用和分区容错性。(cap解读:https://blog.csdn.net/wangliangluang/article/details/120626014)
自我保护模式是—种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服 务。使用自我保护模式,可以让 Eureka 集群更加的健壮、稳定。
测试:
……
4.3 搭建 EurekaServer 集群- 实现负载均衡&故障容错
4.3.1 为什么需要集群 Eureka Server
微服务 RPC 远程服务调用最核心的是实现高可用
如果注册中心只有1个,它出故障,会导致整个服务环境不可用
解决办法:搭建 Eureka 注册中心集群,实现负载均衡+故障容错
4.3.2需求分析**/**图解
4.3.3 搭建 Eureka Server 集群
4.3.3.1 创建 e-commerce-eureka-server-9002 微服务模块[作为注册中心]
4.3.3.1.1 创建步骤参考 e-commerce-eureka-server-9001
4.3.3.1.2 修改 pom.xml , 加入依赖
4.3.3.1.3 创建 resources/application.yml
4.3.3.1.4 创建主启动类 EurekaApplication9002.java
4.3.3.2 修改 e-commerce-eureka-server-9001 微服务模块
4.3.3.2.1 修改 resources/application.yml
4.3.3.2.2 修改主启动类名为 EurekaApplication9001.java
4.3.3.3 修改 hosts 文件
域名转ip地址:先找本机的host文件,hosts文件中没有才去DNS服务器寻找,
现在我们需要访问eureka9001.com这样的形式,就需要自行在本机的hosts文件添加键值对实现域名->ip
/private/etc/hosts 复制出来,修改,覆盖原来的文件即可完成修改
在hosts文件中添加内容:
#eureka 主机名和 ip 映射
**127.0.0.1 eureka9001.com **
127.0.0.1 eureka9002.com
4.3.3.4 完成测试
4.3.3.4.1 启动 **e-commerce-eureka-server-9001
4.3.3.4.2** 启动 **e-commerce-eureka-server-9002
4.3.3.4.3** 浏览器**: http://eureka9001.com:9001** 浏览器**: http://eureka9002.com:9002**
4.3.3.5 将 member-service-provider-10000 注册到 EurekaServer 集群(目前 2 台)
4.3.3.5.1 修改 resources/application.yml
‘’’
defaultZone: http://eureka9001.com:9001/eureka, http://eureka9002.com:9002/eureka
*#*表示将自己注册到哪个 eurekaServer
将本微服务注册到多个 eurekaServer, 使用逗号隔开
‘’’
4.3.3.5.2 完成测试
1. 启动 e-commerce-eureka-server-9001 和 e-commerce-eureka-server-9002
2. 启动 member-service-provider-10000
3. 观察 member-service-provider-10000 是否注册到 Eureka 集群前 2 台)
4.3.3.6 将 member-service-consumer-80 注册到 EurekaServer 集群(目前 2 台)
4.3.3.6.1 修改 resources/application.yml
1 | defaultZone: http://eureka9001.com:9001/eureka,http://eureka9002.com:9002/eureka |
4.3.3.6.2 完成测试
1. 启动 e-commerce-eureka-server-9001 和 e-commerce-eureka-server-9002
2. 启动 member-service-consumer-80
3. 观察 member-service-consumer-80 是否注册到 Eureka 集群(目前 2 台)
4.3.4 搭建会员中心服务提供方**-**集群
4.3.4.1 架构示意图
4.3.4.2 创建member-service-provider-10002
1.参考member-service-provider-10000 来创建 member-service-provider-10002 即可
2.创建好后,使用memberservice-provider-10000 的源 码和配置替換member-service-provider-10002 生成的代码(不要到磁盘整体拷贝,会出现关联到 member-service-provider-10000 的问题,很麻烦,可以创建好新项目的包,然后再拷贝对应包下的文件,就不会出向题)
3.提醒,拷贝时不要忘记拷贝 resources/mapper/Mem berMapper:xml 这些xaos.xml 文件
4.3.4.3 创建 resources/application.yml
1. 创建好 application.yml
2. 从 member-service-provider-10000 拷贝 application.yml 的内容
3. 修改端口号即可
4.3.4.4 修改主启动类名
1. 修改 member-service-provider-10000 的主启动类为 MemberProviderApplication10000
2. 修改 member-service-provider-10002 的主启动类为 MemberProviderApplication10002
4.3.4.5 完成测试
……
4.3.4.6 注意事项和细节
- 因为 member-service-provider-10000 和 mem ber-service-provider-10002 作为一个集群提供服务,因此需要將 spring.application.name 进行统一。
- 这样消费方通过统一的别名进行负载均衡调用。
将相同服务的提供方对外暴露的名称设置为相同的,这样就方便管理了。
4.3.5 配置服务消费端 member-service-consumer-80 使用会员中心服务集群
4.3.5.1 架构图
4.3.5.2 修改 MemberConsumerController.java
1 | public static final String MEMBER_SERVICE_PROVIDER_URL = "http://member-service-provider"; |
4.3.5.3 修改 CustomizationBean.java
给 RestTemplate添加注解:**@LoadBalanced**
目的是:赋予 RestTemplate 负载均衡的能力
4.3.5.5 完成测试
4.3.5.5.1 启动 eureka server 集群**(目前 2 台)**
4.3.5.5.2 启动 member-service-provider-10000
4.3.5.5.3 启动 member-service-provider-10002
4.3.5.5.4不急,先测试 : http://localhost:10000/member/get/1 和 http://localhost:10002/member/get/1
先看看直接使用服务提供方时有没有问题,没问题再进行下一步测试(方便排错!)
4.3.5.5.5 启动 member-service-consumer-80
4.3.5.5.6 浏览器访问**: http://localhost/member/consumer/get/1**
4.3.5.6 交替访问member服务说明:
- 注解@LoadBalanced 底层是Ribbon支持算法
- 2.Ribbon和Eureka 整合后consumer 直接调用服务而不用再关心地址和端口号,且该服务还有负载功能
4.3.6 获取 Eureka Server 服务注册信息 -DiscoveryClient
4.3.6.1 需求分析/图解
1. 需求分析示意图
2. 这里我们以服务消费方, 去获取 Eureka Server 的服务注册信息为例讲解
3. 当然也可以在服务提供方获取 Eureka Server 的服务注册信息
4.3.6.2 代码实现
- 所在模块 member-service-consumer-80
- 修改 com/hspedu/springcloud/controller/MemberConsumerController.java
1 | //装配DiscoveryClient |
3. 这里修改主启动类 com/hspedu/springcloud/MemberConsumerApplication.java
添加注解:@EnableDiscoveryClient
4.3.6.3 测试
1. 重启 member-service-consumer-80
2. 浏览器输出 http://localhost/member/consumer/discovery
4.3.6.4 注意事项和细节说明
在引入 DiscoveryClient 时,不要引入错误的包:
正确的包**:** import org.springframework.cloud.client.discovery.DiscoveryClient;
错误的包**:** import com.netflix.discovery.DiscoveryClient;
4.4 Eureka后续说明
1. Eureka 停更说明**: https://github.com/Netflix/eureka/wiki**
2. 对于一些早期使用 Eureka 项目,掌握老师讲解技术基本可以应付了(这也是老师为什么还 要讲 Eureka 的原因)
3.目前替代 Eureka 做服务注册和发现,均衡负载的 最佳组件是 spring Cloud Alibaba Nacos,后面老师会重点讲解。
4.虽然Eureka 停更,目前用的不多,但是它的服务注册和发现,均衡负载的思想是优先的,有了Eureka 的基础,我们学习 Spring Cloud Alibaba Nacos 会轻松很多
5 SpringCloudRibbon服务负载均衡
5.1 Ribbon介绍
5.1.1 Ribbon是什么
Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套**客户端负载均衡**的工具。
Ribbon 主要功能是提供客户端负载均衡算法和服务调用
Ribbon 客户端组件提供一系列完善的配置项如连接超时,重试等。
Ribbon 会基于某种规则(如简单轮询,随机连接等)去连接指定服务
程序员很容易使用 Ribbon 的负载均衡算法实现负载均衡
一句话:Ribbon: 负载均衡+RestTemplate调用
5.1.2 官网
5.1.2.1 https://github.com/Netflix/ribbon
5.1.3 Ribbon进入维护状态
Ribbon 目前进入维护模式, 未来替换方案 是 Spring Cloud LoadBalancer
5.1.4 LB(Load Balance)
5.1.4.1 LB分类
集中式 LB
即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5,也可以是软件,如Nginx),由该设施负责把访向请求通过某种策略转发至服务的提供方:
LB(Load Balance 负载均衡)
进程内 LB
将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些服务地址可用,然后再从这些地址中选择出一个合适的服务地址。
Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。
5.1.4.2 实例-前面 member-consumer 轮询负载访问 10000/10002 底层就是 Ribbon 默认的轮询负载算法
5.2 Ribbon原理
5.2.1 Ribbon架构图**&**机制
Ribbon 机制
- 先选择 EurekaServer,它优先选择在同一个区域内负载较少的 server
- 再根据用户指定的策略,在从 server取到的服务注册列表中选择一个地址
- Ribbon 提供了多种策略:比如轮询、随机和根据响应时间加权。
5.2.2 Ribbon常见负载算法
5.3 替换负载均衡算法-应用实例
5.3.1 需求分析**/**图解
- 需求:将默认的轮询算法改成随机算法 RandomRule
- 浏览器输入:htp://ocalhost/member/consuimer/get/1
- 要求 彷问的 10000/10002 端口的服务是随机的
5.3.2代码实现
- 创建 member-service-consumer-80com/hspedu/springcloud/config/RibbonRule.java
5.3.3 测试
1. 浏览器输入 **: http://localhost/member/consumer/get/1 **
2. 观察访问的 10000/10002 端口的服务是随机的
6 SpringCloud Open Feign服务调用
6.1 OpenFeign介绍
6.1.1 OpenFeign是什么
0penFeign 是个声明式 Webservice 客户端,使用 OpenFeign 让编写 web Service 客户端更简单
它的使用方法是定义一个服务接口然后在上面添加注解
0penFeign 也支持可拔插式的编码器和解码器。
Spring cloud 对 OpenFeign 进行了封装使其支持了 Spring Mvc 标准注解和HttpMessageConverters
0penFeign 可以与Eureka 和 Ribbon 组合使用以支持负载均衡
6.1.2 官网
6.1.2.1 https://github.com/spring-cloud/spring-cloud-openfeign
6.1.3 Feign和OpenFeign区别
Feign(不好用,没人用了):
Feign是Spring Cioud组件中的一个轻量级RESTful的HTTP服务客户端
Feign内置了Ribbon,用来做客户端免载均衡, 去调用服务注册中心的服务。
Feign的使用方式是:使用Feign的注解定义接口,调用服务注册中心的服务
Feign支持的注解和用法请参考官方文档:https://githulb.com/OpenFeign/feign
Feign本身不支持Spring MvC的注解,它有一套自己的注解
OpenFeign:
openFeign是Spring Cloud **在Feign的基础上支持了Spring MvC的注解**,如@Requesapping等等。
OpenFeign的@FeignClient可以解析SpringvC的@RequestMapping注解下的接口
OpenFeign通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务
精简一句话 : OpenFeign 就是在 Feign 基础上做了加强 , 有些程序员为了方便,说 Feign 就是指的 OpenFeign
6.2 OpenFeign-应用实例
6.2.1 需求分析**/**图解
(Eureka实现获取服务、Ribbon实现自定义负载均衡算法、RestTemplate实现远程调用)
(Eureka实现获取服务、OpenFeign实现负载均衡+远程调用)
6.2.2 创建服务消费模块 **-**通过 OpenFeigen 实现远程调用
1. 参考 member-service-consumer-80 创建 **member-service-consumer-openfeign-80(**具体步骤参考以前)
2. 修改 pom.xml
1 | <!-- 引入openfeign-start,即场景启动器 --> |
**3.创建 application.yml 内容如下:**、
1 | server: |
4.创建主启动类
1 | //启动openFeignClient |
- 创建 com/study/springcloud/service/MemberFeignService.java
1 |
|
- 创建 com/study/springcloud/controller/MemberConsumerFeignController.java
1 | //结果以json格式返回 |
6.2.3 测试
浏览器输入 : http://localhost/member/consumer/openfeign/get/1
6.2.4 注意事项和细节
配Openfeign的使用特点是 微服务调用接口+@Feignclient,使用接口进行解耦
@FeignClient(value = “MEMBER-SERVICE-PROVIDER”),这里MEMBER-SERVICE-PROVIDER就是Eureka Server服务提供方注册的名称,不要写错了
接口方法上: value是不能乱写,远程调用的url 为http://MEMBER-SERVICE-PROVIDER/member/get/{id}
@GetMapping(“/member/get/{id}”)
public Result getMemberById(@PathVariable(“id”)Long id);
6.3 日志配置
6.3.1 基本介绍
1.说明:Feign 提供了日志打印功能,可以通过配罝来调整日志级别,从而对 Feign 接口的调用情况进行监控和输出
2.日志级别
NONE :默认的,不显示任何日志
BASIC:仅记录请求方法、URL、响应状态码及执行时间;
HEADERS : 除了 BASIC中定义的信息之外,还有请求和响应的头信息;
FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。
6.3.2 配置日志**-**应用实例
1. 在 member-service-consumer-openfeign-80 创 建
com/hspedu/springcloud/config/OpenFeignConfig.java
1 |
|
2. 在 member-service-consumer-openfeign-80 修改 application.yml
1 | #对MemberFeignService接口调用过程打印信息-debug |
6.3.3 测试
……
6.4 OpenFeign超时
若服务提供方(可能由于各种原因,比如操作数据库时间过长)响应超过OpenFeign的等待时间(默认1秒),会返回超时错误(time out)
……
6.4.3 设置OpenFeign超时时间
在服务消费方的配置文件中进行响应配置:
1 | # 设置feign客户端超时时间 |
6.4.4 测试
……
7 🌟SpringCloudGateway 服务网关
7.1 Gateway介绍
7.1.1 看一个需求,引出网关服务
1、有一个前后端分离项目**,** 分析如图
2、使用网关服务, 重构项目架构
7.1.2 🌟Gateway 网络拓扑图
7.1.3 Gateway是什么
Gateway 是在 Spring 生态系统之上构建的 API 网关服务,基于 spring , Spring Boot 和 Project Reactor 等技术。
Gateway 旨在提供一种简单而有效的方式来对 API 进行路由,以及提供一些强大的过滤器功能,例如 :熔断、限流、重试等。
7.1.4 官网
7.1.4.1 https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
7.1.5 Gateway 核心功能
7.1.5.1 鉴权
7.1.5.2 流量控制
7.1.5.3 熔断
7.1.5.4 日志监控
7.1.5.5 反向代理
7.1.6 Gateway vs Zuul
7.1.6.1 Gateway 和 Zuul 区别
SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul
SpringCloud Gateway 是基于 Spring WebFlux框架实现的
Spring WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty,提升了网关性能
7.1.6.2 Gateway 特性
Spring Cloud Gateway 基 于 Spring Framework(支 特 Spring WebFlux), project Reactor 和 spring Boot 进行构建,具有如下特性:
- 动态路由
- 可以对路由指定 predicate(断言)和Filter(过滤器)
- 集成Hystrix的断路器功能
- 集成 Spring Cloud 服务发现功能
- 请求限流功能
- 支持路径重写
7.2 Gateway基本原理
7.2.1 Gateway核心组件
7.2.1.1 一张图
web 请求通过一些匹配条件,定位到真正的服务节点/微服务模块,在这个转发过程的前后,进行一些精细化控制。
predicate:就是匹配条件(请求是否能被接受使用)
filter:可以理解为是网关的过滤机制。
有了predicate 和filter,再加上目标 URL,就可以实现一个具体的路由
7.2.1.2 Route(路由)
一句话:路由是构建网关的基本模块,它由 ID,目标 URL,一系列的断言和过滤器组成,如果断言为 true 则匹配该路由。
7.2.1.3 Predicate(断言)
一句话:对 HTTP 请求中的所有内容(例如请求头或请求参数)进行匹配,如果请求与断言相匹配则进行路由
简单举例,比如配置路径,- Path=/member/get/** 断言,路经相匹配的进行路由转发,如果Http 请求的路径不匹配,则不进行路由转发。
7.2.1.4 Filter(过滤)
1、一句话:使用过滤器,可以在请求被路由前或者之后对请求进行处理
2、你可以理解成,在对 Http 请求断言匹配成功后,可以通过网关的过滤机制,对Http 请求处理
7.2.2 HowItWorks工作机制
7.2.2.1 一图胜千言
客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,將其发送到 Gateway Web Handler。
Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(”pre”)或之后(“post”)执行业务逻辑。
Filter 在”pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,
在”post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
一句话说:路由转发+执行过滤器链
7.3 搭建 Gateway 微服务
7.3.1 搭建 **Gateway-**应用实例
7.3.1.1 需求分析/图解
– 引入 Gateway 项目架构
1. 通过网关暴露的接口,实现调用真正的服务
2. 网关本身也是一个微服务模块
7.3.1.2 代码实现
1. 参考 member-service-consumer-80 创建 **e-commerce-gateway-20000(**具体步骤参考以前)
2. 修改 pom.xml, 部分内容可以从 member-service-consumer-80 的 pom.xml 拷贝
1 |
|
3.创建 application.yml(重点核心) 内容如下:
1 | server: |
**4.**创建主启动类 com/hspedu/springcloud/GateWayApplication20000.java
1 |
|
7.3.1.3 测试
……
7.3.1.4 注意事项和细节
因为我们的 member 的 controller 的方法参数使用了@RequestBody ,所以在使用 postman时,需要使用 json 格式发送数据, 否则会报400错误。
7.3.2 二说 Gateway 路由配置
7.3.2.1 方式 1: application.yml 中配置-前面讲过
7.3.2.2 方式 2: 编写配置类注入【了解】
1. 先注销 application.yml 对网关路由部分注销
2. 重启 e-commerce-gateway-20000, 再次测试,网关路由失效
3. 参考官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#spring-cloud-circuitbreaker-filter-factory , 创 建com/hspedu/springcloud/config/GateWayRoutesConfig.java
7.3.2.3 测试
……
7.3.3 动态路由
7.3.3.1 需求分析/图
7.3.3.2 代码实现
1. 修改 e-commerce-gateway-20000 的 application.yml
1 | server: |
7.3.3.3 测试
7.3.3.3.1 启动 e-commerce-eureka-server-9001
7.3.3.3.2 启动 member-service-provider-10000
7.3.3.3.3 启动 member-service-provider-10002
7.3.3.3.4 启动 e-commerce-gateway-20000
7.3.3.3.5 浏览器**:(通过网关访问) http://localhost:20000/member/get/1**
浏览器输入**: http://localhost:20000/member/get/1**
7.3.3.4 注意事项和细节
7.3.3.4.1 配置好动态路由后 Gateway 会根据注册中心上微服务名,为请求创建动态路由,实现 动态路由 功能
7.3.3.4.2 使用的 lb 协议支持负载均衡**-**轮询算法
7.3.3.4.3 配置自己的负载均衡算法, 测试完毕恢复成原来的轮询算法
7.4 Predicate/断言
7.4.1 基本介绍
7.4.1.1 一句话: Predicate 就是一组匹配规则,当请求匹配成功,就执行对应Route, 匹配失败,放弃 处理/转发
7.4.1.2 RoutePredicateFactories
- Spring Cloud Gateway包括许多内置的Route Predicate工厂,所有这些Predicate都与HTTP请求的不同属性匹配,可以组合使用.
- Spring Cloud Gateway 创建 Route 对象时,使用RoutePredicateFactory 创建Predicate对象,Predicate 对象可以赋值给Route。
- 所有这些谓词都匹配HTTP请求的不同属性。多种谓词工厂可以组合
其实就是利用工厂中的api进行断言
7.4.2 RoutePredicate实例(根据上述文档进行操作演示)
7.4.2.1 AfterRoutePredicate
7.4.2.1.1 需求分析**/**图解
1. 需求分析**/**图解
需求**:** 只有 2022-11-18 12:35:50 之后的请求才进行匹配**/转发,** 不满足该条件的,不处理
7.4.2.1.2 代码实现
1. 参考文档 : https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-request-predicates-factories
2. 修改 e-commerce-gateway-20000 的 application.yml
1 | spring: |
7.4.2.2 BeforeRoutePredicate
1. 需求分析**/**图解
需求**:** 只有 2022-11-18 12:35:50 之前的请求才进行匹配**/转发,** 不满足该条件的,不处理
7.4.2.2.2 代码实现
2. 修改 e-commerce-gateway-20000 的 application.yml
1 | spring: |
7.4.2.3 BetweenRoutePredicate
1. 需求分析**/**图解
需求**:** 只有 2020-11-18 12:35:50 和 2022-11-18 12:35:50 之间 的请求才进行匹配**/转 发,** 不满足该条件的,不处理
7.4.2.3.2 代码实现
2. 修改 e-commerce-gateway-20000 的 application.yml
1 | spring: |
7.4.2.4 CookieRoutePredicate
7.4.2.4.1 需求分析**/**图解
需求**:** 请求带有 cookie 键**: user** 值**: hsp** 才匹配**/**断言成功
1.4.2.4.2 代码实现
2. 修改 e-commerce-gateway-20000 的 application.yml
1 | spring: |
7.4.2.5 HeaderRoutePredicate
7.4.2.5.1 需求分析**/**图解
1. 需求分析**/**图解
需求: 请求头 Header 有 X-Request-Id, 并且值为xxxxx 才匹配/断言成功
1 | spring: |
7.4.2.6 HostRoutePredicate
7.4.2.6.1 需求分析**/**图解
1. 需求分析**/**图解
需求: 请求 Host 是*.hspedu.* 才匹配/断言成功 , 比如 Host: www.hspedu.com
1 | spring: |
7.4.2.7 MethodRoutePredicate
1.4.2.7.1 需求分析**/**图解
需求: 请求是 XXXXXX 方式才匹配/断言成功
1 | spring: |
7.4.2.8 PathRoutePredicate
1 | spring: |
7.4.2.9 QueryRoutePredicate
1.4.2.9.1 需求分析**/**图解
需求**:** 请求有参数 email ,并且满足电子邮件的基本格式, 才能匹配**/**断言成功
1 | spring: |
7.4.2.10 RemoteAddr Route Predicate
7.4.2.10.1 需求分析**/**图解
需求: 请求的 IP 是 127.0.0.1, 才能匹配/断言成功
1 | spring: |
7.5 Filter/过滤器
7.5.1 基本介绍
路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应
Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生
7.5.2 类型
7.5.2.1 GatewayFilter
7.5.2.2 GlobalFilter
一般很少使用官方的filter,都是自定义满足需求,因此只介绍一个官方filter
7.5.3 GatewayFilter使用
7.5.3.1 开发直接使用 GatewayFilter 较少,一般是自定义过滤器
演示:The AddRequestParameter GatewayFilter Factory
1 | spring: |
7.5.4 自定义 GlobalFilter
7.5.4.1 需求分析/图解
1. 自定义全局 GlobalFilter 过滤器
2. 如果请求参数 user=hspedu , pwd=123456 则放行**,** 否则不能通过验证
7.5.4.2 代码实现
1. 在 e-commerce-gateway-20000 创建com/hspedu/springcloud/filter/CustomGateWayFilter.java
1 | package com.study.springcloud.filter; |
7.5.4.3 测试
7.5.4.3.1 启动 e-commerce-eureka-server-9001
7.5.4.3.2 启动 member-service-provider-10000/10002
7.5.4.3.3 启动 e-commerce-gateway-20000
7.5.4.3.4 浏览器**:(通过网关访问) http://localhost:20000/member/get/1?user=hspedu&pwd=123456** 输入**: http://localhost:20000/member/get/1?user=hspedu&pwd=123456**
7.5.4.4 测试完毕,记得代码恢复到测试前
8 SpringCloud Sleuth+Zipkin 服务跟踪
8.1 Sleuth/ZipKin基础
8.1.1 官网
8.1.1.1 https://github.com/spring-cloud/spring-cloud-sleuth
8.1.2 Sleuth/Zipkin是什么?
8.1.2.1 概述(两张图)
在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用**,** 来协同产生最后的请求结果,每一个请求都会形成一条复杂的分布式服务调用链路
链路中的任何一环出现高延时或错误都会引起整个请求最后的失败,因此对整个服务的调用进行链路追踪和分析就非常的重要
Sleuth 和 Zipkin简单关系图
8.1.2.2 一句话: Sleuth 提供了一套完整的服务跟踪的解决方案 并兼容 Zipkin
8.1.2.3 梳理: 🌟Sleuth 做链路追踪 , Zipkin 做数据搜集/存储/可视化
8.1.3 Sleuth工作原理
1. Span 和 Trace 在一个系统中使用 Zipkin 的过程**-**图形化
表示一请求链路,一条链路通过Trace id唯一标识,span标识发起的请求信息,各span通过parent id关联起来
Trace:类似于树结构的Span集合,表示一条调用链路,存在唯一标识 (一条请求链路只有唯一一个Trace id)
Span:基本工作单元,表示调用链路来源,通俗的理解span就是一次请求信息
2. spans 的 parent/child 关系图形化
小伙伴注意看老师标识的红线,后一个span节点的parentid 指向/记录 了上一个Span结点
span就是一次请求信息
多个Span集合就构成一条调用链路
在span=C 这个节点存在分支
8.2 Sleuth/ZipKin-搭建链路监控实例
8.2.1 需求说明**/**图解
要求: 通过 Sleuth 和 Zipkin 可以对服务调用链路进行监控, 并在 Zipkin 进行显示
8.2.2 安装**/**使用 Zipkin
8.2.2.1 下载
下载地址:https://repo1.maven.org/maven2/io/zipkin/zipkin-server/
得到 zipkin-server-2.14.1-exec.jar
8.2.2.2 运行
- 进入 zipkin-server-2.14.1-exec.jar 所在目录的终端
- 执行命令 java -jar zipkin-server-2.14.1-exec.jar 开启zipkin服务
8.2.2.3 访问
浏览器输入**:http://localhost:9411/zipkin/**
8.2.3 服务提供方集成 Sleuth/Zipkin
1. 修改 member-service-provider-10000 的 pom.xml , 增加引入 sleuth+zipkin
1 | <!-- 引入sleuth与zipkin相关依赖 --> |
2. 修改 member-service-provider-10000 的 appliaction.xml , 指定 Zipkin
1 | server: |
8.2.4 服务消费方集成 Sleuth/Zipkin
1. 修改 member-service-consumer-80 的 pom.xml , 增加引入 sleuth+zipkin
2. 修改 member-service-consumer-80 的 appliaction.xml , 指定 Zipkin
8.2.5 测试
8.2.5.1 启动 e-commerce-eureka-server-9001
8.2.5.2 启动 member-service-provider-10000
8.2.5.3 启动 member-service-consumer-80
8.2.5.4 浏览器: 浏览器输入: http://localhost/member/consumer/get/1
8.2.6 查看监控**&**分析结果
8.2.6.1 查看监控&分析结果
1. 查看 **Zipkin : http://localhost:9411/zipkin/ **
2. 选择某个服务,看结果
3. 查看一次调用链路的深度,以及该链路包含请求,各个请求耗时,**找到请求瓶颈,为优化提供依据**(重要)
4. 查看服务调用的依赖关系
9 🌟SpringCloudAlibabaNacos 服务注册中心+服务配置
9.1 Nacos基础
9.1.1 官网
9.1.1.1 https://github.com/alibaba/Nacos
9.1.2 Nacos是什么?
9.1.2.1 一句话: Nacos 就是注册中心[替代 Eureka]+配置中心[替代 Config]
9.1.2.2 Nacos:Dynamic Naming and Configuration Service
9.1.2.3 Nacos:架构理论基础: CAP 理论 (支持 AP 和 CP, 可以切换)
CAP理论:
一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。
- 一致性指 “all nodes see the same data at the same time”,即所有节点在同一时间的数据完全一致。即多副本(Replications)问题中的数据一致性
- 可用性指“
Reads and writes always succeed
”,即服务在正常响应时间内一直可用。好的可用性主要是指系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。 - 分区容错性指“the system continues to operate despite arbitrary message loss or failure of part of the system”,即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性或可用性的服务。
比如对于两个结点如果它们之间的网络断开了,我们假设需要满足分区容错性,那么一定要在一致性和可用性之间进行取舍(分区容错性满足的情况下,如果满足一致性那就必须等待网络恢复后数据进行同步后才能提供服务——放弃了可用性;反之,如果选择了可用性,那么两个结点提供的数据一定不能保证一致性——牺牲了一致性)
9.1.3 Nacos下载&运行
9.1.3.1 下载: https://github.com/alibaba/nacos/releases/tag/1.2.1
9.1.3.2 环境要求: Java8/Maven 3.2.x+
9.1.3.3 解压
在我的mac中执行:
1 | cd /Applications/nacos/bin //因为我把nacos放在了/Applications目录下 |
9.1.3.4 浏览器 http://localhost:8848/nacos
9.1.3.5 用户名/密码 为 nacos
9.2 创建 Nacos 服务提供者
9.2.1 需求说明/图解
9.2.2 创建 member-service-nacos-provider-10004 并注册到 NacosServer8848
9.2.2.1 创建 member-service-nacos-provider-10004
参考member-service-provider-10000 来创建 member-service-nacos-provider-10004 即可
创建好后,使用member-service-provider-10000 的源码和配置替换member-service-nacos-provider-10004 生成的代码
提醒,拷贝时不要忘记拷贝 resources/mapper/MernberrVapper.xml 这些xeox.xrl 文件
9.2.2.2 修改父项目 pom.xml
1 | <dependency> |
9.2.2.3 修改本模块 pom.xml
1. 将 member-service-provider-10000 的 pom.xml 的
拷贝过来,修改即可
1 |
|
9.2.2.4 创建 application.yml
1. 将 member-service-provider-10000 的 application.xml 拷贝过来,修改即可
1 | server: |
9.2.2.5 创建主启动类
1. 创建主启动类 MemberNacosProviderApplication10004
1 | package com.study.springcloud; |
9.2.2.6 为看到更好提示,修改 Controller
……
9.2.2.7 测试
9.2.2.7.1 启动 Nacos Server 8848
9.2.2.7.2 启动 member-service-nacos-provider-10004
9.2.2.7.3 观察 nacos 服务是否注册成功
9.2.3 创建 member-service-nacos-provider-10006 并注册到 NacosServer8848
9.2.3.1 创建 member-service-nacos-provider-10006
参考member-service-nacos-provider-10004 来创建 member-service-nacos-provider-10006 即可
创建好后,使用member-service-nacos-provider-10004 的源码和配罝替换member-service-nacos-provider-10006 生成的代码
提醒,拷贝时不要忘记拷贝 resources/mapper/MemberMapper.xml 这些xoxx.xml文件
9.2.3.2 修改本模块 pom.xml
1. 将 member-service-provider-10000 的 pom.xml 的
拷贝过来,修改即可
9.2.3.3 创建 application.yml
1. 将 member-service-nacos-provider-10004 的 application.xml 拷贝过来,修改端口即可
9.2.3.4 创建主启动类
1. 创建主启动类 MemberNacosProviderApplication10006 (也复制过来,改个名称即可)
9.2.3.5 为看到更好提示,修改 Controller
9.2.3.6 测试
9.2.3.6.1 保证 Nacos Server 8848 是启动的
9.2.3.6.2 启动 **member-service-nacos-provider-10006 **
9.2.3.6.3 观察 nacos 服务是否注册成功
9.2.3.6.4 浏览器**: http://localhost:10006/member/get/1**
9.3 创建 Nacos 的服务消费者
9.3.1 需求说明**/**图解
– 示意图
9.3.2 创建 member-service-nacos-consumer-80 并注册到 NacosServer8848
9.3.2.1 创建 member-service-nacos-consumer-80
- 参考 member-service-consumer-80 来创建 member-service-nacos-consumer-80 即可
9.3.2.2 修改 pom.xml
将 member-service-consumer-80 的 pom.xml 的
9.3.2.3 创建 application.yml
1 | server: |
9.3.2.4 创建主启动类
……
9.3.2.5 业务类
nacos 本身就集成了 Ribbon, 直接支持 Ribbon(负载均衡)+RestTemplate(远程调用) 调用
1. 创建配置类 com/hspedu/springcloud/config/CustomizationBean.java
2. 创建 com/hspedu/springcloud/controller/MemberNacosConsumerController.java
9.3.2.6 测试
9.3.2.6.1 启动 Nacos Server 8848
9.3.2.6.2 启动 member-service-nacos-provider-10004/10006 9.3.2.6.3 启动 member-service-nacos- consumer-80
9.3.2.6.4 浏览器**: http://localhost/member/nacos/consumer/get/1**
9.3.2.7 配置自己的负载均衡算法, 测试完毕恢复成原来的轮询算法
1 | package com.study.springcloud.config; |
9.4 NacosAP和CP切换-理论
9.4.1 各种注册中心对比
9.4.2 选择 AP 还是 CP?
1、CP: 服务可以不能用,但必须要保证数据的一致性。
2、AP: 数据可以短暂不一致,但最终是需要一致的,无论如何都要保证服务的可用。
3、取舍:只能在 CP 和 AP 选择一个平衡点**,** 大多数都是选择 AP 模式
9.4.3 AP和CP切换
Nacos 集群默认支持的是CAP原则中的AP原则,但是也可切换为CP原则**(一般不切换)**
9.4.3.2 参考: https://www.jianshu.com/p/c56e22c222bb
9.5 Nacos 配置中心实例
9.5.1 需求分析**/**图解
微服务各个模块中有许多配置是相同的,在配置中心进行统一的配置不仅配置更方便,也便于日后修改。
– 示意图
9.5.2 在 Nacos Server 加入配置
- 进入到 Nacos Server
- 加入配置, 老韩特别提醒: 文件后缀.yaml 别忘了
Data ID: e-commerce-nacos-config-client-dev.yaml
9.5.3 创建 Nacos 配置客户端模块 e-commerce-nacos-config-client5000
9.5.3.1 创建 Module
先创建 e-commerce-nacos-config-client5000 模块,参考以前的方法
9.5.3.2 修改 pom.xml
1. 修改 pom.xml
1 | 在之前的消费方xml文件的基础上添加: |
9.5.3.3 创建 application.xml
创建 application.yml
1 | spring: |
参考*: https://blog.csdn.net/zsl131557/article/details/80886114*
9.5.3.4 创建 bootstrap.yml
创建 bootstrap.yml
1 | server: |
9.5.3.5 主启动类
……
9.5.3.6 业务类
1 | package com.study.springcloud.controller; |
9.5.3.7 测试
9.5.3.7.1 启动 **Nacos Server
9.5.3.7.2 启动 **e-commerce-nacos-config-client5000 **
9.5.3.7.3 浏览器**: http://localhost:5000/nacos/config/ip**
浏览器输入**: http://localhost:5000/nacos/config/ip**
9.5.3.8 注意事项和细节
0. src\main\java\com\study\springcloud\controller\NacosConfigClientController.java 的 @Value(“${config.ip}”), 是 import org.springframework.beans.factory.annotation.Value; 而不是 lombok 包下的.
1. 配置文件 application.yml 和 bootstrap.yml 结合会得到配置文件/资源的地址
2. 参考文档: https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
3. 注意在 Nacos Server 的配置文件的后缀是 .yaml , 而不是 .yml
4. 在项目初始化时,要保证先从配置中心进行配置拉取,拉取配置之后,才能保证项目的正常启动, 也就是说如果项目不能正确的获取到 Nacos Server 的配置数据,项目是启动不了的.[演示]
5. springboot 中配置文件的加载是存在优先级顺序的,bootstrap.yml 优先级高于 application.yml
🌟6. @RefreshScope 是 springcloud 原生注解,实现配置信息自动刷新, 如果在 Nacos Server 修改了配置数据,Client 端就会得到最新配置
9.6 Nacos 分类配置 (实现配置隔离)
9.6.1 DataID方案
9.6.1.1 需求分析/图解
– 示意图
9.6.1.2 解决方案分析
9.6.1.2.1 使用 Data ID 方案解决
9.6.1.3 配置实现
1. 在 nacos server 创建新的配置:e-commerce-nacos-config-client-test.yaml
9.6.1.4 修改 application.yml
1 | spring: |
9.6.1.5 测试
9.6.1.5.1 浏览器**: http://localhost:5000/nacos/config/ip**
**1.**浏览器输入: http://localhost:5000/nacos/config/ip
9.6.2 Group方案
9.6.2.1 需求分析/图解
– 示意图
9.6.2.2 解决方案分析
9.6.2.2.1 使用 Group 方案解决
9.6.2.3 配置实现
1. 在 nacos server 创建新的配置:order/e-commerce-nacos-config-client-dev.yaml
2. 在 nacos server **创建新的配置:**seckill/e-commerce-nacos-config-client-dev.yaml
9.6.2.4 修改 application.yml
1 | spring: |
9.6.2.5 修改 bootstrap.yml
1 | server: |
9.6.2.6 测试
9.6.2.6.1 浏览器**: http://localhost:5000/nacos/config/ip**
**1.**浏览器输入: http://localhost:5000/nacos/config/ip
9.6.3 Namespace方案
9.6.3.1 需求分析/图解
– 示意图
9.6.3.2 解决方案分析
9.6.3.2.1 使用 Namespace 方案解决
9.6.3.3 配置实现
1. 在 nacos server 创建新的 namespace , baidu 和 alibaba
2. 在 nacos server 创建新的 group/dataid
9.6.3.4 修改 application.yml
1 | spring: |
9.6.3.5 修改 bootstrap.yml
1. 增加 Namespace 参数
1 | server: |
9.6.3.6 测试
9.6.3.6.1 浏览器**: http://localhost:5000/nacos/config/ip**
**1.**浏览器输入: http://localhost:5000/nacos/config/ip
9.6.4 Namespace/Group/Data ID 关系
9.6.4.1 一图胜千言
9.6.4.2 详解介绍
1. namespace / group / data id 的关系
2.梳理:
Nacos默认的命名空间是public,Namespace主要用来实现配置隔离,隔离范围大
Group默认是DEFAULT GROUP, Group可以把不同的微服务划分到同一个分组里面去
Service就是微服务,相同的Service可以是一个Cluster(簇/集群), Instance就是微服务的实例
10 SpringCloud Alibaba Sentinel——分布式系统的流量哨兵
10.1 Sentinel基础
10.1.1 官网
10.1.1.1 Github: https://github.com/alibaba/Sentinel
10.1.1.2 快速开始: https://sentinelguard.io/zh-cn/docs/quick-start.html
10.1.1.3 中文: https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
10.1.1.4 使 用 手 册 https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel
10.1.2 Sentinel是什么?
10.1.2.1 Sentinel 概述
- Sentinel 是什么?
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
- Sentinel 的主要特性
梳理: sentinel **可以完成的功能 **: 绿色方框列出的部分
- Sentinel 的开源生态
10.1.2.2 一句话: Sentinel: 分布式系统的流量防卫兵, 保护你的微服务
10.1.3 Sentinel核心功能
10.1.3.1 流量控制
10.1.3.2 熔断降级
- 在调用系统的时候,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积,如下图:
解读:
熔断降级可以解决这个问题,所谓的熔断降级就是当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
10.1.3.3 系统负载保护
根据系统能够处理的请求,和允许进来的请求,来做平衡,追求的目标是在系统不被拖垮的情况下**,** 提高系统的吞吐率
10.1.3.4 消息削峰填谷
某瞬时来了大流量的请求**,** 而如果此时要处理所有请求,很可能会导致系统负载过高,影响稳定性。
但其实可能后面几秒之内都没有消息投递,若直接把多余的消息丢掉则没有充分利用系统处理消息的能力
- Sentinel 的Rate Limiter模式能在某一段时间间隔内以匀速方式处理这样的请求, 充分利用系统的处理能力, 也就是削峰填谷, 保证资源的稳定性
10.1.4 Sentinel两个组成部分
10.1.4.1 核心库:(Java 客户端)不依赖任何框架/库,能够运行在所有 Java运行时环境,对 Spring Cloud有较好的支持
10.1.4.2 控制台:(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器(就跟nacos、eureka那种控制台那样)
10.2 Sentinel控制台
10.2.1 需求分析**/**图解
1. 需求**:** 搭建 Sentinel 控制台,用于显示各个微服务的使用情况
10.2.2 下载
10.2.2.1 https://github.com/alibaba/Sentinel/releases/tag/v1.8.0
10.2.3 运行
10.2.3.1 指令:
我把下载的jar包放在 /Applications/Java/jar包资源 此处了
因此在终端运行以下指令即可启动 Sentinel
1 | cd /Applications/Java/jar包资源 |
10.2.3.2 注意: Sentinel 控制台 默认端口是 8080
10.2.4 访问
10.2.4.1 浏览器: http://localhost:8080
10.2.4.2 控制台页面
1. 浏览器输入**: http://localhost:8080 ,** 用户**/**密码都是 sentinel
2. 登录成功后的页面, 目前是空的,因为 sentinel 还没有进行流量监控
10.3 Sentinel监控微服务
10.3.1 需求分析**/**图解
- 需求**:** 使用 Sentinel 控制台对 member-service-nacos-provider-10004 微服务 进行实时监控
– 示意图
- 当调用了member-service-nacos-provider-10004微服务时,可以监控到请求的url/QPS(每秒查询率)/响应时间/流量
10.3.2 代码**/**配置实现
1. 修改 member-service-nacos-provider-10004 的 pom.xml, 引入 alibaba-sentinel
1 | <!-- 引入alibaba-sentinel starter --> |
2. 修改 member-service-nacos-provider-10004 的 application.yml
1 | server: |
3. 成功启动后, netstat -anb 可以查看到该端口.
10.3.3 测试
10.3.3.1 启动 Nacos Server 8848
10.3.3.2 启动 Sentinel8080 控制台 / Sentinel dashboard
10.3.3.3 启动 member-service-nacos-provider-10004
10.3.3.4 浏览器: localhost:10004/member/get/1
10.3.3.5 Sentinel 控制台监控页面
1. 浏览器输入**: http://localhost:10004/member/get/1**
2. 进入到 Sentinel 查看实时监控效果, http://localhost:8080/#/dashboard
10.3.4 注意事项和细节
10.3.4.1 QPS: Queries Per Second(每秒查询率),是服务器每秒响应的查询次数
10.3.4.2 Sentinel采用的是懒加载,只有调用了某个接口/服务,才能看到监控数据
10.4 Sentinel流量控制
10.4.1 规则
1. 先看一张图
- 对上图的解读
资源名:唯一名称,默认请求路径
针对来源:Sentine可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
阈值类型/单机阈值:
- QPS(每秒钟的请求数量):当调用该 api 的 QPS 达到阈值的时候,进行限流
- 线程数:当调用该 api 的线程数达到阈值的时候,进行限流
解读: QPS和线程数的区别,注意听,比如 QPS和线程我们都设置阈值为1
(1)对QPS而言,如果在1秒内,客户端发出了2 次请求,就达到阈值,从而限流
(2)对线程数而言,如果在1秒内,客户端发出了2 次请求,不一定达到线程限制的國值,为什么呢?假设我们1 次请求后台会创建一个线程,但是这个请求完成时间是 0.1 秒(可以视为该请求对应的线程存活 0.1 秒),所以当客户端第2 次请求时(比如客户端是在0.3秒发出的),这时第 1个请求的线程就己经结束了,因此就没有达到线程的闻值,也不会限流。
(3)小伙伴可以这样理解,如果1个请求对应的线程平均执行时间为 0.1 那么,就相当于 QPS 为 10
是否集群:不需要集群
流控模式:
- 直接:api 达到限流条件时,直接限流
- 关联:当关联的资源达到闻值时,就限流自己
- 链路:当从某个接口过来的资源达到限流条件时,开启限流
流控效果:
- 快速失败:直接失败,抛异常
- Warm Up:根据 code Factor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的 QPS 阈值
- 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为 QPS, 否则无效
10.4.2 流量控制实例**-QPS**
10.4.2.1 需求分析/图解
1. 需求**:** 通过 Sentinel 实现 流量控制
2. 当调用 member-service-nacos-provider-10004 的 /member/get/ **API **时,限制 1秒内最多访问 1 次,否则直接失败,抛异常
10.4.2.2 配置实现步骤
1. 为**/member/get/1** 增加流控规则
2. 在流控规则菜单,可以看到新增的流控规则
10.4.2.3 测试
10.4.2.3.1 启动 Nacos Server 8848
10.4.2.3.2 启动 Sentinel8080 控制台**/Sentinel dashboard 10.4.2.3.3** 启动 **member-service-nacos-provider-10004 **
10.4.2.3.4 浏览器**: localhost:10004/member/get/1 **
10.4.2.3.5 Sentinel 控制台监控页面
1. 浏览器输入**: http://localhost:10004/member/get/1 , 1** 秒钟内访问次数不超过 1 次**,** 页 面显示正常
2. 浏览器输入:http://localhost:10004/member/get/1 ,1秒钟内访问次数超过1次, 页面出现错误提示
10.4.2.4 注意事项和细节
1. 流量规则改动,实时生效,不需重启微服务 , Sentinel 控制台
为什么?因为sentinel中规则一发生改动,就会将信息push到微服务主机监听sentinel服务的进程
2. 在 sentinel 配置流量规则时,如何配置通配符问题, 比如 /member/get/1 /member/get/2 统一使用一个规则
- 方案1: 在sentinel中 /member/get?id=1 和 /member/get?id=2 被统一认为是**/member/get** 所以只要对/member/get 限流就OK了. (将要携带的参数放在载荷而不是路径中)
1 |
|
访问:http://localhost:10004/member/get?id=3
- 方案2: URL资源清洗
可以通过 UrlCleaner 接口来实现资源清洗,也就是对于/member/get/{id}这个 URL,我们可以统一归集到/member/get/*资源下,具体配置代码如下,实现 UrlCleaner 接口,并重写 clean 方法即可
1 | //添加代码: |
3. 如果 sentinel 流控规则没有持久化,当我们重启调用 API 所在微服务模块后,规则会丢失,需要重新加入
10.4.3 流量控制实例**-**线程数
10.4.3.1 需求分析/图解
1. 需求**:** 通过 Sentinel 实现 流量控制
2. 当调用 member-service-nacos-provider-10004 的 /member/get/* API 时,限制只有一个工作线程,否则直接失败,抛异常**.**
10.4.3.2 配置实现步骤
1. 为**/member/get/*** 增加流控规则
2. 在流控规则菜单,可以看到新增的流控规则
10.4.3.3 测试
10.4.3.3.1 启动 Nacos Server 8848
10.4.3.3.2 启动 Sentinel8080 控制台**/Sentinel dashboard **
10.4.3.3.3 启动 **member-service-nacos-provider-10004 **
10.4.3.3.4 浏览器**: localhost:10004/member/get/1 **
10.4.3.3.5 结果页面
1. 浏览器输入**: http://localhost:10004/member/get/1 ,** 快速刷新**,** 页面显示正常**(原因是服务执行时间很短,刷新下一次的时候,启动的工作线程,已经完成)**
2. 为了看到效果,我们修改下com/hspedu/springcloud/controller/MemberController.java
1 | //让它睡眠一下 |
3. 重启 member-service-nacos-provider-10004 , 注意需要重新加入流控规则.
4. 浏览器输入: http://localhost:10004/member/get/1 , 快速刷新, 页面出现异常
10.4.3.4 注意事项和细节
1. 当我们请求一次微服务的 API 接口时,后台会启动一个线程
2.阈值类型 QPS 和 线程数的区别讨论
- 如果一个线程平均执行时间为0.05秒,就说明在1秒钟,可以执行20次(相当于 QPS为20)
- 如果一个线程平均执行时间为1秒,说明1秒钟,可以执行1次(相当于 QPS为1)
- 如果一个线程平均执行时间为2秒,说明2秒钟内,才能执行1次请求
10.4.4 流量控制实例**-**关联
10.4.4.1 关联的含义
10.4.4.1.1 当关联的资源达到阈值时,就限流自己
10.4.4.2 需求分析/图解
1. 需求**:** 通过 Sentinel 实现 流量控制
2. 当调用 member-service-nacos-provider-10004 的 /t2 API 接口时,如果 QPS 超过 1,这时调用 /t1 API 接口 直接失败,抛异常**.**
梳理: /t2 是关联的资源 , 限流的资源是**/t1**
1 |
|
10.4.4.3 配置实现步骤
1. 为**/t1** 增加流控规则
2. 在流控规则菜单,可以看到新增的流控规则
10.4.4.4 测试
10.4.4.4.1 启动 Nacos Server 8848
10.4.4.4.2 启动 Sentinel8080 控制台**/Sentinel dashboard**
10.4.4.4.3 启动 **member-service-nacos-provider-10004 **
10.4.4.4.4 「Postman模拟高并发访问**/t2**」
1. 创建新的 http request
2. 保存 request 到 一个新的 collection 中
3. 设置 run collection 参数, 并运行
4. 浏览器访问: http://localhost:10004/t1
10.4.4.4.5 浏览器: localhost:10004/t1
1. 浏览器访问 http://localhost:10004/t1 的结果页面
10.4.4.5 注意事项和细节
10.4.4.5.1 在 postman 执行 高并发访问 /t2 没有结束时, 去访问 /t1 才能看到流控异常出现
10.4.5 流量控制实例**-Warm up**
10.4.5.1 Warm up 介绍
1. 概述
- 当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长 一些。即如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的 增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启动, 预热)模式就是为了实现这个目的的。
- 这个场景主要用于启动需要额外开销的场景,例如建立数据库连接等
2. 一张图
- 通常冷启动的过程系统允许通过的 QPS 曲线图(上图)
- 默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值
- 这里的threshold 就是最终要达到的QPS阈值.
10.4.5.1.1 文 档 :
https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8
10.4.5.1.2 默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值
10.4.5.1.3 Warm up 称为 冷启动**/**预热
10.4.5.1.4 应用场景**:** 秒杀在开启瞬间,大流量很容易造成冲垮系统,Warmup 可慢慢的把流量放入,最终将阀值增长到设置阀值
10.4.5.2 需求分析/图解
1. 需求**:** 通过 Sentinel 实现流量控制**,**演示 Warm up
2. 调用 member-service-nacos-provider-10004 的 /t2 API 接口,将 QPS 设置为 9, 设置 Warm up 值为 3
4. 含义为 请求 /t2 的 QPS 从 threshold / 3( 9 /3 = 3) 开始,经预热时长**(3** 秒**)逐渐升至 设定的 QPS 阈值(9)**
5. 为什么是 9 / 3, 这个是 3 就是默认冷启动启动加载因子 coldFactor=3
6. 测试预期效果**:** 在前 3 秒,如果访问 /t2 的 QPS 超过 3, 会直接报错,在 3 秒后 访问 /t2 的 QPS 超过 3, 小于等于 9, 是正常访问
10.4.5.3 配置实现步骤
1. 为**/t2** 增加流控规则
2. 在流控规则菜单,可以看到新增的流控规则
10.4.5.4 测试
10.4.5.4.1 启动 Nacos Server 8848
10.4.5.4.2 启动 Sentinel8080 控制台**/Sentinel dashboard **
10.4.5.4.3 启动 **member-service-nacos-provider-10004 **
10.4.5.4.4 浏览器**: localhost:10004/t2**
1. 浏览器访问 http://localhost:10004/t2 快速刷新页面,在前 3 秒,会出现流控异常, 后 3 秒就正常了**(如果你刷新非常快 QPS>9 , 仍然会出现流控异常)**
10.4.5.5 注意事项和细节
10.4.5.5.1 测试 Warm up 效果不是很好测,如果出不来可以尝试,调整流控规则**:** 比如 QPS 为 **11, Warm up 预热时间 **6 秒
10.4.5.5.2 如果请求停止**(即:** 一段时间没有达到阈值**), Warm up** 过程将重复**,** 小伙伴可以理解是一个弹性过程
10.4.6 流量控制实例**-**排队
10.4.6.1 排队 介绍
1. 排队方式:这种方式严格控制了请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法
2. 一张图
3. 这种方式主要用于处理间隔性突发的流量,例如消息队列。比如这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。-类似前面说的削峰填谷
4. 匀速排队,阈值必须设置为QPS
10.4.6.2 需求分析/图解
1. 需求**:** 通过 Sentinel 实现 流量控制**-排队
2. 调用 member-service-nacos-provider-10004 的 /t2 API 接口,将 QPS 设置为 1 **
3. 当调用 /t2 的 QPS 超过 1 时,不拒绝请求,而是排队等待, 依次执行
4.当等待时间超过 10 秒,则为等待超时——等待超时就不要了
10.4.6.3 修改业务类
1. 为了测试看到效果,修改 com/hspedu/springcloud/controller/MemberController.java
1 |
|
10.4.6.4 配置实现步骤
1. 为**/t2** 增加流控规则
2. 在流控规则菜单,可以看到新增的流控规则
10.4.6.5 测试
10.4.6.5.1 启动 Nacos Server 8848
10.4.6.5.2 启动 Sentinel8080 控制台**/Sentinel dashboard **
10.4.6.5.3 启动 **member-service-nacos-provider-10004 **
10.4.6.5.4 浏览器**: localhost:10004/t2**
1. 浏览器访问 http://localhost:10004/t2 快速刷新页面 9 次,观察前台**/**后台输出的情况
输出结果分析:没有报错误,后台请求排队执行,每隔1s匀速执行
2. 浏览器访问 http://localhost:10004/t2 快速刷新页面20次,当请求等待时间超过10S, 仍然出现流控异常
10.5 Sentinel熔断降级
10.5.1 线程堆积引出熔断降级
1. 一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。
2. 例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需 要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现 了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用
3. 这时,我们对不稳定的服务进行熔断降级,让其快速返回结果,不要造成线程堆积
10.5.2 文档地址**: https://sentinelguard.io/zh-cn/docs/circuit-breaking.html**
10.5.3 基本介绍
1. 一张图
2. 解读上图:
- 现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。
- 链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。
- 因此需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩
3. 熔断,降级,限流三者的关系
熔断:强调的是服务之间的调用能实现自我恢复的状态
限流:是从系统的流量入口考虑, 从进入的流量上进行限制**, **达到保护系统的作用
降级:是从系统业务的维度考虑,流量大了或者频繁异常, 可以牺牲一些非核心业务,保护核心流程正常使用
-熔断是降级方式的一种
-降级又是限流的一种方式
-三者都是为了通过一定的方式在流量过大或者出现异常时,保护系统的手段
10.5.4 熔断策略
10.5.4.1 慢调用比例
1、慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用
2、当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断
3、熔断时长后,熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用RT则结束熔断,若大于设置的慢调用RT 则会再次被熔断
4、配置参考
10.5.4.2 异常比例
1、异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断
2、经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN状态)
3、若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断
4、异常比率的阈值范围是[0.0, 1.0],代表0% - 100%
5、配置参考
6、工作示意图
10.5.4.3 异常数
1、异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断
2、经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态)
3、若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断
4、配置参考
10.5.5 熔断降级实例**-**慢调用比例
10.5.5.1 需求分析/图解
1. 需求**:** 通过 Sentinel 实现 熔断降级控制**-**慢调用比例
2. 当调用 member-service-nacos-provider-10004 的 /t3 API 接口时,如果在 1s 内持续进入了 5 个请求,并且请求的平均响应时间超过 200ms, 那么就在未来 10 秒钟内,断路器打开, 让 /t3 API 接口微服务不可用
3. 后面对/t3 API 接口访问降到 1S 内 1 个请求,降低访问量了,断路器关闭,微服务恢复
10.5.5.2 修改业务类
1. 修改 com/hspedu/springcloud/controller/MemberController.java 增加方法 t3()
1 |
|
10.5.5.3 配置实现步骤
1. 为**/t3** 增加降级规则
2. 在流控规则菜单,可以看到新增的降级规则
10.5.5.4 测试
10.5.5.4.1 启动 Nacos Server 8848
10.5.5.4.2 启动 Sentinel8080 控制台**/Sentinel dashboard **
10.5.5.4.3 启动 member-service-nacos-provider-10004
10.5.5.4.4 Postman测试
1. 先创建 collection , 也可以在已经存在的 collection 进行修改
…………
10.5.5.5 注意事项和细节
10.5.5.5.1 平均响应时间超出阈值且在 1s 内通过的请求**>=5**, 两个条件同时满足后触发降级
10.5.5.5.2 熔断时间过后,关闭断路器,访问恢复正常
10.5.6 熔断降级实例-异常比例
10.5.6.1 需求分析/图解
1. 需求**:** 通过 Sentinel 实现 熔断降级控制
2. 当调用 member-service-nacos-provider-10004 的 /t4 API 接口时,当资源的每秒请求量**>=5,并且每秒异常总数占通过量的比值超过20%(即异常比例到20%),** 断路器打开**(即:** 进入降级状态**),** 让 /t4 API 接口微服务不可用
3. 当对**/t4 API** 接口 访问降到 1S 内 1 个请求,降低访问量了,断路器关闭,5 秒后微服务恢复
10.5.6.2 修改业务类
1. 修改 com/hspedu/springcloud/controller/MemberController.java 增加方法 t4()
1 | private static int num = 0; |
10.5.6.3 配置实现步骤
1. 为**/t4** 增加降级规则
2. 在流控规则菜单,可以看到新增的降级规则
10.5.6.4 测试
10.5.6.4.1 启动 Nacos Server 8848
10.5.6.4.2 启动 Sentinel8080 控制台/Sentinel dashboard
10.5.6.4.3 启动 member-service-nacos-provider-10004
10.5.6.4.4 Postman测试
1. 先创建给 collection , 也可以在已经存在的 collection 进行修改**,** 一定确保更新成功**.**
2. 点击 Run sentinel
3. 浏览器访问: http://localhost:10004/t4 出现 Blocked by Sentinel (flow limiting)
4. 停止 Postman
5. 浏览器访问: http://localhost:10004/t4 , 结果正常了(一次返回异常,一次返回正确结 果)
10.5.7.5注意事项和细节
10.5.7.5.1 资源在 1 分钟的异常数目超过阈值之后会进行熔断降级
10.5.7.5.2 异常数统计是分钟级别的,若 设置的时间窗口 小于 60s,则结束熔断状态后仍可能再进入熔断状态**,** 测试时,最好将时间窗口设置超过 60S
10.6 Sentinel 热点规则
10.6.1 一个问题引出热点 key 限流
1. 热点**:** 热点即经常访问的数据。很多时候我们希望统计热点数据中**,** 访问频次最高的 Top K 数据,并对其访问进行限制。
2. 比如某条新闻上热搜 ,在某段时间内高频访问, 为了防止系统雪崩**,** 可以对该条新闻进行热点限流
10.6.2文档地址 :
https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
10.6.3 基本介绍
1. 一张图
2. 解读上图:
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。
热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控 https://blog.csdn.net/qq_34416331/article/details/106668747
热点参数限流支持集群模式
10.6.4 热点 Key 限流**-**实例
10.6.4.1 需求分析/图解
1. 需求**:** 通过 Sentinel 实现热点 Key 限流
2. 对 member-service-nacos-provider-10004 的 /news?id=x&type=x API 接口进行热点限流
3. 假定 id=10 这一条新闻是当前的热点新闻, 当查询新闻时,对通常的 id(非热点新闻)请求 QPS 限定为 2, 如果 id=10 QPS 限定为 100
4. 如果访问超出了规定的 QPS, 触发热点限流机制, 调用自定义的方法,给出提示信息**. **
5. 当对 /news?id=x&type=x API 接口降低访问量,QPS 达到规定范围**,** 服务恢复
10.6.4.2 修改业务类
1. 修 改 com/hspedu/springcloud/controller/MemberController.java 增 加 方 法 queryNews()
1 | /** |
10.6.4.3 测试
10.6.4.3.1 启动 Nacos Server 8848
10.6.4.3.2 启动 Sentinel8080 控制台/Sentinel dashboard
10.6.4.3.3 启动 member-service-nacos-provider-10004
10.6.4.3.4 配置实现步骤
1. 为资源 news 增加热点规则**,** 注意不是 /news
2. 在热点参数限流规则菜单,可以看到新增规则
10.6.4.3.5 浏览器**: http://localhost:10004/news?id=1&type=%E6%95%99%E8%82%B2**
如果QPS没有超过2,则返回正确结果
如果QPS超过2,则返回热点key处理信息
10.6.4.3.6 独立设置热点 id=10 的 QPS 阈值(即添加例外)
1. 独立设置热点 id=10 的 QPS 阈值**(即添加例外)**
10.6.4.3.7 浏览器: http://localhost:10004/news?id=10&type=%E6%95%99%E8%82%B2
1. 浏览器输入: http://localhost:10004/news?id=10&type=%E6%95%99%E8%82%B2 , 如果QPS没有超过 100,则返回正确结果
2. 浏览器访问的 id 不是10 的,仍然遵守 QPS 不能超过 2 的热点限制
10.6.5 注意事项和细节
10.6.5.1 热点参数类型是(byte/int/long/float/double/char/String)
10.6.5.2 热点参数值,可以配置多个
10.6.5.3 热点规则只对指定的参数生效 (比如本实例对 id 生效, 对 type 不生效)
10.7 系统规则
10.7.1 一个问题引出系统规则
1.如我们系统最大性能能抗 100QPS,如何分配 /t1 /t2 的 QPS?
方案1: /t1 分配 QPS=50;/t2 分配 QPS=50,问题,如果/t1 当前 QPS 达到 50,而/t2 的 QPS 才 10,会造成没有充分利用服务器性能
方案2: /t1 分配 QPS=100 /t2 分配 QPS=100,问题,容易造成系统没有流量保护造成请求线程堆积,形成雪崩
有没有对各个资源请求的QPS弹性设置,只要总数不超过系统最大QPS的流量保护规则?=> 系统规则
10.7.2文 档 地 址 :
10.7.3 一句话**:** 系统规则作用**,** 在系统稳定的前提下,保持系统的吞吐量
10.7.4 基本介绍
1. 一张图
**2.**解读上图:
系统处理请求的过程想象为一个水管,到来的请求是往这个水管灌水,当系统处理顺畅的时候,请求不需要排队,直接从水管中穿过,这个请求的RT是最短的,反之,当请求堆积的时候,那么处理请求的时间则会变为:排队时间 + 最短处理时间
**3.**系统规则(参考以下五种数据来判断系统是否超负荷)
Load 自适应(仅对 Linux/Unix-like 机器生效): 系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores *2.5
CPU usage (1.5.0+ 版本): 当系统 CPU 使用率超过阈值即触发系统保护 (取值范围0.0-1.0),比较灵敏。
平均 RT: 当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
10.7.5 实例
10.7.5.1 需求分析/图解
1.需求: 通过 Sentinel 实现 系统规则**-**入口 QPS
2.对 member-service-nacos-provider-10004 的 所有 API 接口进行流量保护,不管访问哪个 API 接口, 系统入口总的 QPS 不能大于 2, 大于 2,就进行限流控制
3. 提示**:** 上面的 QPS 是为了方便看效果**,** 设置的很小
10.7.5.2 配置实现步骤
1. 增加入口 QPS 系统规则
10.7.5.3 测试
10.7.5.3.1 启动 Nacos Server 8848
10.7.5.3.2 启动 Sentinel8080 控制台/Sentinel dashboard
10.7.5.3.3 启动 member-service-nacos-provider-10004
10.7.5.3.4 浏览器: http://localhost:10004/t1
1. 浏览器输入**: http://localhost:10004/t1 ,** 如果 QPS 超过 2, 打开断路器,返回流控信息
2. 浏览器输入: http://localhost:10004/news?id=1&type=%E6%95%99%E8%82%B2 , 如果QPS 超过2, 打开断路器,返回流控信息(说明: 项目的 /t2 资源对应方法有休眠代码,所以使用 /news?id=x&type=x 测试)
10.8 @SentinelResource
10.8.1 自定义全局限流处理类
10.8.1.1 需求分析/图解
1. 先看前面的一段代码
1 |
|
说明: 当配置的资源名 news 触发限流机制时,会调用 newsBlockHandler 方法
2. 上面的处理方案存在一些问题
每个@SentinelResource 对应一个异常处理方法,会造成方法很多
异常处理方法和资源请求方法在一起,不利于业务逻辑的分离
- 解决方案-> 自定义全局限流处理类
3. 需求: 请编写一个自定义全局限流处理类,完成对异常处理.
10.8.1.2 代码实现
1. 修改 com/hspedu/springcloud/controller/MemberController.java 增加方法 t6()
1 | /** |
2. 创建 com/hspedu/springcloud/handler/CustomGlobalBlockHandler.java
1 | package com.study.springcloud.handler; |
10.8.1.3 配置实现步骤
1. 为资源 /t6 增加流控规则**,**方便测试
2. 在流控规则菜单,可以看到新增规则
10.8.1.4 测试
10.8.1.4.1 启动 Nacos Server 8848
10.8.1.4.2 启动 Sentinel8080控制台/Sentinel dashboard
10.8.1.4.3 启动 member-service-nacos-provider-10004
10.8.1.4.4 浏览器: http://localhost:10004/t6
1. 浏览器输入**: http://localhost:10004/t6 ,** 如果 QPS 没有超过 1, 返回正常结果
2. 浏览器输入: http://localhost:10004/t6 ,如果QPS 超过 1, 断路器打开,返回自定义限流处理方法信息
10.8.2 fallback 自定义程序错误处理
10.8.2.1 看一段代码-引出 fallback
1. 修 改 member-service-nacos-provider-10004 的com/hspedu/springcloud/controller/MemberController.java 增加一段代码**.**
1 |
|
2. 浏览器: http://localhost:10004/t6 , 看效果当num为 5的整数时,返回的是error页面,不友好.
3. 怎么解决=> 使用 fallback
10.8.2.2 基本介绍
10.8.2.2.1 blockHandler只负责sentinel控制台配置违规
10.8.2.2.2 fallback负责Java异常/业务异常
10.8.2.3 需求分析/图解
1. 需求**:** 请编写一个自定义全局 fallback 处理类**,** 处理 java 异常**/**业务异常
2. 也就是解决前面我们提出的问题
10.8.2.4 代码实现
1. 在 member-service-nacos-provider-10004 创建com/hspedu/springcloud/handler/CustomGlobalFallbackHandler.java
1 | public class CustomGlobalFallbackHandler { |
2.在 member-service-nacos-provider-10004修改com/hspedu/springcloud/controller/MemberController.java
1 | /** |
10.8.2.5 测试
10.8.2.5.1 启动 Nacos Server 8848
10.8.2.5.2 启动 Sentinel8080 控制台/Sentinel dashboard
10.8.2.5.3 启动 member-service-nacos-provider-10004
10.8.2.5.4 浏览器: http://localhost:10004/t6
1. 浏览器输入**: http://localhost:10004/t6 ,** 访问次数不是 5 的倍数**,** 返回正常结果
2. 浏览器输入: http://localhost:10004/t6 , 访问次数是 5 的倍数, 返回 fallback指定方法信息
3. 为资源 /t6 增加流控规则,方便测试
4. 在流控规则菜单,可以看到新增规则
5. 浏览器输入: http://localhost:10004/t6 , 如果访问 QPS 大于1 , 由blockHandler指定的方法处理,访问次数是 5 的倍数, 由fallback指定方法处理,其它情况返回正常的结果.
10.8.3 exceptionsToIgnore 希望忽略某个异常
10.8.3.1 如果希望忽略某个异常,可以使用 exceptionsToIgnore
10.8.3.2 应用实例
1. 如果希望忽略某个异常**(支持数组)**,可以使用 exceptionsToIgnore
1 |
|
2. 浏览器输入: http://localhost:10004/t6 , 你会发现访问次数为 5 的倍数时,不再调用 fallback 指定方法处理
而是使用RuntimeException.class中的方式(即默认方式)处理
10.8.4 接入 Sentinel 的方式
即(不进入sentinel控制台网页而使用sentinel)
10.8.4.1 代码方式(硬编码,侵入性强, 不推荐)
1. 文档地址**:** https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
2. 基本使用
10.8.4.2 注解方式(低侵入性, 前面用过, 推荐)
1. 注解方式埋点不支持 private 方法
https://xue.baidu.com/okam/pages/strategy-tp/index?strategyId=136707206360879&source=natural
2. @SentinelResource 用于定义资源,并提供可选的异常处理和fallback配置项。
3. @SentinelResource 注解包含以下属性(我们再梳理一下)
value:资源名称,必需项(不能为空)
entryType:entry 类型,可选项(默认为EntryType.OUT)
blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项blockHandler函数访问范围需要是public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其 他类的函数,则可以指定blockHandlerClass为对应的类的Class对象,注意对应的函数必需为 static 函数,否则无法解析。
fallback / fallbackClass:fallback 函数名称,可选项,用于在抛出异常的时候提供fallback处理逻辑。fallback函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:
- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要和原函数一致,或者可以额外多一个Throwable类型的参数用于接收对应的异常。
- fallback函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定fallbackClass为对应的类的Class对象,注意对应的函数必需为static函数,否则无法解析。
- defaultFallback(since 1.6.0):默认的 fallback函数名称,可选项,通常用于通用的fallback逻辑(即可以用于很多服务或方法)。默认fallback函数可以针对所有类型 的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。若同时配置了fallback和defaultFallback,则只有fallback会生效。defaultFallback 函数签名要求:
- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要为空,或者可以额外多一个Throwable类型的参数用于接收对应的异常。
- defaultFallback函数默认需要和原方法在同一个类中。若希望使用其他类的函数, 则可以指定fallbackClass为对应的类的Class对象,注意对应的函数必需为static函数,否则无法解析。
- exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会进入异常统计中,也不会进入fallback逻辑中,而是会原样抛出。
10.9 openFeign+sentinel 对远程调用熔断降级
10.9.1 当前微服务基础环境
10.9.1.1 当前微服务环境架构图
– 示意图
10.9.1.2 测试
10.9.1.2.1 启动 Nacos Server 8848
10.9.1.2.2 启动 member-service-nacos-provider-10004/10006
10.9.1.2.3 启动 member-service-nacos-consumer-80
10.9.1.2.4 浏览器**: http://localhost/member/nacos/consumer/get/1**
1. 浏 览 器 输 入 : http://localhost/member/nacos/consumer/get/1 , 目 前 是 Ribbon+RestTemplate
10.9.2 服务消费者整合 Openfeign
1. 需求:在 member-service-nacos-consumer-80 整合 Openfeign 实现远程调用
10.9.2.2 代码+配置实现步骤
1. 修改 member-service-nacos-consumer-80 的 pom.xml 加入 openfeign 依赖
1 | <!-- 引入openfeign-start,即场景启动器 --> |
2. 在 member-service-nacos-consumer-80 创 建com/study/springcloud/service/MemberOpenFeignService.java
1 | package com.study.springcloud.service; |
3. 在 member-service-nacos-consumer-80 修改 com/study/springcloud/controller/MemberNacosConsumerController.java 增加方法getMemberOpenfeignById()
1 |
|
4. 再在 member-service-nacos-consumer-80 的主启动类加入注解 com/hspedu/springcloud/MemberNacosConsumerApplication80.java
「@EnableFeignClients」
10.9.2.3 测试
10.9.2.3.1 启动 Nacos Server 8848
10.9.2.3.2 启动 **member-service-nacos-provider-10004/10006 **
10.9.2.3.3 启动 member-service-nacos-consumer-80
10.9.2.3.4 浏览器**: http://localhost/member/openfeign/consumer/get/1**
1. 浏览器输入**: http://localhost/member/openfeign/consumer/get/1 , 目前是 Openfeign 调用(负载均衡)**
10.9.3 服务消费者整合 Sentinel
10.9.3.1 需求分析/图解
1. 需求:在 member-service-nacos-consumer-80 整合 Sentinel 能被 Sentinel 监控
10.9.3.2 代码+配置实现步骤
1. 修改 member-service-nacos-consumer-80 的 pom.xml 加入 sentinel 依赖
1 | <!-- 引入 alibaba-sentinel --> |
2. 修改 member-service-nacos-consumer-80 的 application.yml 配置 sentinel
1 | server: |
10.9.3.3 测试
10.9.3.3.1 启动 Nacos Server 8848
10.9.3.3.2 启动 Sentinel8080 控制台/Sentinel dashboard
10.9.3.3.3 启动 **member-service-nacos-provider-10004/10006 **
10.9.3.3.4 启动 member-service-nacos-consumer-80
10.9.3.3.5 浏览器**: http://localhost/member/openfeign/consumer/get/1**
1. 浏览器输入**: http://localhost/member/openfeign/consumer/get/1 ,** 目前是 Openfeign 调用**(负载均衡)**
2. 登录 sentinel 控制台: 可以看到已经监控到 member-service-nacos-consumer
10.9.4 openFeign+sentinel 对远程调用熔断降级
10.9.4.1 需求分析/图解
1. 需求**/如图:在 member-service-nacos-consumer-80 调用某个无效服务时,启动 Sentinel 的熔断降级机制 , 能够快速返回响应,而不是使用默认的超时机制(因为超时机制容易线程堆积,** 从而导致雪崩)
2. 先测试一下,关闭 10004/10006, 这时 openfeign 去调用会怎么样? (返回 time out)
3. 还可以测试一下,让 10004 服务对应的 API 执行时间很长(比如休眠 2 秒), 这 时 openfeign 去调用会怎么样?
10.9.4.2 代码+配置实现步骤
1. 修 改 member-service-nacos-consumer-80 的
com/hspedu/springcloud/service/MemberOpenFeignService.java, 加入 fallback 的处理类
1 | package com.study.springcloud.service; |
2. 创建 com/hspedu/springcloud/service/MemberFeignFallbackService.java
1 | package com.study.springcloud.service; |
3. 修改 member-service-nacos-consumer-80 的 application.yml , 加入 openfeign 和 sentinel 整合配置
1 | 末尾添加以下: |
10.9.4.3 测试
10.9.4.3.1 启动 Nacos Server 8848
10.9.4.3.2 启动 Sentinel8080 控制台/Sentinel dashboard
10.9.4.3.3 关闭 **member-service-nacos-provider-10004/10006 **
10.9.4.3.4 启动 member-service-nacos-consumer-80
10.9.4.3.5 浏览器**: http://localhost/member/openfeign/consumer/get/1**
1. 浏览器输入**: http://localhost/member/openfeign/consumer/get/1 ,** 目前是 Openfeign 调用**(负载均衡)**
10.9.4.4 注意事项和细节说明
1. 因为 member-service-nacos-consumer-80 已经被 sentinel 监控,所以我们可以加入相
关的流控规则**,** 比如为 /member/openfeign/consumer/get/1 加入流控规则 qps = 1
测试: 如果/member/openfeign/consumer/get/1 请求 QPS 超过 1, 会输出Blocked by Sentinel (flow limiting)
QPS 没有超过 1, 会被 fallback 处理
2. 如果远程服务恢复正常, 又会正常调用.
10.10 规则持久化
10.10.1 规则没有持久化的问题
10.10.1.1 如果 sentinel 流控规则没有持久化,当重启调用 API/接口 所在微服务后,规则就会丢失,需要 重新加入
10.10.1.2 解决方案:通过 Nacos 进行持久化
10.10.2 规则持久化方案
10.10.2.1 阿里云 Ahas[最方便/付费]
1. 官方文档 : https://help.aliyun.com/product/87450.html?spm=5176.cnahas.0.0.78034bb7ef0y86
10.10.2.2 🌟在 Nacos Server 配置规则, 完成持久化 -官方推荐
10.10.2.3 将规则持久化到本地文件, 定时同步
10.10.2.4 其它…
10.10.3 Nacos Server 配置中心**-**规则持久化实例
10.10.3.1 工作原理示意图
其实就是靠把规则保存到nacos中,下次重启服务时再从nacos中获取先前设置的规则信息
10.10.3.2 需求分析/图解
1. 需 求 : 为 member-service-nacos-consumer-80 微服务的**/member/openfeign/consumer/get/1 API** 接口添加流控规则 **QPS=1/**快速失败 .
2. 要求将该流控规则加入到 nacos server 配置中心,实现持久化
10.10.3.3 代码+配置实现步骤
1. 在 Nacos Server 配置中心增加 Sentinel 客户端**/**微服务模块的流控规则
1 | [ |
2. 在 Nacos Server 配置中心增加 Sentinel 客户端/微服务模块的流控规则参数说明
- resource ∶ 资源名称;
- limlitApp ∶ 来源应用;
- **grade **∶ 阈值类型,0 表示线程数,1 表示QPS;
- count ∶ 单机阈值;
- **strategy **∶ 流控模式,0 表示直接,1 表示关联,2 表示链路;
- **controlBehavior **∶ 流控效果,0 表示快速失败,1 表示Warm Up,2 表示排队等待;
- **clusterMode **∶ 是否集群
3. 修改 member-service-nacos-consumer-80 的 pom.xml, 加入 sentinel 和 nacos 持久化整合依赖
1 | <!-- 加入 sentinel 和 nacos 持久化整合依赖 --> |
4. 修改 member-service-nacos-consumer-80的application.yml , 配置该微服务从Nacos Server获取流控规则
1 | # 在原本的基础上添加以下代码: |
10.10.3.4 测试
10.10.3.4.1 启动 Nacos Server 8848
10.10.3.4.2 启动 Sentinel8080 控制台/Sentinel dashboard
10.10.3.4.3 启动 **member-service-nacos-provider-10004/10006 **
10.10.3.4.4 启动 member-service-nacos-consumer-80
10.10.3.4.5 浏览器**: http://localhost/member/openfeign/consumer/get/1**
1. 浏览器输入**: http://localhost/member/openfeign/consumer/get/1 ,** 目前是 Openfeign 调用**(负载均衡),** 而且流控规则已经生效了.
2. 查看 Sentinel 控制台,发现已经同步了流控规则
10.10.3.5 注意事项和细节
1. 在 nacos server 配置 sentinel 流控规则的 Data ID 也可以自己指定,比如写成 hsp-id, 只要在 **sentinel client/**微服务 的 applicaion.yml 的 datasource.ds1.nacos.dataId 的值保持一致即可
2. 如图所示
11 SpringCloud Alibaba Seata全局事务
全局事务——保证一个牵扯修改多个数据库的操作由于意外情况导致数据库中数据不一致的情况
11.1 Seata基础
11.1.1 先看一个问题,引出 Seata
1. 单机单库**(多表)**处理事务示意图
2. 分布式微服务架构下的数据库事务示意图(RPC,远程过程调用)
3. 梳理上图
用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持∶
- 仓储服务∶对给定的商品扣除仓库/商品数量
- 订单服务;根据采购需求创建订单
- 帐户服务∶从用户帐户中扣除余额
4. 问题分析
单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源
业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证
但是全局的数据—致性问题没法保证
简单的说: 一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题—–
——->seata
11.1.2 分布式事务问题**&**解决方案
11.1.2.1 分布式微服务架构下的全局数据一致性问题 [即: 分布式事务问题]
11.1.2.2 解决方案: Seata
11.1.3 官网
11.1.3.1 http://seata.io/zh-cn/
11.1.3.2 使用手册: https://seata.io/zh-cn/docs/overview/what-is-seata.html
11.1.4 Seata是什么?
Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务
11.2 🌟Seata 工作机制/返讲
11.2.1 分布式事务过程分析
1. Seata 分布式事务处理过程-ID+三组件模型
2. 一图胜千言
上图展示了一个分布式事务在Seata的处理过程
- Transaction ID XID:全局唯一的事务ID
- Transaction Coordinator(TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚
- Transaction Manager(TM): 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议;
- Resource Manager(RM):控制分支事务,负责分支注册,状态汇报,并接收事务协调器的指令,驱动分支 (本地)事务的提交和回滚
执行过程
- TM向 TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID
- XID在微服务调用链路的上下文中传播
- RM 向 TC注册分支事务,将其纳入 XID 对应全局事务的管辖
- TM 向 TC 发起针对 XID 的全局提交或回滚决议。
- TC 调度 XID下管辖的全部分支事务完成提交或回滚请求
11.2.2 Seata 事务模式
1. 地址: https://seata.io/zh-cn/docs/overview/what-is-seata.html
11.2.2.1 AT(默认模式)
11.2.2.2 TCC
11.2.2.3 SAGA
11.2.2.4 XA
11.2.3 AT无侵入模式
11.2.3.1 文档: https://seata.io/zh-cn/docs/overview/what-is-seata.html
11.2.3.2 一阶段加载
在一阶段,Seata 会拦截**”**业务 SQL”
解析 SQL 语义,找到“业务SQL”要更新的业务数据,在业务数据被更新前,将其保存成”before image”(前罝镜像)
执行”业务 SQL”更新业务数据,在业务数据更新之后,其保存成”after image” /后置镜像
最后生成行锁
以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性
其中,前像与后像存于undo_log数据表中
11.2.3.3 二阶段提交
1. 二阶段如果是顺利提交
2. 因为”业务 SQL”在一阶段已经提交至数据库,所以 Seata 框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可
11.2.3.4 二阶段回滚
二阶段如果是回滚的话,seata 就需要回滚一阶段己经执行的“业务 SQL”‘,还原业务数据。
回滚方式便是用”before image”还原业务数据;但在还原前要首先要校验脏号,对比”数据库当前业务数据”和”after image 如果两份数据完全一致就说明没有脏写,可以还原业务数据
如果不一致就说明有脏写,出现脏写就需要转人工处理
11.2.4 AT事务模式Debug验证
11.2.5 SEATA的分布式交易解决方案
11.3 SeataServer安装
11.3.1 下载
11.3.1.1 https://github.com/seata/seata/releases/tag/v0.9.0
11.3.2 安装和配置
1. 将 seata-server-0.9.0.zip 解压到 指定目录,比如 d:\program
2. 修改 conf\file.conf 文件:
1 | transport { |
3. 在 mysql5.7 创建 seata 数据库
4. 修改 seata 的 \conf\registry.conf , 配置注册中心 nacos server
1 | registry { |
11.3.3 启动
11.3.3.1 启动 Nacos Server 8848
11.3.3.2 双击 Seata 的\bin\seata-server.bat , 启动 Seata Server
1. 启动 seata-server.bat , 看到如下界面说明成功
1 | cd /Applications/seata/bin |
11.3.3.3 登录 Nacos Server , 查看 Seata Server 是否注册成功
11.4 Seata 分布式事务-应用实例
11.4.1 需求分析**/**图解
1. 需求:完成下订单功能,由三个微服务模块协同完成**,** 涉及到多数据库**,** 多张表
11.4.2 创建数据库和表
1. 创建业务数据库和表
1 | -- 订单微服务的数据库 |
2. 分别为 3 库创建对应的回滚日志表**,** 说明回滚日志表在 seata 的 \conf\db_undo_log.sql
1 | use order_micro_service |
11.4.3 开发 seata_storage_micro_service-10010 微服务
1. 参考以前的方式,创建 seata_storage_micro_service-10010 微服务模块
2. 修改 pom.xml, 添加相关的 jar 依赖
1 | <dependencies> |
3. 创建 application.yml, 进行相关的配置
1 | server: |
4. 创建 file.conf, 进行相关的配置, 说明:该文件从 seata 的\conf\file.conf 拷贝,进行修改即可
5. 创建 com/hspedu/springcloud/entity/Storage.java
1 | package com.study.springcloud.entity; |
6. 创建 com/hspedu/springcloud/dao/StorageDao.java
1 |
|
7. 创建 **resources/**mapper/StorageMapper.xml
1 |
|
8. 创建 com/hspedu/springcloud/service/StorageService.java
1 | public interface StorageService { |
9. 创建 com/hspedu/springcloud/service/impl/StorageServiceImpl.java
1 |
|
10. 创建 com/hspedu/springcloud/controller/StorageController.java
1 |
|
11. 创建 com/hspedu/springcloud/config/MyBatisConfig.java
1 |
|
12. 创建com/hspedu/springcloud/config/DataSourceProxyConfig.java ,常规配置(拿来使用即可)
1 | package com.study.springcloud.config; |
13. 创 建 主 启 动 类 com/hspedu/springcloud/SeataStorageMicroServiceApplication10010.java
1 | package com.study.springcloud; |
11.4.4 测试 seata_storage_micro_service-10010 微服务
11.4.4.1 启动 Nacos Server 8848
11.4.4.2 双击 Seata 的\bin\seata-server.bat , 启动 Seata Server
11.4.4.3 启动 seata_storage_micro_service-10010
11.4.4.4 登录 Nacos Server , 查看 10010 微服务是否注册成功
1. 登录 Nacos Server, 查看 10010 是否注册成功
11.4.5 开发 seata_account_micro_service-10012 微服务
(account模块,参照上面storage模块的创建过程即可)
1. 参考以前的方式,创建 seata_account_micro_service-10012 微服务模块
2. 修改 pom.xml, 添加相关的 jar 依赖
3. 创建 application.yml, 进行相关的配置
4.1 创建 file.conf, 进行相关的配置, 说明:该文件从 seata 的\conf\file.conf 拷贝,进行修 改即可
4.2 创建 registry.conf, 进行相关的配置, 说明:该文件从 seata 的\conf\registry.conf 拷贝, 进行修改即可
5. 创建 com/hspedu/springcloud/entity/Account.java
6. 创建 com/hspedu/springcloud/dao/AccountDao.java
7. 创建 **resources/**mapper/AccountMapper.xml
8. 创建 com/hspedu/springcloud/service/AccountService.java
9. 创建 com/hspedu/springcloud/service/impl/AccountServiceImpl.java
10. 创建 com/hspedu/springcloud/controller/AccountController.java
11. 创建 com/hspedu/springcloud/config/MyBatisConfig.java
12. 创建 com/hspedu/springcloud/config/DataSourceProxyConfig.java , 常规配置(拿来使用即可)
13. 创 建 主 启 动 类 com/hspedu/springcloud/SeataAccountMicroServiceApplication10012.java
11.4.6 测试 seata_account_micro_service-10012 微服务
11.4.6.1 启动 Nacos Server 8848
11.4.6.2 双击 Seata 的\bin\seata-server.bat , 启动 Seata Server
11.4.6.3 启动 seata_account_micro_service-10012
11.4.6.4 登录 Nacos Server , 查看 10012 微服务是否注册成功
1. 登录 Nacos Server, 查看 10012 是否注册成功
11.4.7 开发 seata-order-micro-service-10008 微服务
(Order模块,参照上面storage模块的创建过程即可)
1. 参考以前的方式,创建 seata-order-micro-service-10008 微服务模块
2. 修改 pom.xml, 添加相关的 jar 依赖
3. 创建 application.yml, 进行相关的配置
4.1 创建 file.conf, 进行相关的配置, 说明:该文件从 seata 的\conf\file.conf 拷贝,进行修 改即可
4.2 创建 registry.conf, 进行相关的配置, 说明:该文件从 seata 的\conf\registry.conf 拷贝, 进行修改即可
5. 创建 com/hspedu/springcloud/entity/Order.java
6. 创建 com/hspedu/springcloud/dao/OrderDao.java
7. 创建 **resources/**mapper/OrderMapper.xml
8. 创建 com/hspedu/springcloud/service/OrderService.java
9. 创建 com/hspedu/springcloud/service/AccountService.java
10. 创建 com/hspedu/springcloud/service/impl/OrderServiceImpl.java
11. 创建 com/hspedu/springcloud/controller/OrderController.java
12. 创建 com/hspedu/springcloud/config/MyBatisConfig.java
13. 创建 com/hspedu/springcloud/config/DataSourceProxyConfig.java , 常规配置(拿来使用即可)
14. 创 建 主 启 动 类 com/hspedu/springcloud/SeataOrderMicroServiceApplication10008.java
11.4.8 测试 seata-order-micro-service-10008 微服务
……
11.4.9 集成测试**(1)** 三个微服务协同完成**-**正常下单
11.4.9.1 启动 Nacos Server 8848
11.4.9.2 双击 Seata 的\bin\seata-server.bat , 启动 Seata Server
11.4.9.3 启动 seata-order-micro-service-10010 /10012/10008 三个微服务
11.4.9.4 浏览器 : http://localhost:10008/order/save?userId=666&productId=1&nums=1&money=100
1. 浏 览 器 : http://localhost:10008/order/save?userId=666&productId=1&nums=1&money=100
2. 查看数据库/表的情况是否正常,结论:如果没有异常出现,正常下单,数据库三张表 数据一致性是OK的
11.4.9.5 注意事项和细节
1. MySQL 出现 too many connections(1040)错误解决方法:
在 my.ini 设置
max_connections=1000
2. 如果出现**: service id not legal hostname
** 报错 Service id not legal hostname 的原因是服务名称不能带有下划线,可以使用中划线**,**
springcloud 无法识别下划线,把下划线改成中划线就好
11.4.10 集成测试**(2)** 三个微服务协同完成**-**模拟异常
11.4.10.1 启动 Nacos Server 8848
11.4.10.2 双击 Seata 的\bin\seata-server.bat , 启动 Seata Server
11.4.10.3 启动 seata-order-micro-service-100010 /10012/10008 三个微服务
11.4.10.4 浏览器 : http://localhost:10008/order/save?userId=666&productId=1&nums=1&money=100
1. 修 改 seata_account_micro_service-10012 的com/hspedu/springcloud/controller/AccountController.java, 模拟异常出现
1 |
|
2. 浏 览 器 : http://localhost:10008/order/save?userId=666&productId=1&nums=1&money=100
3. 查看数据库/表的情况是否正常
结论:这时数据库/表,出现数据不一致现象, 订单是未支付,但是库存减少了,账号钱也扣了(提示:等休眠时间完成后,再查看account表,会看到数据不一致)
11.4.11 集成测试**(3)** 三个微服务协同完成**-使用@GlobalTransactional** 完成分布式事务控制(出现异常,也能保证数据一致性)
11.4.11.1 启动 Nacos Server 8848
11.4.11.2 双击 Seata 的\bin\seata-server.bat , 启动 Seata Server
11.4.11.3 启动 seata-order-micro-service-10008 /10010/10012 三个微服务
11.4.11.4 浏览器 : http://localhost:10008/order/save?userId=666&productId=1&nums=1&money=100
1. 修 改 seata_account_micro_service-10012 的 com/hspedu/springcloud/controller/AccountController.java, 模拟异常出现
1 |
|
**2.**修 改 seata-order-micro-service-10008 的com/study/springcloud/service/impl/OrderServicelmpl.java
使用@GlobalTransactional控制分布式事务,保证数据一致性
1 | /** |
3. 重启 seata-order-micro-service-10008
4. 浏 览 器 : http://localhost:10008/order/save?userId=666&productId=1&nums=1&money=100
5. 查看数据库/表的情况是否正常, 结论:这时数据库/表,数据不一致性得到保证.
11.4.12 注意事项和细节
11.4.12.1 如果数据库/表使用到关键字,需要使用反引号
- 举例说明**:** 比如mapper/OrderMapper.xml , 这里的 order 就要使用**``,** 否则会报错
1 | <insert id="save"> |