SpringCloud
1.cloud升级
2.父工程搭建
-
新建maven工程,选择site模板
-
设置字符编码,utf-8
-
设置注解支持
-
修改pom文件
-
修改打包类型
<groupId>com.njhr.springcloud</groupId> <artifactId>cloud2020</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging>
-
删除src文件夹
-
同一管理jar包版本
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <log4j.version>1.2.17</log4j.version> <lombok.version>1.16.18</lombok.version> <mysql.version>5.1.47</mysql.version> <druid.verison>1.1.16</druid.verison> <mybatis.spring.boot.verison>1.3.0</mybatis.spring.boot.verison> </properties>
-
父工程锁定版本,子工程不用再写groupID和version
<dependencyManagement> <dependencies> <!--spring boot 2.2.2--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!--spring cloud Hoxton.SR1--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR1</version> <type>pom</type> <scope>import</scope> </dependency> <!--spring cloud alibaba 2.1.0.RELEASE--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!-- MySql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!-- Druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid.verison}</version> </dependency> <!-- mybatis-springboot整合 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.spring.boot.verison}</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <!-- log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> </dependencies> </dependencyManagement>
dependencyManagement与dependcies区别
-
只声明依赖,不实现引入,因此还需要子项目显示声明所需要的依赖
- 父工程创建完毕后,使用maven命令clean和install命令发布到本地仓库,以让子项目继承
3.maven跳过单元测试
maven工具栏点闪电按钮
4.微服务模块的创建流程
- 建model
- 改pom
- 写yml
- 主启动
- 业务类
5.支付模块建立
-
右击父工程,新进model(无选项)
-
创建完成后查看父工程的pom文件
多出来一个model标签
<modules> <module>cloud-provider-payment8001</module> </modules>
说明8001是父工程下的一个子model
model8001中的pom
<parent> <artifactId>cloud2020</artifactId> <groupId>com.njhr.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> //本pom文件的信息 <artifactId>cloud-provider-payment8001</artifactId>
parent说明继承了父工程cloud2020
-
添加依赖
<?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"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.njhr</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-provider-payment8001</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!--eureka-client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> </dependencies> </project>
-
修改yml
#服务端口号
server:
port: 8001
#服务名称
spring:
application:
name: cloud-paymet-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource #当前数据源类型
driver-class-name: org.gjt.mm.mysql.Driver #驱动包
url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
mybatis:
mapper-locations: classpath:mapper/*.xml #mapper路径
type-aliases-package: com.bjhr.springcloud.entities #配置别名
-
主启动类
-
业务代码
-
entities
-
主实体:payment
package com.njhr.springcloud.entities; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * @author GuoZhaoning */ /* lombok注解 data不用去写get、set、tostring、hashcode、eauals方法了 all用于创建一个全部参数的构造器 no用于创建一个无参构造器 */ @Data @AllArgsConstructor @NoArgsConstructor public class Payment implements Serializable { private Long id; private String serial; }
-
json封装体CommonResult
package com.njhr.springcloud.entities; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * 向前端发送的数据 * * @param <T> * @author GuoZhaoning */ @Data @AllArgsConstructor @NoArgsConstructor public class CommonResult<T> { /** * 向前端返回网络状态 * 例如:200、404 */ private Integer code; /** * 消息 * 例如:success:成功 */ private String message; /** * 实体对象 * 例如:payment */ private T data; /** * 两个参数的构造方法,用于data为null */ public CommonResult(Integer code, String message) { this(code, message, null); } }
-
-
dao
package com.njhr.springcloud.dao; import com.njhr.springcloud.entities.Payment; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * @author GuoZhaoning */ @Mapper public interface PaymentDao { public int create(Payment payment); public Payment getPaymentByID(@Param("id") Long id); }
-
mapper
-
service
-
controller
-
测试
-
数据库脚本
CREATE TABLE `payment` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `serial` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT
CHARSET=utf8;
6.开启热部署
父pom添加插件
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
开启自动编译adbc全部打钩
7.消费者模块建立
-
新建maven项目(不选)
-
改pom
<?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"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.njhr.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-consumer-order80</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies> </project>
-
写yml
-
主启动
-
业务类
-
entities
- 实体类
- json封装体
-
RestTemplate
spring提供的一个可以访问http协议的httpclient
-
config配置类
引入resttemplate,依赖注入
-
controller
这边注意客户端为浏览器,地址测试只能为get请求,所以使用getmapping
注意:如果实体类中属性不能正确添加,尝试添加requestBody注解
-
8.工程重构
为什么重构
系统中有重复部分,例如entities
- 新建cloud-api=comoons模块,用于保存公共部分(公共代码)
- 改pom
- entities
- maven命令clean、install
- 删除原项目中的重复
- 添加生成的依赖
9.Eureka服务注册中心
-
什么是当前服务治理
springcloud封装了Netflix公司开发的Eureka模块来实现服务治理
在传统rpc远程调用框架中,管理多个服务之间的依赖关系比较复杂,所以使用服务治理,管理服务之间的依赖关系,可以实现服务调用、负载均衡、容错等、实现服务注册用于发现。
-
什么是服务注册
Eureka采用了CS的设计架构,Eureka server作为服务注册功能的服务器,是服务注册中心,而系统中的其他微服务,使用Eureka的客户端连接到Eureka server并维持心跳连接,维护人员可以通过Eureka server监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心,当服务器启动,会把当前自己服务器的信息比如服务器地址、通讯地址等以别名方式注册到注册中心上,另一方(消费者、服务提供者),以别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用
RPC远程调用框架核心思想:在注册中心,因为注册中心管理每个服务与服务之间的依赖关系(服务治理),在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))
一般情况注册中心和服务提供者需要做集群
- 两个组件
10.Eureka服务端构建
- 新建model
- 改pom
- 写yyml
- 主程序
11. 支付微服务8001入住Eureka server
- 改pom
- 改yml
- 主启动类加入客户端注解标签
12.订单微服务80入驻server
- 改pom
- 改yml
- 主启动类修改
13.集群版Eureka服务端
什么是集群?
互相注册,相互守望
修改host文件
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com # eureka服务端实例名称
client:
#false表示不向注册中心注册自己
register-with-eureka: false
#false表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
# 设置与 eureka server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7001.com:7001/eureka/
-
新建model
-
改pom
-
写yml
-
7001
server: port: 7001 eureka: instance: hostname: eureka7001.com # eureka服务端实例名称 client: #false表示不向注册中心注册自己 register-with-eureka: false #false表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: # 设置与 eureka server交互的地址查询服务和注册服务都需要依赖这个地址 # defaultZone: http://eureka7001.com:7001/eureka/ #单机版 defaultZone: http://eureka7002.com:7002/eureka/ # server: # # 关闭自我保护机制 # enable-self-preservation: false # # 心跳时间默认90s,改为2000ms,即2s # eviction-interval-timer-in-ms: 2000
-
7002
server: port: 7002
eureka:
instance:
hostname: eureka7002.com # eureka服务端实例名称
client:
#false表示不向注册中心注册自己
register-with-eureka: false
#false表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
# 设置与 eureka server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7001.com:7001/eureka/ -
-
主启动
14.将服务提供者同时发布到集群服务端
-
修改服务提供者yml文件
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/
-
测试
首先启动Eureka,再次启动server,最后启动消费者
15.服务提供者集群配置
-
新建model与payment8001相同
-
改pom
-
写yml 配置中暴露的服务名称相同,端口号不同
-
主启动
-
业务类
-
在两个服务提供者业务类,添加输出端口号的代码,可以用来测试是哪个服务提供的
-
测试发现,只会使用一个端口,原因,是在消费者控制层,将端口号写死了
-
控制层修改地址
-
测试出错
原因,该地址上有很多个服务提供者,程序不知道使用那一个
解决方式,配置负载均衡
-
需要在config类加上一个注解,实现负载均衡
- 赋予了resttemplate负载均衡的能力
16.actuator微服务信息完善
当前出现的问题,主机名称暴露例如localhost:8080
解决方式,修改主机名,在服务提供者的yml文件进行修改
修改后的服务提供者结果
访问路径可以显示ip地址
修改yml
效果
17.actuator健康检查
18.discover服务发现
可以用来显示服务的内部信息
在服务提供者controller添加依赖及代码
19.Eureka自我保护机制
一句话:某时刻,某个微服务不可用了,Eureka不会立刻清理,依旧会对微服务的信息进行保存
属于cap里面的ap分支
20.怎么禁止自我保护
在EurekaServer的yml文件中添加
下面的时间为获取心跳的间隔
服务提供者修改yml
测试结果:
关闭服务提供者后Eureka立即删除服务
21.Zookeeper
centos下的配置
到zookeeper路径下
关闭防火墙
项目搭建
-
新进cloud-provider-payment8004
-
pom
引入zookeeper删除Eureka依赖
-
yml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2QqTxiAr-1596976924649)(SpringCloud.assets/image-20200802185152287.png)]
-
主启动
注解使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nN0QrYtL-1596976924652)(SpringCloud.assets/image-20200802185225262.png)]
不在使用Eureka的注解
-
controller
-
启动服务,若出现启动出错,可能原因有jar包冲突
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nFi4j4at-1596976924655)(SpringCloud.assets/image-20200802185550730.png)]
解决方式:修改依赖
-
打开zookeeper服务器,发现服务
22.临时还是持久节点
zookeeper中的znode节点
微服务作为一个节点注册进来
讨论:节点为持久节点还是临时
实验:关闭服务提供者
结果:节点为临时节点
zookeeper比Eureka更加干脆,有就是有,没有就删
23.订单服务入驻zookeeper
新建model
pom
yml
主启动
controller
24.Consul服务注册中心
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n3d3OHLK-1596976924658)(SpringCloud.assets/image-20200802191022305.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1MPejuou-1596976924665)(SpringCloud.assets/image-20200802191049127.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dz9J1mic-1596976924667)(SpringCloud.assets/image-20200802191139088.png)]
23.安装并运行consul
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ExkM0Kh9-1596976924669)(SpringCloud.assets/image-20200802191430343.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X2mqdOEr-1596976924672)(SpringCloud.assets/image-20200802191535447.png)]
24.服务提供者入驻
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NrzMlTVo-1596976924678)(SpringCloud.assets/image-20200802191752748.png)]
pom修改依赖
yaml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jWyVmBZi-1596976924685)(SpringCloud.assets/image-20200802191838607.png)]
25.服务消费者入驻
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uSExiknn-1596976924687)(SpringCloud.assets/image-20200802192223898.png)]
26.三个注册中心比较
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T7YwsIRU-1596976924692)(SpringCloud.assets/image-20200802192728082.png)]
CAP官方架构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dDCJDsL6-1596976924694)(SpringCloud.assets/image-20200802215107209.png)]
AP高可用、CP数据一致
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hXCPD4h2-1596976924697)(SpringCloud.assets/image-20200802215024264.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uNWOCZrz-1596976924700)(SpringCloud.assets/image-20200802215140081.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QqL4lC5Y-1596976924706)(SpringCloud.assets/image-20200802215151987.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HTr4RMZM-1596976924718)(SpringCloud.assets/image-20200802215519425.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o0xdbtHM-1596976924720)(SpringCloud.assets/image-20200802215725666.png)]
27.Ribbon负载均衡、服务调用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tDuxT76m-1596976924723)(SpringCloud.assets/image-20200802220113766.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HpLLbBM7-1596976924726)(SpringCloud.assets/image-20200802220700144.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n5d0lf6K-1596976924727)(SpringCloud.assets/image-20200802221114609.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qAzbquKH-1596976924742)(SpringCloud.assets/image-20200802220715457.png)]
本地负载均衡是进程内LB
服务端负载均衡是集中式LB
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uu3dGabH-1596976924745)(SpringCloud.assets/image-20200802220940694.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rCwH8tcF-1596976924747)(SpringCloud.assets/image-20200802220952075.png)]
28.ribbon的负载均衡和rest调用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gl0bY3JM-1596976924750)(SpringCloud.assets/image-20200804190101203.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r1wDt4Tm-1596976924752)(SpringCloud.assets/image-20200804190225738.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OYTU8dlu-1596976924754)(SpringCloud.assets/image-20200804190358300.png)]
问题:为何之前没有引入ribbon依赖,依然可以实现负载均衡
答案:因为新版的Eureka集成了ribbon,可以通过查看Eureka的pom父pom,可以找到ribbon依赖
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RSk56477-1596976924756)(SpringCloud.assets/image-20200804191256645.png)]
RestTemplate
常用方法[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lsmqU0Iy-1596976924760)(SpringCloud.assets/image-20200804191748675.png)]
object和entity区别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4qgIgsu1-1596976924762)(SpringCloud.assets/image-20200804192022974.png)]
29.ribbon默认自带的负载规则
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YMJTH1ee-1596976924764)(SpringCloud.assets/image-20200804195417284.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eKc6PbPc-1596976924766)(SpringCloud.assets/image-20200804194541029.png)]
常用规则如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JUGUp1Ji-1596976924768)(SpringCloud.assets/image-20200804192944862.png)]
30.ribbon负载规则替换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8irMtbL6-1596976924771)(SpringCloud.assets/image-20200804193208169.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q4sIPJJy-1596976924772)(SpringCloud.assets/image-20200804193225034.png)]
就是不能放在与启动类同级的包下,以及父包下,这些包都能被扫描到
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wHkoBr7t-1596976924774)(SpringCloud.assets/image-20200804194236266.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-poD1GI1r-1596976924776)(SpringCloud.assets/image-20200804194301587.png)]
31.ribbon负载均衡算法原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EEO9N7nc-1596976924777)(SpringCloud.assets/image-20200804194801411.png)]
-
轮询原理:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9F3yKkip-1596976924779)(SpringCloud.assets/image-20200804194950442.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PEOE2C76-1596976924783)(SpringCloud.assets/image-20200804195026279.png)]
32.源码分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pFYutZ74-1596976924785)(SpringCloud.assets/image-20200804195437571.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2TTGFERe-1596976924787)(SpringCloud.assets/image-20200804195453807.png)]
33.手写轮询算法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s1isgeWj-1596976924789)(SpringCloud.assets/image-20200804200353579.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ySr4f0mB-1596976924791)(SpringCloud.assets/image-20200804200452175.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-140DcZ7F-1596976924794)(SpringCloud.assets/image-20200804200512474.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TiQTkvWp-1596976924795)(SpringCloud.assets/image-20200804200616178.png)]
34.OpenFegin服务调用概述
是什么?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2pZVls00-1596976924798)(SpringCloud.assets/image-20200804201011269.png)]
能干嘛?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QZLmMllP-1596976924800)(SpringCloud.assets/image-20200804201134872.png)]
OpenFegin与Fegin的区别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tKKyUu4V-1596976924802)(SpringCloud.assets/image-20200804201423017.png)]
35.OpenFegin使用
对于OpenFeign的理解:
在服务消费端定义service接口,在此接口上添加@feignClient(value = “需要调用的服务提供者地址”)
在service接口中的方法上方添加诸如@GetMapping等注解,用于调用服务提供者具体的接口
就可以调用该服务提供者在controller暴露的接口,从而实现服务之间的调用
原来使用ribbon+restTemplate,需要定义一个config包,用于获取resttemplate,并通过@Loadbalanced注解实现负载均衡,然后在控制层使用resttemplate实例去调用服务提供者的暴露的接口
-
接口+注解
微服务调用接口+@feginClient注解
-
新建cloud-consumer-fegin-order80消费者服务
Fegin在消费端使用
-
pom
<?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"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-consumer-feign-order80</artifactId> <!--openfeign--> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-common</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
-
yml
server: port: 80 eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka
-
主启动
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableFeignClients public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class,args); } }
-
业务类
-
业务逻辑接口+@FeginClient配置调用provider服务
-
新建PaymentFeginService接口并新增注解@FeignClient
package com.atguigu.springcloud.service; import com.atguigu.springcloud.entities.CommonResult; import com.atguigu.springcloud.entities.Payment; import feign.Param; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id); }
-
controller
package com.atguigu.springcloud.controller; import com.atguigu.springcloud.entities.CommonResult; import com.atguigu.springcloud.entities.Payment; import com.atguigu.springcloud.service.PaymentFeignService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; @GetMapping(value = "/consumer/payment/get/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){ return paymentFeignService.getPaymentById(id); } }
-
-
测试
- 先启动两个Eureka集群7001、7002
- 在启动两个服务提供者8001、8002
- 启动OpenFeign
- http://localhost/consumer/payment/get/31
- Fegin自带负载均衡配置项
-
总结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RaFCwTUs-1596976924804)(SpringCloud.assets/image-20200805144248157.png)]
36.OpenFegin超时控制
-
超时设置,故意设置超时演示出错情况
-
OpenFeign默认等待1秒钟,超过后报错
-
是什么
默认feign客户端只等待1秒钟,但是服务端处理需要超过1秒钟,导致feign客户端不想等待了,直接报错,为了避免这样的情况,有时候我们需要设置Feign客户端的超时控制
在yml文件中开启配置
OpenFeign默认支持Ribbon
-
yml文件里需要开启OpenFeign客户端超时控制
ribbon: #建立连接最大等待时间 ReadTimeout: 5000 #建立连接后,获取可用资源最大等待时间 ConnectTimeout: 5000
37.OpenFegin日志打印功能
-
是什么?
Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节,说白了就是对Feign接口的调用情况进行监控和输出
-
日志级别
- none:默认的,不显示
- basic:仅记录请求方法、URL、响应状态码及执行时间
- headers:除了basic中定义的信息外,还有请求和响应的头信息
- full:除了headers中定义的信息之外,还有请求和响应的正文和元数据。
-
配置日志bean
package com.atguigu.springcloud.config; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; }
-
yml文件里需要开启日志的Fegin客户端
logging: level: com.atguigu.springcloud.service.PaymentFeignService: debug
-
后台日志查看
38.Hystrix断路器概述
读音(histreaks)
-
分布式系统面临的问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AItcifqS-1596976924806)(SpringCloud.assets/image-20200805153956512.png)]
服务雪崩
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pGbodwLB-1596976924809)(SpringCloud.assets/image-20200805154017539.png)]
-
是什么
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c1xpuuiY-1596976924811)(SpringCloud.assets/image-20200805154034523.png)]
-
能干嘛
- 服务降级
- 服务熔断
- 接近实时的监控
- 。。。。。
-
官网资料
-
Hystrix官宣,停更进维
39.Hystrix重要概念
-
服务降级(fallback)
就类似switch中最后的default,某个服务出错,要给一个最基本的返回提示,而不是让服务崩溃
- 服务器忙,请稍后再试,不让客户端等待并立即返回一个友好提示,fallback
- 哪些情况会触发降级
- 程序运行异常
- 超时
- 服务熔断触发服务降级
- 线程池、信号量打满也会导致服务降级
-
服务熔断(break)
直接返回服务不能使用了
-
类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方式返回友好提示
-
就是保险丝
服务的降级-》进而熔断-》恢复调用链路
-
-
服务限流(flowlimit)
秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行
40.Hystrix案例
-
构建
-
新建cloud-provider-hystrix-payment8001
-
pom
<?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"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-provider-hystrix-payment8001</artifactId> <dependencies> <!--新增hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
-
yml
server: port: 8001 eureka: client: register-with-eureka: true #表识不向注册中心注册自己 fetch-registry: true #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务 service-url: # defaultZone: http://eureka7002.com:7002/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址 defaultZone: http://eureka7001.com:7001/eureka/ # server: # enable-self-preservation: false spring: application: name: cloud-provider-hystrix-payment # eviction-interval-timer-in-ms: 2000
-
主启动
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class PaymentHystrixMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentHystrixMain8001.class,args); } }
-
业务类
-
service
package com.atguigu.springcloud.service; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; @Service public class PaymentService { //成功 public String paymentInfo_OK(Integer id){ return "线程池:"+Thread.currentThread().getName()+" paymentInfo_OK,id: "+id+"\t"+"哈哈哈" ; } //失败 public String paymentInfo_TimeOut(Integer id){ int timeNumber = 3; try { TimeUnit.SECONDS.sleep(timeNumber); }catch (Exception e) {e.printStackTrace();} return "线程池:"+Thread.currentThread().getName()+" paymentInfo_TimeOut,id: "+id+"\t"+"呜呜呜"+" 耗时(秒)"+timeNumber; } }
-
controller
package com.atguigu.springcloud.controller; import com.atguigu.springcloud.service.PaymentService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @Slf4j public class PaymentController { @Resource private PaymentService paymentService; @Value("${server.port}") private String serverPort; @GetMapping("/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id){ String result = paymentService.paymentInfo_OK(id); log.info("*******result:"+result); return result; } @GetMapping("/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ String result = paymentService.paymentInfo_TimeOut(id); log.info("*******result:"+result); return result; } }
-
-
正常测试
- 启动Eureka7001
- 启动payment8001
- 访问
- 访问 http://localhost:8001/payment/hystrix/ok/31
- 每次调用耗费5秒钟 http://localhost:8001/payment/hystrix/timeout/31
- 上述model均ok 以上述为根基平台,从正确-》错误-》降级熔断-》恢复
-
高并发测试
-
上述在非高并发的情形下,还能勉强满足,but。。。。
-
Jmeter压测测试
-
开启jmeter,来个20000的并发压死8001,20000个请求都去访问paymentInfo_TimeOut服务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lHTTZXIf-1596976924813)(SpringCloud.assets/image-20200805160002438.png)]
-
再来一个访问
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3zypXeMc-1596976924815)(SpringCloud.assets/image-20200805160114059.png)]
-
看演示结果
-
两个都在自己转圈圈
-
为什么会被卡死
tomcat默认的工作线程数都被打满了,没有多余的线程来分解压力和处理
-
-
-
Jmeter压测结论
上面还是服务提供者8001自己测试,加入此时外部的消费者80也来访问,那消费者只能干等,最终导致消费者80不满,服务端8001直接被拖死
-
消费者80加入
-
新建cloud-consumer-feign-hystrix-order80
-
pom
<?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"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-consumer-feign-hystrix-order80</artifactId> <dependencies> <!--新增hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
-
yml
server port: 80 eureka: client: register-with-eureka: true #表识不向注册中心注册自己 fetch-registry: true #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务 service-url: defaultZone: http://eureka7001.com:7001/eureka/ spring: application: name: cloud-provider-hystrix-order
-
主启动
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableFeignClients public class OrderHystrixMain80 { public static void main(String[] args) { SpringApplication.run(OrderHystrixMain80.class,args); } }
-
业务类
-
PaymentHystrixService
package com.atguigu.springcloud.service; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit;
-
-
@Service
public class PaymentService {//成功 public String paymentInfo_OK(Integer id){ return "线程池:"+Thread.currentThread().getName()+" paymentInfo_OK,id: "+id+"\t"+"哈哈哈" ; } //失败 public String paymentInfo_TimeOut(Integer id){ int timeNumber = 3; try { TimeUnit.SECONDS.sleep(timeNumber); }catch (Exception e) {e.printStackTrace();} return "线程池:"+Thread.currentThread().getName()+" paymentInfo_TimeOut,id: "+id+"\t"+"呜呜呜"+" 耗时(秒)"+timeNumber; } }
package com.atguigu.springcloud.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Component
@FeignClient(value = “CLOUD-PROVIDER-HYSTRIX-PAYMENT”)
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable(“id”) Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable(“id”) Integer id);
}```
2. OrderHystrixController ```java package com.atguigu.springcloud.controller; import com.atguigu.springcloud.service.PaymentService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController
@Slf4j
public class PaymentController {@Resource private PaymentService paymentService; @Value("${server.port}") private String serverPort; @GetMapping("/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id){ String result = paymentService.paymentInfo_OK(id); log.info("*******result:"+result); return result; } @GetMapping("/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ String result = paymentService.paymentInfo_TimeOut(id); log.info("*******result:"+result); return result; } }
package com.atguigu.springcloud.controller;
import com.atguigu.springcloud.service.PaymentHystrixService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderHystrixController {@Resource private PaymentHystrixService paymentHystrixService; @Value("${server.port}") private String serverPort; @GetMapping("/consumer/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id){ String result = paymentHystrixService.paymentInfo_OK(id); log.info("*******result:"+result); return result; } @GetMapping("/consumer/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ String result = paymentHystrixService.paymentInfo_TimeOut(id); log.info("*******result:"+result); return result; } } ```
-
正常测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rlaN6GC5-1596976924816)(SpringCloud.assets/image-20200805164616538.png)]
-
高并发测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-urZweUKf-1596976924819)(SpringCloud.assets/image-20200805164632562.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MWI1dtcQ-1596976924821)(SpringCloud.assets/image-20200805164645971.png)]
-
-
故障和导致原因
- 8001同一层次的其他接口服务被困死,因为tomcat线程里面的工作线程已经被挤占完毕
-
80此时调用8001,客户端访问响应缓慢,转圈圈
-
-
上述结论
正因为有上述故障或不佳表现,才有我们的降级、容错、限流等技术的诞生
-
如何解决?解决的要求
-
超时导致服务器变慢(转圈)
超时不再等待
-
出错(宕机或程序运行出错)
出错要有兜底
-
解决
- 对方服务8001超时了,调用者80不能卡死等待,必须有服务降级
-
对方服务8001宕机了,调用者80不能一直卡死等待,必须有服务降级
3. 对方服务8001ok,调用者80自己出故障或自我要求(自己等待的时间小于服务者),自己处理降级。
-
-
41.服务降级
-
降低配置
@hystrixCommand
-
8001先从自身找问题
设置自身调用超时时间的峰值,峰值内可以正常运行,超过了需要兜底的方法处理,做服务降级fallback
-
8001fallback
-
业务类启用
@HystrixCommand报异常后如何处理
package com.atguigu.springcloud.service; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; @Service public class PaymentService { //成功 public String paymentInfo_OK(Integer id){ return "线程池:"+Thread.currentThread().getName()+" paymentInfo_OK,id: "+id+"\t"+"哈哈哈" ; } //失败 @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000") //3秒钟以内就是正常的业务逻辑 }) public String paymentInfo_TimeOut(Integer id){ // int timeNumber = 5; int age = 10/0; // try { TimeUnit.SECONDS.sleep(timeNumber); }catch (Exception e) {e.printStackTrace();} //return "线程池:"+Thread.currentThread().getName()+" paymentInfo_TimeOut,id: "+id+"\t"+"呜呜呜"+" 耗时(秒)"+timeNumber; return "线程池:"+Thread.currentThread().getName()+" paymentInfo_TimeOut,id: "+id+"\t"+"呜呜呜"+" 耗时(秒)"; } //兜底方法 public String paymentInfo_TimeOutHandler(Integer id){ return "线程池:"+Thread.currentThread().getName()+" 系统繁忙, 请稍候再试 ,id: "+id+"\t"+"哭了哇呜"; } }
一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kf4b2jsJ-1596976924824)(SpringCloud.assets/image-20200806135407285.png)]
-
主启动类激活
添加新注解@EnableCricuitBreaker
-
-
80fallbanck
-
80订单微服务,也可以更好的保护自己,自己也一样画葫芦进行客户端降级保护
-
切记
自己部署过的热部署方式对java代码的改动明显,但对@HystrixCommand内的修改建议重启微服务
-
yml
feign: hystrix: enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
-
主启动
@EnableHystrix
-
业务类
@GetMapping("/consumer/payment/hystrix/timeout/{id}") @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500") //3秒钟以内就是正常的业务逻辑 }) public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ String result = paymentHystrixService.paymentInfo_TimeOut(id); return result; } //兜底方法 public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id){ return "我是消费者80,对付支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,(┬_┬)"; }
-
-
目前问题
- 每个业务方法对应一个兜底的方法,代码膨胀
- 同一和自定义的分开
-
解决问题
-
每个方法配置一个??膨胀
-
fegin接口系列
-
@DefaultProperties(defaultFallback=“”)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PpYEzMmx-1596976924826)(SpringCloud.assets/image-20200806144452155.png)]
说明
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZTr22AH1-1596976924827)(SpringCloud.assets/image-20200806144518106.png)]
-
controller配置
package com.atguigu.springcloud.controller; import com.atguigu.springcloud.service.PaymentHystrixService; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @Slf4j @DefaultProperties(defaultFallback = "payment_Global_FallbackMethod") //全局的 public class OrderHystrixController { @Resource private PaymentHystrixService paymentHystrixService; @GetMapping("/consumer/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id){ String result = paymentHystrixService.paymentInfo_OK(id); return result; } // @GetMapping("/consumer/payment/hystrix/timeout/{id}") // public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ // String result = paymentHystrixService.paymentInfo_TimeOut(id); // return result; // } @GetMapping("/consumer/payment/hystrix/timeout/{id}") // @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = { // @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500") //1.5秒钟以内就是正常的业务逻辑 // }) @HystrixCommand public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ int age = 10/0; String result = paymentHystrixService.paymentInfo_TimeOut(id); return result; } //兜底方法 public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id){ return "我是消费者80,对付支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,(┬_┬)"; } //下面是全局fallback方法 public String payment_Global_FallbackMethod(){ return "Global异常处理信息,请稍后再试,(┬_┬)"; } }
-
-
和业务逻辑混在一起??混乱
-
服务降级,客户端去调用服务端,碰上服务端宕机或关闭
-
本次案例服务降级处理是在客户端80实现的,与服务端8001没有关系,只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦
-
未来我们要面对的异常
- 运行
- 超时
- 宕机
-
再看我们的业务类PaymentController
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8uFAIOEx-1596976924830)(SpringCloud.assets/image-20200806145000586.png)]
-
修改cloud-consumer-feign-hystrix-order80
-
根据cloud-consumer-feign-hystrix-order80已经有的PaymentHystrixService接口,重新新建一个类(PaymenFallbackService)实现该接口,统一为接口里面的方法进行异常处理
-
paymentFallbackService类实现PaymentFeignClientService接口
package com.atguigu.springcloud.service; import org.springframework.stereotype.Component; @Component public class PaymentFallbackService implements PaymentHystrixService { @Override public String paymentInfo_OK(Integer id) { return "-----PaymentFallbackService fall back-paymentInfo_OK , (┬_┬)"; } @Override public String paymentInfo_TimeOut(Integer id) { return "-----PaymentFallbackService fall back-paymentInfo_TimeOut , (┬_┬)"; } }
-
yml
feign: hystrix: enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
-
PaymentFeignClientService接口
package com.atguigu.springcloud.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @Component @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class) public interface PaymentHystrixService { @GetMapping("/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id); @GetMapping("/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id); }
-
测试
-
单个Eureka先启动7001
-
PaymentHystrixMain8001启动
-
正常访问测试 http://localhost/consumer/payment.hystrix/ok/31
-
故意关闭微服务8001
-
客户端自己调用提升
此时服务端provider已经宕机了,但是我们做了服务降级处理,让客户端在服务端不可用时也可以获取到提示信息而不会挂起耗死服务器
测试结果分析:客户端如果有默认的降级处理,那么会显示默认的降级处理信息,而不返回降级处理类中的降级信息
-
-
-
42.服务熔断
-
断路器
一句话就是家里保险丝
-
熔断是什么
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-goeN8MXG-1596976924831)(SpringCloud.assets/image-20200806150138308.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fj0PHBJO-1596976924833)(SpringCloud.assets/image-20200806150155339.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-37nUM8aT-1596976924836)(SpringCloud.assets/image-20200806194618539.png)]
类比保险丝,首先是一个关闭的状态,到达阈值后,进入开启状态,此时微服务不能使用,然后进入一个半开状态,如果服务能够重新使用,重新进入关闭状态
-
实操
-
修改cloud-provider-hystrix-payment8001
-
PaymentService
//服务熔断 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //请求次数 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //时间范围 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //失败率达到多少后跳闸 }) public String paymentCircuitBreaker(@PathVariable("id") Integer id){ if (id < 0){ throw new RuntimeException("*****id 不能负数"); } String serialNumber = IdUtil.simpleUUID(); return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber; } public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){ return "id 不能负数,请稍候再试,(┬_┬)/~~ id: " +id; }
为什么配置这些参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PVOh3XDh-1596976924837)(SpringCloud.assets/image-20200806220840952.png)]
-
PaymetController
//===服务熔断 @GetMapping("/payment/circuit/{id}") public String paymentCircuitBreaker(@PathVariable("id") Integer id){ String result = paymentService.paymentCircuitBreaker(id); log.info("*******result:"+result); return result; }
-
测试
-
自测cloud-provider-hystrix-payment8001
-
正确 http://localhost:8001/payment/circuit/31
-
错误 http://localhost:8001/payment/circuit/-31
-
一次正确一次错误trytry
-
重点测试
多次错误,然后慢慢正确,发现刚开始不满足条件,就算是正确的访问地址也不能进行访问,需要慢慢的恢复链路
-
-
-
原理
-
大神结论
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tt8ozu5N-1596976924839)(SpringCloud.assets/image-20200806221806553.png)]
-
熔断类型
-
熔断打开
请求不在进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入熔断状态
-
熔断关闭
熔断关闭不会堆服务进行熔断
-
熔断半开
部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断
-
-
官网断路器流程图
-
官网步骤
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lfYsR7vA-1596976924841)(SpringCloud.assets/image-20200806221831562.png)]
-
断路器在什么情况下开始起作用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i7lghpzM-1596976924845)(SpringCloud.assets/image-20200806221849387.png)]
-
断路器开启或关闭的条件
- 当满足一定的阈值的时候(默认10秒内超过20个请求次数)
- 当失败率达到一定的时候(默认10秒内超过50%请求失败)
- 到达以上阈值,断路器将会开启
- 当开启的时候,所有请求都不会进行转发
- 一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中的一个请求进行转发,如果成功,断路器关闭,若失败,继续开启,重复4和5
-
断路器打开之后
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ni9x8U7N-1596976924846)(SpringCloud.assets/image-20200806221905602.png)]
-
ALL配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jr3PB0Ug-1596976924848)(SpringCloud.assets/image-20200806221925738.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2BzZzIaa-1596976924851)(SpringCloud.assets/image-20200806221950610.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j0mdY4Ry-1596976924852)(SpringCloud.assets/image-20200806222010858.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TlzbwltN-1596976924854)(SpringCloud.assets/image-20200806222028922.png)]
-
-
43.服务限流
在alibaba的Sentinel中说明
44.Hystrix工作流程
-
http://github.com/Netflix/Hystrix/wikio/How-it-Works
-
Hystrix工作流程
-
官网图例
-
步骤说明
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bWLNUegV-1596976924857)(SpringCloud.assets/image-20200808175300813.png)]
-
45.服务监控HystrixDashboard
-
概述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u2bp9re3-1596976924859)(SpringCloud.assets/image-20200808175353782.png)]
-
仪表盘9001
-
新建cloud-consumer-hystrix-dashboard9001
-
pom
<?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"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-consumer-hystrix-dashboard9001</artifactId> <dependencies> <!--新增hystrix dashboard--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
-
yml
server: port: 9001
-
HystrixDashboardMain9001+新注解@EnableHystrixDashboard
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableHystrixDashboard public class HystrixDashboardMain9001 { public static void main(String[] args) { SpringApplication.run(HystrixDashboardMain9001.class,args); } }
-
所有Provider微服务提供类(8001、8002、8003)都需要监控依赖配置
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
启动cloud-consumer-hystrix-dashboard9001该微服务后续将监控微服务8001
http://localhost:9001/hystrix
-
-
断路器演示
-
修改cloud-provider-hystrix-payment8001
-
注意:新版本Hystrix需要在启动类MainAppHystrix8001中指定监控路径
@Bean public ServletRegistrationBean getServlet(){ HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet(); ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); registrationBean.setLoadOnStartup(1); registrationBean.addUrlMappings("/hystrix.stream"); registrationBean.setName("HystrixMetricsStreamServlet"); return registrationBean; }
-
Unable to connect to Command Metric Stream
-
404
-
-
监控测试
-
启动1个Eureka或者3个Eureka集群均可
-
观察监控窗口
-
9001监控8001
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g5Rw4EBr-1596976924861)(SpringCloud.assets/image-20200808180250976.png)]
- 填写监控地址
- localhost:8001/hystrix.stream
-
测试地址
-
localhost:8001/payment/cricuit/31
-
localhost:8001/payment/cricuit/-31
-
测试通过----ok
-
先访问正确地址,在访问错误地址,再正确地址,会发现图示断路器都是慢慢放开的
-
监控结果,成功
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tDxhR3c8-1596976924863)(SpringCloud.assets/image-20200808180903667.png)]
-
监控结果,失败
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3BRmcdVf-1596976924864)(SpringCloud.assets/image-20200808180913952.png)]
-
-
-
如何看
-
7色
-
1圈
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MhKgT3s6-1596976924866)(SpringCloud.assets/image-20200808181017015.png)]
-
1线
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hi8TuS4s-1596976924867)(SpringCloud.assets/image-20200808224632145.png)]
-
整图说明
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VXy8Vf4N-1596976924870)(SpringCloud.assets/image-20200808224650534.png)]
-
整图说明2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pflyixkn-1596976924872)(SpringCloud.assets/image-20200808224702597.png)]
-
-
搞懂一个才能看懂复杂的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NSW2AnJZ-1596976924874)(SpringCloud.assets/image-20200808224718701.png)]
-
-
-
46.GateWay新一代网关
-
官网
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yXnfMcPQ-1596976924875)(SpringCloud.assets/image-20200809131540295.png)]
-
是什么
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wwYROJBs-1596976924879)(SpringCloud.assets/image-20200809131559359.png)]
-
概述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dK5HSgVE-1596976924880)(SpringCloud.assets/image-20200809131634377.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bPfprXPD-1596976924882)(SpringCloud.assets/image-20200809131855930.png)]
-
一句话
-
springcloud gateway使用的WebFlux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架
-
源码架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jGR0NIE2-1596976924885)(SpringCloud.assets/image-20200809131812461.png)]
-
-
-
能干嘛
- 反向代理
- 鉴权
- 流量控制
- 熔断
- 日志监控
- 。。。。
-
微服务架构中网关在哪里
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zJB3vTJ5-1596976924887)(SpringCloud.assets/image-20200809132037661.png)]
-
有了Zuul了怎么又出来gateway
-
为什么选择gateway
-
neflix不太靠谱,zuul2.0一直跳票,迟迟不发布
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8fSCelLd-1596976924891)(SpringCloud.assets/image-20200809132242517.png)]
-
springcloud gateway具有如下特性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4lxVmwZk-1596976924894)(SpringCloud.assets/image-20200809132251772.png)]
-
gateway和zuul的区别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MPSSuyBv-1596976924896)(SpringCloud.assets/image-20200809132310254.png)]
-
-
Zuul1.x模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kfo6w7nq-1596976924898)(SpringCloud.assets/image-20200809132419377.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1mR0SzKx-1596976924901)(SpringCloud.assets/image-20200809132428338.png)]
-
gateWay模型
-
说明
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PScfFcpP-1596976924902)(SpringCloud.assets/image-20200809132441142.png)]
-
WebFlux是什么
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wCKMGt2P-1596976924904)(SpringCloud.assets/image-20200809132456951.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xAyMbpY1-1596976924906)(SpringCloud.assets/image-20200809132507658.png)]
-
-