辽宁市场网站建设销售,广州网站改版 网站建设,销售人员培训课程有哪些,国内网建公司排名目录
八、Hystrix#xff08;服务降级#xff09;
8.1、Hystrix基本概念
8.1.1、分布式系统面临的问题
8.1.2、Hystrix是什么#xff1f;
8.1.3、服务降级
概念
哪些情况会触发降级
8.1.4、服务熔断
8.1.5、服务限流
8.2、Hystrix案例
8.2.1、Hystrix支付微服务构…目录
八、Hystrix服务降级
8.1、Hystrix基本概念
8.1.1、分布式系统面临的问题
8.1.2、Hystrix是什么
8.1.3、服务降级
概念
哪些情况会触发降级
8.1.4、服务熔断
8.1.5、服务限流
8.2、Hystrix案例
8.2.1、Hystrix支付微服务构建未加入熔断降级前
1新建cloud-provider-hygtrix-payment8001
2pom
3yml配置文件
4主启动类
5Service业务类
6Controller
7测试
8.2.2、Jmeter并发压力测试
8.2.3、Jmeter压测结论
8.2.4、新建消费者80
1新建cloud-consumer-feign-hystrix-order80
2pom
3yml配置文件
4主启动类
5Service Feign接口
6Controller
7测试
8.2.5、如何解决
8.2.6、服务降级提供者
1将8001 Hystrix提供者的Service方法改为如下
2主启动类激活
3测试
8.2.7、服务降级消费者
1将80 Hystrix消费者者的yml加入下面代码
2修改业务类controller
3主启动类加注解
8.2.8、Hystrix全局服务降级DefaultProperties
1修改消费者80的Controller
2测试
8.2.9、Hystrix之通配服务降级FeignFallBack
1修改cloud-consumer-feign-hystrix-order80
2yml
3PaymentHystrixService接口
4测试
8.2.10、服务熔断理论
8.2.11、服务熔断案例
1修改cloud-provider-hystrix-payment8001
2Controller
3测试
8.2.12、服务熔断总结
8.2.13、Hystrix工作流程
8.3、Hystrix图形化Dashboard
8.3.1、概述
8.3.2、图形化搭建
1新建cloud-consumer-hystrix-dashboard9001
2pom
3yml
4主启动类
5所有Provider微服务提供类(8001/8002/8003)都需要监控依赖配置
6启动9001
8.3.3、监控实战
1修改cloud-provider-hystrix-payment8001主启动类
2监控测试
3观察监控窗口
九、GateWay服务网关
9.1、GateWay基本概念
9.1.1、GateWay是什么
9.1.2、微服务架构中网关的位置
9.1.3、有Zuul了怎么又出来Gateway我们为什么选择Gateway?
9.1.4、GateWay非阻塞异步模型
9.2、GateWay工作流程
9.2.1、三大核心概念
9.2.2、工作流程
9.3、GateWay入门配置
9.3.1、Gateway9527搭建
1新建cloud-gateway-gateway9527
2pom
3yml
4主启动类
5查看cloud-provider-payment8001看看controller的访问地址
6修改yml
7测试
9.4、GateWay配置路由的两种方式
9.4.1、第一种yml
9.4.2、第二种代码中注入RouteLocator的Bean
1创建配置类
2测试
9.5、GateWay配置动态路由
9.5.1、实现
1启动
2pom
3yml
4测试
9.6、GateWay常用的Predicate
The After Route Predicate Factory
The Before Route Predicate Factory
The Between Route Predicate Factory
The Cookie Route Predicate Factory
The Header Route Predicate Factory
9.7、GateWay的Filter
9.7.1、是什么
9.7.2、常见的过滤器
9.7.3、自定义过滤器
十、SpringCloud Config分布式配置中心
10.1、介绍
分布式系统面临的配置问题
是什么
怎么玩
能干嘛
10.2、Config服务端配置与测试
1用你自己的账号在Github或者码云上新建一个名为springcloud-config的新Repository
2获取springcloud-config的Git地址SSH
3本地硬盘目录上新建Git仓库并Clone
10.3、Config配置总控中心搭建
1新建cloud-config-center-3344
2pom
3YML配置文件
4主启动类
5Windows下修改hosts文件增加映射
6测试通过Config微服务是否可以从Github上获取配置内容
10.4、Config客户端配置与测试
1新建cloud-config-client-3355
2pom
3创建bootstrap.yml
4主启动类
5业务类
6测试
7随之而来的问题
10.5、Config动态刷新之手动版
1修改3355模块POM引入actuator监控
2修改YML暴露监控端口
3RefreshScope业务类Controller修改
4运维人员发送Post请求刷新3355
5测试
6出现的问题
十一、SpringCloud Bus消息总线
11.1、介绍
什么是总线
基本原理
11.2、Bus之RabbitMQ环境配置
11.3、创建3366跟3355一样
1新建cloud-config-client-3366
2pom
3bootstrap.yml配置文件
4主启动类
5业务类
6设计思想
11.4、Bus动态刷新全局广播配置实现
给3344配置中心服务端添加消息总线支持
1pom
2YML配置文件
给3355客户端添加消息总线支持
1pom
2YML配置文件
给3366客户端添加消息总线支持
1pom
2YML配置文件
测试
11.5、Bus动态刷新定点通知
十二、SpringCloud Stream消息驱动
12.1、Stream为什么被引入
12.2、Binder介绍
12.3、Stream的设计思想
为什么用Cloud Stream
Stream凭什么可以统一底层差异
Stream编码常用注解简介
Spring Cloud Stream标准流程套路
编码API和常用注解
案例说明
12.4、Stream消息驱动之生产者发送
1创建cloud-stream-rabbitmq-provider8801
2pom
3YML配置文件
4主启动类
5业务类
6controller
7测试
12.5、Stream消息驱动之消费者接收
1创建cloud-stream-rabbitmq-consumer8802
2pom
3YML配置文件
4主启动类
5业务类
6测试
12.6、消息重复消费
1依照8802克隆出来一份运行8803 - cloud-stream-rabbitmq-consumer8803
2启动
3如何解决消息重复消费
4实现不同分组
5实现相同分组
12.7、消息持久化
十三、SpringCloud Sleuth分布式请求链路跟踪
13.1、Sleuth介绍
为什么会出现这个技术要解决哪些问题
是什么
13.2、Sleuth之zipkin搭建安装
下载
运行jar
运行控制台
完整的调用链路
13.3、Sleuth链路监控展现
服务提供者cloud-provider-payment8001
1pom
2YML
3controller
服务消费者cloud-consumer-order80(调用方)
1pom
2YML
3OrderController
4测试 八、Hystrix服务降级
8.1、Hystrix基本概念
8.1.1、分布式系统面临的问题
复杂分布式体系结构中的应用程序有数十个依赖关系每个依赖关系在某些时候将不可避免地失败。
服务雪崩
多个微服务之间调用的时候假设微服务A调用微服务B和微服务C微服务B和微服务C又调用其它的微服务这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用对微服务A的调用就会占用越来越多的系统资源进而引起系统崩溃所谓的“雪崩效应”。
对于高流量的应用来说单一的后避依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是这些应用程序还可能导致服务之间的延迟增加备份队列线程和其他系统资源紧张导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理以便单个依赖关系的失败不能取消整个应用程序或系统。
所以通常当你发现一个模块下的某个实例失败后这时候这个模块依然还会接收流量然后这个有问题的模块还调用了其他的模块这样就会发生级联故障或者叫雪崩。 8.1.2、Hystrix是什么
Hystrix是一个用于处理分布式系统的延迟和容错的开源库在分布式系统里许多依赖不可避免的会调用失败比如超时、异常等Hystrix能够保证在一个依赖出问题的情况下不会导致整体服务失败避免级联故障以提高分布式系统的弹性。
断路器”本身是一种开关装置当某个服务单元发生故障之后通过断路器的故障监控类似熔断保险丝)向调用方返回一个符合预期的、可处理的备选响应FallBack)而不是长时间的等待或者抛出调用方无法处理的异常这样就保证了服务调用方的线程不会被长时间、不必要地占用从而避免了故障在分布式系统中的蔓延乃至雪崩。 8.1.3、服务降级
概念
服务器忙请稍后再试不让客户端等待并立刻返回一个友好提示fallback。 哪些情况会触发降级
程序运行导常数组下标越界、除数分母为0。
超时。
服务熔断触发服务降级。
线程池/信号量打满也会导致服务降级。 8.1.4、服务熔断
类比保险丝达到最大服务访问后直接拒绝访问拉闸限电然后调用服务降级的方法并返回友好提示。服务熔断也是一种服务降级方式。
服务降级是你暂时不可用返回个提示10秒钟后可以重写访问。但服务熔断直接就不可用了直接拉闸限电。 8.1.5、服务限流
秒杀高并发等操作严禁一窝蜂的过来拥挤大家排队一秒钟N个有序进行。 8.2、Hystrix案例
8.2.1、Hystrix支付微服务构建未加入熔断降级前
1新建cloud-provider-hygtrix-payment8001 2pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdcloud2020/artifactIdgroupIdcom.atguigu.springcloud/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdcloud-provider-hygtrix-payment8001/artifactIddependencies!--hystrix--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-hystrix/artifactId/dependency!--eureka client--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependency!--web--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependency!-- 引入自己定义的api通用包可以使用Payment支付Entity --groupIdcom.atguigu.springcloud/groupIdartifactIdcloud-api-commons/artifactIdversion${project.version}/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies/project
3yml配置文件
server:port: 8001spring:application:name: cloud-provider-hystrix-paymenteureka:client:register-with-eureka: truefetch-registry: trueservice-url:#defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eurekadefaultZone: http://eureka7001.com:7001/eureka
4主启动类
SpringBootApplication
EnableEurekaClient
public class PaymentHystrixMain8001 {public static void main(String[] args) {SpringApplication.run(PaymentHystrixMain8001.class,args);}
}
5Service业务类
Service
public class PaymentService {/*** 正常访问肯定OK*/public String paymentInfo_OK(Integer id) {return 线程池: Thread.currentThread().getName() paymentInfo_OK,id: id\tO(∩_∩)O哈哈~;}/*** 模拟方法运行时间超时*/public String paymentInfo_TimeOut(Integer id) {try {TimeUnit.MILLISECONDS.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return 线程池: Thread.currentThread().getName() id: id\tO(∩_∩)O哈哈~ 耗时(秒): 3;}}
6Controller
RestController
Slf4j
public class PaymentController {Resourceprivate 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;}}
7测试
启动eureka7001
启动cloud-provider-hystrix-payment8001 访问
success的方法 - http://localhost:8001/payment/hystrix/ok/1
每次调用耗费5秒钟 - http://localhost:8001/payment/hystrix/timeout/1 都能正常访问只不过第二个访问的慢一点3秒钟之后才返回数据到页面中。
以上述为根基平台从正确 - 错误 - 降级熔断 - 恢复。 8.2.2、Jmeter并发压力测试
当我们使用Jmeter 20000个并发同时访问http://localhost:8001/payment/hystrix/timeout/1接口。这时我们再访问http://localhost:8001/payment/hystrix/ok/1接口发现http://localhost:8001/payment/hystrix/ok/1接口也开始转圈了也就是说此接口也被拖慢了那么问题来了我们之前测试此接口明明是秒回啊怎么被第二个接口拖慢了呢20000个并发访问的是第二个接口怎么能影响到第一个呢
原因是当20000个并发同时打到第二个接口时整个微服务的资源都在为你服务。 8.2.3、Jmeter压测结论
上面还是服务提供者8001自己测试假如此时外部的消费者80也来访问那消费者只能干等最终导致消费端80不满意服务端8001直接被拖慢。 8.2.4、新建消费者80
1新建cloud-consumer-feign-hystrix-order80 2pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdcloud2020/artifactIdgroupIdcom.atguigu.springcloud/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdcloud-consumer-feign-hystrix-order80/artifactIddependencies!--openfeign--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId/dependency!--hystrix--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-hystrix/artifactId/dependency!--eureka client--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependency!-- 引入自己定义的api通用包可以使用Payment支付Entity --dependencygroupIdcom.atguigu.springcloud/groupIdartifactIdcloud-api-commons/artifactIdversion${project.version}/version/dependency!--web--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!--一般基础通用配置--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies/project
3yml配置文件
server:port: 80eureka:client:register-with-eureka: falseservice-url:defaultZone: http://eureka7001.com:7001/eureka/
4主启动类
SpringBootApplication
EnableFeignClients
public class OrderHystrixMain80 {public static void main(String[] args) {SpringApplication.run(OrderHystrixMain80.class,args);}
}
5Service Feign接口
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);}
6Controller
RestController
Slf4j
public class OrderHystrixController {Resourceprivate 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;}}
7测试
我们发现一样的超时2万个并发同时访问第二个接口一样会拖慢第一个接口。 8.2.5、如何解决
超时导致服务器变慢(转圈) - 超时不再等待。
出错(宕机或程序运行出错) - 出错要有兜底。 解决
对方服务(8001)超时了调用者(80)不能一直卡死等待必须有服务降级。
对方服务(8001)down机了调用者(80)不能一直卡死等待必须有服务降级。
对方服务(8001)OK调用者(80)自己出故障或有自我要求(自己的等待时间小于服务提供者)自己处理降级。 8.2.6、服务降级提供者
1将8001 Hystrix提供者的Service方法改为如下
Service
public class PaymentService {/*** 正常访问肯定OK*/public String paymentInfo_OK(Integer id) {return 线程池: Thread.currentThread().getName() paymentInfo_OK,id: id\tO(∩_∩)O哈哈~;}/*** 模拟方法运行时间超时设置峰值3秒钟此方法运行超过3秒钟直接调用fallback方法*/HystrixCommand(fallbackMethod paymentInfo_TimeOutHandler/*指定善后方法名*/,commandProperties {HystrixProperty(nameexecution.isolation.thread.timeoutInMilliseconds,value3000)})public String paymentInfo_TimeOut(Integer id){//int age 10/0;try { TimeUnit.MILLISECONDS.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); }return 线程池: Thread.currentThread().getName() id: id\tO(∩_∩)O哈哈~ 耗时(秒): ;}/*** 用来善后的方法*/public String paymentInfo_TimeOutHandler(Integer id){return 线程池: Thread.currentThread().getName() 8001系统繁忙或者运行报错请稍后再试,id: id\to(╥﹏╥)o;}}
2主启动类激活
SpringBootApplication
EnableEurekaClient
EnableCircuitBreaker //加入
public class PaymentHystrixMain8001 {public static void main(String[] args) {SpringApplication.run(PaymentHystrixMain8001.class,args);}
}
3测试 8.2.7、服务降级消费者
1将80 Hystrix消费者者的yml加入下面代码
#开启
feign:hystrix:enabled: true
2修改业务类controller
RestController
Slf4j
public class OrderHystrixController {Resourceprivate 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})HystrixCommand(fallbackMethod paymentTimeOutFallbackMethod,commandProperties {HystrixProperty(nameexecution.isolation.thread.timeoutInMilliseconds,value1500)})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秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o;}}
3主启动类加注解
SpringBootApplication
EnableFeignClients
EnableHystrix //添加到此处
public class OrderHystrixMain80{public static void main(String[] args){SpringApplication.run(OrderHystrixMain80.class,args);}
}
注意假如你的提供者设置的方法运行时间峰值为5秒而方法真正运行时间为3秒这样当然不用触发降级。但消费者这边设置方法运行时间的峰值为1.5秒那么结果就是会触发消费者这端的fallback。 8.2.8、Hystrix全局服务降级DefaultProperties
目前问题每个业务方法对应一个兜底的方法代码膨胀。
解决方法
1:1每个方法配置一个服务降级方法技术上可以但是不聪明
1:N除了个别重要核心业务有专属其它普通的可以通过DefaultProperties(defaultFallback “”)统一跳转到统一处理结果页面
通用的和独享的各自分开避免了代码膨胀合理减少了代码量 1修改消费者80的Controller
RestController
Slf4j
DefaultProperties(defaultFallback payment_Global_FallbackMethod)
public class OrderHystrixController {Resourceprivate 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})/*HystrixCommand(fallbackMethod paymentTimeOutFallbackMethod,commandProperties {HystrixProperty(nameexecution.isolation.thread.timeoutInMilliseconds,value1500)})*/HystrixCommand//用全局的fallback方法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秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o;}// 下面是全局fallback方法public String payment_Global_FallbackMethod() {return Global异常处理信息请稍后再试/(ㄒoㄒ)/~~;}}
① 在类上加入注解DefaultProperties(defaultFallback payment_Global_FallbackMethod)代表全局降级方法。
② 编写全局降级方法payment_Global_FallbackMethod()。
③ 将paymentInfo_TimeOut方法的HystrixCommand(fallbackMethod paymentTimeOutFallbackMethod注解注释掉然后加入单独的HystrixCommand注解代表用全局的fallback方法。 2测试 8.2.9、Hystrix之通配服务降级FeignFallBack
目前问题统一和自定义的分开代码混乱。
服务降级客户端去调用服务端碰上服务端宕机或关闭。
本次案例服务降级处理是在客户端80实现完成的与服务端8001没有关系只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦。
未来我们要面对的异常
运行
超时
宕机 1修改cloud-consumer-feign-hystrix-order80
根据cloud-consumer-feign-hystrix-order80已经有的PaymentHystrixService接口重新新建一个类(AaymentFallbackService)实现该接口统一为接口里面的方法进行异常处理。
PaymentFallbackService类实现PaymentHystrixService接口
Component
public class PaymentFallbackService implements PaymentHystrixService {Overridepublic String paymentInfo_OK(Integer id) {return -----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o;}Overridepublic String paymentInfo_TimeOut(Integer id) {return -----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o;}
}
2yml
server:port: 80eureka:client:register-with-eureka: falseservice-url:defaultZone: http://eureka7001.com:7001/eureka/#开启
feign:hystrix:enabled: true
3PaymentHystrixService接口
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);}
4测试
依次启动7001、PaymentHystrixMain8001、OrderHystrixMain80。
访问http://localhost/consumer/payment/hystrix/ok/1 客户端自己调用提示 - 此时服务端provider已经down了但是我们做了服务降级处理让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器。 8.2.10、服务熔断理论
熔断机制概述
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时会进行服务的降级进而熔断该节点微服务的调用快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。
在Spring Cloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况当失败的调用到一定阈值缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是HystrixCommand。 1、调用失败会触发降级而降级会调用fallback方法。
2、但无论如何降级的流程一定会先调用正常方法再调用fallback方法。
3、假如单位时间内调用失败次数过多也就是降级次数过多则触发熔断。
4、熔断以后就会跳过正常方法直接调用fallback方法。
5、所谓“熔断后服务不可用”就是因为跳过了正常方法直接执行fallback。 8.2.11、服务熔断案例
1修改cloud-provider-hystrix-payment8001
Service
public class PaymentService {/*** 正常访问肯定OK*/public String paymentInfo_OK(Integer id) {return 线程池: Thread.currentThread().getName() paymentInfo_OK,id: id\tO(∩_∩)O哈哈~;}/*** 模拟方法运行时间超时设置峰值3秒钟此方法运行超过3秒钟直接调用fallback方法*/HystrixCommand(fallbackMethod paymentInfo_TimeOutHandler/*指定善后方法名*/,commandProperties {HystrixProperty(nameexecution.isolation.thread.timeoutInMilliseconds,value3000)})public String paymentInfo_TimeOut(Integer id){//int age 10/0;try { TimeUnit.MILLISECONDS.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); }return 线程池: Thread.currentThread().getName() id: id\tO(∩_∩)O哈哈~ 耗时(秒): ;}/*** 用来善后的方法*/public String paymentInfo_TimeOutHandler(Integer id){return 线程池: Thread.currentThread().getName() 8001系统繁忙或者运行报错请稍后再试,id: id\to(╥﹏╥)o;}//服务熔断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 不能负数请稍后再试/(ㄒoㄒ)/~~ id: id;}
}
2Controller
//服务熔断
GetMapping(/payment/circuit/{id})
public String paymentCircuitBreaker(PathVariable(id) Integer id){String result paymentService.paymentCircuitBreaker(id);log.info(****result: result);return result;
}
3测试
自测cloud-provider-hystrix-payment8001
正确 - http://localhost:8001/payment/circuit/1
错误 - http://localhost:8001/payment/circuit/-1
多次错误再来次正确但是出现了错误的显示。
重点测试 - 多次错误然后慢慢正确发现刚开始不满足条件就算是正确的访问地址也不能进行这就是直接服务熔断了。 8.2.12、服务熔断总结
涉及到断路器的三个重要参数
1、快照时间窗断路器确定是否打开需要统计一些请求和错误数据而统计的时间范围就是快照时间窗默认为最近的10秒。
2、请求总数阀值在快照时间窗内必须满足请求总数阀值才有资格熔断。默认为20意味着在10秒内如果该hystrix命令的调用次数不足20次即使所有的请求都超时或其他原因失败断路器都不会打开。
3、错误百分比阀值当请求总数在快照时间窗内超过了阀值比如发生了30次调用如果在这30次调用中有15次发生了超时异常也就是超过50%的错误百分比在默认设定50%阀值情况下这时候就会将断路器打开。 8.2.13、Hystrix工作流程
1、创建HystrixCommand 用在依赖的服务返回单个操作结果的时候或HystrixObserableCommand用在依赖的服务返回多个操作结果的时候对象。
2、命令执行。
3、其中 HystrixCommand实现了下面前两种执行方式
① execute()同步执行从依赖的服务返回一个单一的结果对象或是在发生错误的时候抛出异常。
② queue()异步执行直接返回一个Future对象其中包含了服务执行结束时要返回的单一结果对象。
4、而 HystrixObservableCommand实现了后两种执行方式
① obseve()返回Observable对象它代表了操作的多个统果它是一个Hot Observable 不论“事件源”是否有“订阅者”都会在创建后对事件进行发布所以对于Hot Observable的每一个“订阅者”都有可能是从“事件源”的中途开始的并可能只是看到了整个操作的局部过程。
② toObservable()同样会返回Observable对象也代表了操作的多个结果但它返回的是一个Cold Observable没有“订间者”的时候并不会发布事件而是进行等待直到有“订阅者之后才发布事件所以对于Cold Observable 的订阅者它可以保证从一开始看到整个操作的全部过程。
5、若当前命令的请求缓存功能是被启用的并且该命令缓存命中那么缓存的结果会立即以Observable对象的形式返回。
6、检查断路器是否为打开状态。如果断路器是打开的那么Hystrix不会执行命令而是转接到fallback处理逻辑(第8步)如果断路器是关闭的检查是否有可用资源来执行命令(第5步)。
7、线程池/请求队列信号量是否占满。如果命令依赖服务的专有线程地和请求队列或者信号量不使用线程的时候已经被占满那么Hystrix也不会执行命令而是转接到fallback处理理辑(第8步) 。
8、Hystrix会根据我们编写的方法来决定采取什么样的方式去请求依赖服务。
HystrixCommand.run()返回一个单一的结果或者抛出异常。
HystrixObservableCommand.construct()返回一个Observable对象来发射多个结果或通过onError发送错误通知。
9、Hystix会将“成功”、“失败”、“拒绝”、“超时” 等信息报告给断路器而断路器会维护一组计数器来统计这些数据。断路器会使用这些统计数据来决定是否要将断路器打开来对某个依赖服务的请求进行熔断/短路。
10、当命令执行失败的时候Hystix会进入fallback尝试回退处理我们通常也称波操作为“服务降级”。而能够引起服务降级处理的情况有下面几种
① 第4步∶当前命令处于“熔断/短路”状态断洛器是打开的时候。
② 第5步∶当前命令的钱程池、请求队列或者信号量被占满的时候。
③ 第6步∶HystrixObsevableCommand.construct()或HytrixCommand.run()抛出异常的时候。
11、当Hystrix命令执行成功之后它会将处理结果直接返回或是以Observable的形式返回。 tips如果我们没有为命令实现降级逻辑或者在降级处理逻辑中抛出了异常Hystrix依然会运回一个Obsevable对象但是它不会发射任结果数惯而是通过onError方法通知命令立即中断请求并通过onError方法将引起命令失败的异常发送给调用者。 8.3、Hystrix图形化Dashboard
8.3.1、概述
除了隔离依赖服务的调用以外Hystrix还提供了准实时的调用监控(Hystrix Dashboard)Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息并以统计报表和图形的形式展示给用户包括每秒执行多少请求多少成功多少失败等。
Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合对监控内容转化成可视化界面。 8.3.2、图形化搭建
1新建cloud-consumer-hystrix-dashboard9001 2pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdcloud2020/artifactIdgroupIdcom.atguigu.springcloud/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdcloud-consumer-hystrix-dashboard9001/artifactIddependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-hystrix-dashboard/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies/project
3yml
server:port: 9001
4主启动类
SpringBootApplication
EnableHystrixDashboard
public class HystrixDashboardMain9001 {public static void main(String[] args) {SpringApplication.run(HystrixDashboardMain9001.class, args);}
}
5所有Provider微服务提供类(8001/8002/8003)都需要监控依赖配置
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId
/dependency
6启动9001
浏览器输入http://localhost:9001/hystrix 8.3.3、监控实战
1修改cloud-provider-hystrix-payment8001主启动类
注意新版本Hystrix需要在主启动类PaymentHystrixMain8001中指定监控路径。
SpringBootApplication
EnableEurekaClient
EnableCircuitBreaker
public class PaymentHystrixMain8001 {public static void main(String[] args) {SpringApplication.run(PaymentHystrixMain8001.class,args);}/***此配置是为了服务监控而配置与服务容错本身无关springcloud升级后的坑*ServletRegistrationBean因为springboot的默认路径不是/hystrix.stream*只要在自己的项目里配置上下面的servlet就可以了*否则Unable to connect to Command Metric Stream 404*/Beanpublic ServletRegistrationBean getServlet() {HystrixMetricsStreamServlet streamServlet new HystrixMetricsStreamServlet();ServletRegistrationBean registrationBean new ServletRegistrationBean(streamServlet);registrationBean.setLoadOnStartup(1);registrationBean.addUrlMappings(/hystrix.stream);registrationBean.setName(HystrixMetricsStreamServlet);return registrationBean;}}
2监控测试
启动1个eureka7001
启动80019001 3观察监控窗口
9001监控8001 - 填写监控地址 - http://localhost:8001/hystrix.stream 到 http://localhost:9001/hystrix页面的输入框。 测试地址
http://localhost:8001/payment/circuit/1
http://localhost:8001/payment/circuit/-1 测试通过
先访问正确地址再访问错误地址再正确地址会发现图示断路器都是慢慢放开的。 九、GateWay服务网关
9.1、GateWay基本概念
9.1.1、GateWay是什么
Gateway是在Spring生态系统之上构建的API网关服务基于Spring 5Spring Boot 2和Project Reactor等技术。
Gateway旨在提供一种简单而有效的方式来对API进行路由以及提供一些强大的过滤器功能例如熔断、限流、重试等。
SpringCloud Gateway是Spring Cloud的一个全新项目基于Spring 5.0Spring Boot 2.0和Project Reactor等技术开发的网关它旨在为微服务架构提供—种简单有效的统一的API路由管理方式。
SpringCloud Gateway作为Spring Cloud 生态系统中的网关目标是替代Zuul在Spring Cloud 2.0以上版本中没有对新版本的Zuul 2.0以上最新高性能版本进行集成仍然还是使用的Zuul 1.x非Reactor模式的老版本。而为了提升网关的性能SpringCloud Gateway是基于WebFlux框架实现的而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。
Spring Cloud Gateway的目标提供统一的路由方式且基于Filter链的方式提供了网关基本的功能例如安全监控/指标和限流。 9.1.2、微服务架构中网关的位置 9.1.3、有Zuul了怎么又出来Gateway我们为什么选择Gateway?
1、netflix不太靠谱zuul2.0一直跳票迟迟不发布。
① 一方面因为Zuul1.0已经进入了维护阶段而且Gateway是SpringCloud团队研发的是亲儿子产品值得信赖。而且很多功能Zuul都没有用起来也非常的简单便捷。
② Gateway是基于异步非阻塞模型上进行开发的性能方面不需要担心。虽然Netflix早就发布了最新的Zuul 2.x但Spring Cloud貌似没有整合计划。而且Netflix相关组件都宣布进入维护期不知前景如何
③ 多方面综合考虑Gateway是很理想的网关选择。 2、SpringCloud Gateway具有如下特性
① 基于Spring Framework 5Project Reactor和Spring Boot 2.0进行构建
② 动态路由能够匹配任何请求属性
③ 可以对路由指定Predicate (断言)和Filter(过滤器)
④ 集成Hystrix的断路器功能
⑤ 集成Spring Cloud 服务发现功能
⑥ 易于编写的Predicate (断言)和Filter (过滤器)
⑦ 请求限流功能
⑧ 支持路径重写。 3、SpringCloud Gateway与Zuul的区别
① 在SpringCloud Finchley正式版之前Spring Cloud推荐的网关是Netflix提供的Zuul。
② Zuul 1.x是一个基于阻塞I/O的API Gateway。
③ Zuul 1.x基于Servlet 2.5使用阻塞架构它不支持任何长连接(如WebSocket)Zuul的设计模式和Nginx较像每次I/О操作都是从工作线程中选择一个执行请求线程被阻塞到工作线程完成但是差别是Nginx用C实现Zuul用Java实现而JVM本身会有第-次加载较慢的情况使得Zuul的性能相对较差。
④ Zuul 2.x理念更先进想基于Netty非阻塞和支持长连接但SpringCloud目前还没有整合。Zuul .x的性能较Zuul 1.x有较大提升。在性能方面根据官方提供的基准测试,Spring Cloud Gateway的RPS(每秒请求数)是Zuul的1.6倍。
⑤ Spring Cloud Gateway建立在Spring Framework 5、Project Reactor和Spring Boot2之上使用非阻塞API。
⑥ Spring Cloud Gateway还支持WebSocket并且与Spring紧密集成拥有更好的开发体验 9.1.4、GateWay非阻塞异步模型
Zuul1.x模型
Springcloud中所集成的Zuul版本采用的是Tomcat容器使用的是传统的Serviet IO处理模型。
Servlet的生命周期servlet由servlet container进行生命周期管理。
1、container启动时构造servlet对象并调用servlet init()进行初始化
2、container运行时接受请求并为每个请求分配一个线程一般从线程池中获取空闲线程然后调用service)
3、container关闭时调用servlet destory()销毁servlet。 上述模式的缺点
Servlet是一个简单的网络IO模型当请求进入Servlet container时Servlet container就会为其绑定一个线程在并发不高的场景下这种模型是适用的。但是一旦高并发(如抽风用Jmeter压)线程数量就会上涨而线程资源代价是昂贵的上线文切换内存消耗大严重影响请求的处理时间。在一些简单业务场景下不希望为每个request分配一个线程只需要1个或几个线程就能应对极大并发的请求这种业务场景下servlet模型没有优势。
所以Zuul 1.X是基于servlet之上的一个阻塞式处理模型即Spring实现了处理所有request请求的一个servlet (DispatcherServlet)并由该servlet阻塞式处理。所以SpringCloud Zuul无法摆脱servlet模型的弊端。 Gateway模型
传统的Web框架比如说: Struts2SpringMVC等都是基于Servlet APl与Servlet容器基础之上运行的。
但是在Servlet3.1之后有了异步非阻塞的支持。而WebFlux是一个典型非阻塞异步的框架它的核心是基于Reactor的相关API实现的。相对于传统的web框架来说它可以运行在诸如NettyUndertow及支持Servlet3.1的容器上。非阻塞式函数式编程(Spring 5必须让你使用Java 8)。
Spring WebFlux是Spring 5.0 引入的新的响应式框架区别于Spring MVC它不需要依赖Servlet APl它是完全异步非阻塞的并且基于Reactor来实现响应式流规范。 9.2、GateWay工作流程
9.2.1、三大核心概念
1、Route(路由) - 路由是构建网关的基本模块它由ID目标URI一系列的断言和过滤器组成如断言为true则匹配该路由。
2、Predicate(断言) - 参考的是Java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数)如果请求与断言相匹配则进行路由。
3、Filter(过滤) - 指的是Spring框架中GatewayFilter的实例使用过滤器可以在请求被路由前或者之后对请求进行修改。
web请求通过一些匹配条件定位到真正的服务节点。并在这个转发过程的前后进行一些精细化控制。
predicate就是我们的匹配条件而fliter就可以理解为一个无所不能的拦截器。有了这两个元素再加上目标uri就可以实现一个具体的路由了。
举例我去医院看牙科请求门卫大爷Filter过滤说不管你要看什么必须先做核酸。当我做完核酸后门卫大爷让我进去了。这时我拿着手机上的挂号信息与医院的挂号信息相匹配Predicate断言匹配上了我可以找大夫看病了路由。 9.2.2、工作流程 客户端向Spring Cloud Gateway发出请求。然后在Gateway Handler Mapping 中找到与请求相匹配的路由将其发送到GatewayWeb Handler。
Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post执行业务逻辑。
Filter在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等在“post”类型的过滤器中可以做响应内容、响应头的修改日志的输出流量监控等有着非常重要的作用。
核心逻辑路由转发 执行过滤器链。 9.3、GateWay入门配置
9.3.1、Gateway9527搭建
1新建cloud-gateway-gateway9527 2pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdcloud2020/artifactIdgroupIdcom.atguigu.springcloud/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdcloud-gateway-gateway9527/artifactIddependencies!--gateway--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-gateway/artifactId/dependency!--eureka-client--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependency!-- 引入自己定义的api通用包可以使用Payment支付Entity --dependencygroupIdcom.atguigu.springcloud/groupIdartifactIdcloud-api-commons/artifactIdversion${project.version}/version/dependency!--一般基础配置类--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies/project
3yml
server:port: 9527spring:application:name: cloud-gatewayeureka:instance:hostname: cloud-gateway-serviceclient: #服务提供者provider注册进eureka服务列表内service-url:register-with-eureka: truefetch-registry: truedefaultZone: http://eureka7001.com:7001/eureka
4主启动类
SpringBootApplication
EnableEurekaClient
public class GateWayMain9527 {public static void main(String[] args) {SpringApplication.run(GateWayMain9527.class, args);}
}
5查看cloud-provider-payment8001看看controller的访问地址
get方法和lb方法 我们目前不想暴露8001端口希望在8001外面套一层9527。
6修改yml
server:port: 9527spring:application:name: cloud-gateway#############################新增网关配置###########################cloud:gateway:routes:- id: payment_routh #payment_route #路由的ID没有固定规则但要求唯一建议配合服务名uri: http://localhost:8001 #匹配后提供服务的路由地址#uri: lb://cloud-payment-service #匹配后提供服务的路由地址predicates:- Path/payment/get/** # 断言路径相匹配 的进行路由- id: payment_routh2 #payment_route #路由的ID没有固定规则但要求唯一建议配合服务名uri: http://localhost:8001 #匹配后提供服务的路由地址#uri: lb://cloud-payment-service #匹配后提供服务的路由地址predicates:- Path/payment/lb/** # 断言路径相匹配的进行路由
####################################################################eureka:instance:hostname: cloud-gateway-serviceclient: #服务提供者provider注册进eureka服务列表内service-url:register-with-eureka: truefetch-registry: truedefaultZone: http://eureka7001.com:7001/eureka7测试
启动7001、8001、9527。 添加网关前 - http://localhost:8001/payment/get/1
添加网关后 - http://localhost:9527/payment/get/1
两者访问成功返回相同结果 9.4、GateWay配置路由的两种方式
9.4.1、第一种yml
详细步骤请看9.3.1。 9.4.2、第二种代码中注入RouteLocator的Bean
业务需求通过9527网关访问到外网的百度新闻网址。
1创建配置类
Configuration
public class GateWayConfig {Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){RouteLocatorBuilder.Builder routes routeLocatorBuilder.routes();routes.route(path_route_atguigu,r - r.path(/guonei).uri(http://news.baidu.com/guonei)).build();return routes.build();}
}
2测试
浏览器输入http://localhost:9527/guonei返回页面不存在_百度搜索相同的页面。 9.5、GateWay配置动态路由
9.5.1、实现
默认情况下Gateway会根据注册中心注册的服务列表以注册中心上微服务名为路径创建动态路由进行转发从而实现动态路由的功能不写死一个地址。 1启动
eureka7001
payment8001/8002 2pom
!--eureka-client--
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId
/dependency
3yml
server:port: 9527spring:application:name: cloud-gateway#############################新增网关配置###########################cloud:gateway:discovery:locator:enabled: true #开启从注册中心动态创建路由的功能利用微服务名进行路由routes:- id: payment_routh #payment_route #路由的ID没有固定规则但要求唯一建议配合服务名#uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-service #匹配后提供服务的路由地址predicates:- Path/payment/get/** # 断言路径相匹配的进行路由- id: payment_routh2 #payment_route #路由的ID没有固定规则但要求唯一建议配合服务名#uri: http://localhost:8001 #匹配后提供服务的路由地址uri: lb://cloud-payment-service #匹配后提供服务的路由地址predicates:- Path/payment/lb/** # 断言路径相匹配的进行路由
####################################################################eureka:instance:hostname: cloud-gateway-serviceclient: #服务提供者provider注册进eureka服务列表内service-url:register-with-eureka: truefetch-registry: truedefaultZone: http://eureka7001.com:7001/eureka4测试
浏览器输入 - http://localhost:9527/payment/lb
结果不停刷新页面8001/8002两个端口切换。 9.6、GateWay常用的Predicate
The After Route Predicate Factory 此时间可以使用ZonedDateTime打印。
这个After大多用在维护开服时间比如游戏准备22年10月1日开服那用After可以设置此时间之后的路由才好使。 The Before Route Predicate Factory
与After类似。 The Between Route Predicate Factory
与After类似两个时间之间用逗号分隔。 The Cookie Route Predicate Factory
两个参数一个是Cookie name另一个是正则表达式。
路由规则会通过获取对应的Cookie name值和正则表达式去匹配如果匹配上就会执行路由如果没有匹配上则不执行。 打开DOS命令行进行测试
curl http://localhost:9527/payment/lb //不带Cookie测试结果肯定不能访问curl http://localhost:9527/payment/lb --cookie usernamejcy //带上Cookie匹配成功 The Header Route Predicate Factory
两个参数一个是属性名称和一个正则表达式这个属性值和正则表达式匹配则执行。 打开DOS命令行进行测试
# 带指定请求头的参数的CURL命令
curl http://localhost:9527/payment/lb -H X-Request-Id:123 9.7、GateWay的Filter
9.7.1、是什么
路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应路由过滤器只能指定路由进行使用。Spring Cloud Gateway内置了多种路由过滤器他们都由GatewayFilter的工厂类来产生。 9.7.2、常见的过滤器
总共过滤器有31种之多。 9.7.3、自定义过滤器
自定义全局GlobalFilter
两个主要接口介绍
GlobalFilterOrdered
能干什么
全局日志记录统一网关鉴权…
Component
Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {Overridepublic MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info(***********come in MyLogGateWayFilter: new Date());String uname exchange.getRequest().getQueryParams().getFirst(uname);if(uname null) {log.info(*******用户名为null非法用户o(╥﹏╥)o);exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);return exchange.getResponse().setComplete();}return chain.filter(exchange);}Overridepublic int getOrder() {return 0;}
}
测试分别启动
EurekaMain7001
PaymentMain8001
PaymentMain8002
GateWayMain9527 浏览器输入
http://localhost:9527/payment/lb - 访问异常
http://localhost:9527/payment/lb?unameabc - 正常访问 十、SpringCloud Config分布式配置中心
10.1、介绍
分布式系统面临的配置问题
微服务意味着要将单体应用中的业务拆分成一个个子服务每个服务的粒度相对较小因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行所以一套集中式的、动态的配置管理设施是必不可少的。
SpringCloud提供了ConfigServer来解决这个问题我们每一个微服务自己带着一个application.yml上百个配置文件的管理.…… 比如你现在有40个微服务都用的一个叫test的数据库如果我们修改了数据库的名字那还要每个微服务的配置文件都改一遍吗所以我们需要Config进行集中式管理。 是什么
SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。 怎么玩
SpringCloud Config分为服务端和客户端两部分。
● 服务端也称为分布式配置中心它是一个独立的微服务应用用来连接配置服务器并为客户端提供获取配置信息加密/解密信息等访问接口。
● 客户端则是通过指定的配置中心来管理应用资源以及与业务相关的配置内容并在启动的时候从配置中心获取和加载配置信息配置服务器默认采用git来存储配置信息这样就有助于对环境配置进行版本管理并且可以通过git客户端工具来方便的管理和访问配置内容。 能干嘛
● 集中管理配置文件。
● 不同环境不同配置动态化的配置更新分环境部署比如dev/test/prod/beta/release。
● 运行期间动态调整配置不再需要在每个服务部署的机器上编写配置文件服务会向配置中心统一拉取配置自己的信息。
● 当配置发生变动时服务不需要重启即可感知到配置的变化并应用新的配置。
● 将配置信息以REST接口的形式暴露 - post/crul访问刷新即可… 10.2、Config服务端配置与测试
1用你自己的账号在Github或者码云上新建一个名为springcloud-config的新Repository 2获取springcloud-config的Git地址SSH
3本地硬盘目录上新建Git仓库并Clone
在springcloud-config的文件夹种创建三个配置文件为本次教学使用的。随后git add .git commit -m sthpush等一系列上传操作上传到springcloud-config的新Repository。
● config-dev.yml
config:info: master branch,springcloud-config/config-dev.yml version7
● config-prod.yml
config:info: master branch,springcloud-config/config-prod.yml version1
● config-test.yml
config:info: master branch,springcloud-config/config-test.yml version1 10.3、Config配置总控中心搭建
1新建cloud-config-center-3344 2pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdcloud2020/artifactIdgroupIdcom.atguigu.springcloud/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdcloud-config-center-3344/artifactIddependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-config-server/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies/project
3YML配置文件
server:port: 3344spring:application:name: cloud-config-center #注册进Eureka服务器的微服务名cloud:config:server:git:uri: https://gitee.com/ak/springcloud-config.git #GitHub上面的git仓库名字
# username: xxxqq.com
# password: 123456####搜索目录search-paths:- springcloud-config####读取分支label: master#服务注册到eureka地址
eureka:client:service-url:defaultZone: http://localhost:7001/eureka
4主启动类
SpringBootApplication
EnableConfigServer
public class ConfigCenterMain3344 {public static void main(String[] args) {SpringApplication.run(ConfigCenterMain3344.class, args);}
}
5Windows下修改hosts文件增加映射
127.0.0.1 config-3344.com 6测试通过Config微服务是否可以从Github上获取配置内容
依次启动7001、3344
访问http://config-3344.com:3344/master/config-dev.yml 10.4、Config客户端配置与测试
1新建cloud-config-client-3355 2pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdcloud2020/artifactIdgroupIdcom.atguigu.springcloud/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdcloud-config-client-3355/artifactIddependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-config/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies/project
3创建bootstrap.yml
server:port: 3355spring:application:name: config-clientcloud:#Config客户端配置config:label: master #分支名称name: config #配置文件名称profile: dev #读取后缀名称 上述3个综合master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.ymluri: http://localhost:3344 #配置中心地址k#服务注册到eureka地址
eureka:client:service-url:defaultZone: http://localhost:7001/eureka
4主启动类
EnableEurekaClient
SpringBootApplication
public class ConfigClientMain3355 {public static void main(String[] args) {SpringApplication.run(ConfigClientMain3355.class, args);}
}
5业务类
RestController
RefreshScope
public class ConfigClientController {Value(${config.info})private String configInfo;GetMapping(/configInfo)public String getConfigInfo(){return configInfo;}}
6测试
启动7001、3344、3355
访问http://localhost:3355/configInfo 成功的实现了客户端3355访问SpringCloud Config3344通过GitHub获取配置信息。 7随之而来的问题
Linux运维修改GitHub上的配置文件内容做调整。刷新3344发现ConfigServer配置中心立刻响应。刷新3355发现ConfigClient客户端没有任何响应。3355没有变化除非自己重启或者重新加载。难到每次运维修改配置文件客户端都需要重启噩梦。 10.5、Config动态刷新之手动版
避免每次更新配置都要重启客户端微服务3355。
1修改3355模块POM引入actuator监控
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId
/dependency
2修改YML暴露监控端口
# 暴露监控端点
management:endpoints:web:exposure:include: *
3RefreshScope业务类Controller修改
RestController
RefreshScope
public class ConfigClientController {Value(${config.info})private String configInfo;GetMapping(/configInfo)public String getConfigInfo() {return configInfo;}}
4运维人员发送Post请求刷新3355
curl -X POST http://localhost:3355/actuator/refresh 5测试
启动7001、3344、3355。
修改GitHub上的版本号比如现在是1版本改为10。
刷新3344网址看版本号是否跟着改变http://config-3344.com:3344/master/config-dev.yml
刷新3355网址看版本号是否跟着改变http://localhost:3355/configInfo 6出现的问题
假如有多个微服务客户端3355、3366、3377.......那每个服务都要运维通过curl执行一次post请求手动刷新很显然有点麻烦那能不能用广播的形式一次通知处处生效当然可以下一章消息总线Bus见...... 十一、SpringCloud Bus消息总线
11.1、介绍
Spring Cloud Bus配合Spring Cloud Config使用可以实现配置的动态刷新。
Spring Cloud Bus是用来将分布式系统的节点与轻量级消息系统链接起来的框架它整合了Java的事件处理机制和消息中间件的功能。Spring Cloud Bus目前支持RabbitMQ和Kafka。 什么是总线
在微服务架构的系统中通常会使用轻量级的消息代理来构建一个共用的消息主题并让系统中所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费所以称它为消息总线。在总线上的各个实例都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息。 基本原理
ConfigClient实例都监听MQ中同一个topic(默认是Spring Cloud Bus)。当一个服务刷新数据的时候它会把这个信息放入到Topic中这样其它监听同一Topic的服务就能得到通知然后去更新自身的配置。 11.2、Bus之RabbitMQ环境配置
安装步骤省略.....
开启RabbitMQ服务 11.3、创建3366跟3355一样
1新建cloud-config-client-3366 2pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdcloud2020/artifactIdgroupIdcom.atguigu.springcloud/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdcloud-config-client-3366/artifactIddependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-config/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies/project
3bootstrap.yml配置文件
server:port: 3366spring:application:name: config-clientcloud:#Config客户端配置config:label: master #分支名称name: config #配置文件名称profile: dev #读取后缀名称 上述3个综合master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.ymluri: http://localhost:3344 #配置中心地址#服务注册到eureka地址
eureka:client:service-url:defaultZone: http://localhost:7001/eureka# 暴露监控端点
management:endpoints:web:exposure:include: *
4主启动类
EnableEurekaClient
SpringBootApplication
public class ConfigClientMain3366 {public static void main(String[] args) {SpringApplication.run(ConfigClientMain3366.class,args);}
}
5业务类
RestController
RefreshScope
public class ConfigClientController {Value(${server.port})private String serverPort;Value(${config.info})private String configInfo;GetMapping(/configInfo)public String configInfo() {return serverPort: serverPort\t\n\n configInfo: configInfo;}}
6设计思想
1、利用消息总线触发一个客户端/bus/refresh,而刷新所有客户端的配置。
2、利用消息总线触发一个服务端ConfigServer的/bus/refresh端点而刷新所有客户端的配置。 第二种的架构显然更加适合第一种不适合的原因如下
打破了微服务的职责单一性因为微服务本身是业务模块它本不应该承担配置刷新的职责。
破坏了微服务各节点的对等性。
有一定的局限性。例如微服务在迁移时它的网络地址常常会发生变化此时如果想要做到自动刷新那就会增加更多的修改。 11.4、Bus动态刷新全局广播配置实现
给3344配置中心服务端添加消息总线支持 1pom
!--添加消息总线RabbitMQ支持--
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-bus-amqp/artifactId
/dependency
2YML配置文件
server:port: 3344spring:application:name: cloud-config-center #注册进Eureka服务器的微服务名cloud:config:server:git:uri: https://gitee.com/ak/springcloud-config.git #GitHub上面的git仓库名字
# username: xxxqq.com
# password: 123456####搜索目录search-paths:- springcloud-config####读取分支label: master#rabbitmq相关配置--------------------------
rabbitmq:host: localhostport: 5672username: guestpassword: guest#服务注册到eureka地址
eureka:client:service-url:defaultZone: http://localhost:7001/eureka##rabbitmq相关配置,暴露bus刷新配置的端点--------------------------
management:endpoints: #暴露bus刷新配置的端点web:exposure:include: bus-refresh
给3355客户端添加消息总线支持
1pom
!--添加消息总线RabbitMQ支持--
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-bus-amqp/artifactId
/dependency
2YML配置文件
server:port: 3355spring:application:name: config-clientcloud:#Config客户端配置config:label: master #分支名称name: config #配置文件名称profile: dev #读取后缀名称 上述3个综合master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.ymluri: http://localhost:3344 #配置中心地址k#rabbitmq相关配置 15672是Web管理界面的端口5672是MQ访问的端口----------------------rabbitmq:host: localhostport: 5672username: guestpassword: guest#服务注册到eureka地址
eureka:client:service-url:defaultZone: http://localhost:7001/eureka# 暴露监控端点
management:endpoints:web:exposure:include: *
给3366客户端添加消息总线支持
1pom
!--添加消息总线RabbitMQ支持--
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-bus-amqp/artifactId
/dependency
2YML配置文件
server:port: 3366spring:application:name: config-clientcloud:#Config客户端配置config:label: master #分支名称name: config #配置文件名称profile: dev #读取后缀名称 上述3个综合master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.ymluri: http://localhost:3344 #配置中心地址#rabbitmq相关配置 15672是Web管理界面的端口5672是MQ访问的端口-----------------------rabbitmq:host: localhostport: 5672username: guestpassword: guest#服务注册到eureka地址
eureka:client:service-url:defaultZone: http://localhost:7001/eureka# 暴露监控端点
management:endpoints:web:exposure:include: *
测试
1依次启动7001、3344、3355、3366
2依次访问下面的地址看版本号是多少
http://config-3344.com:3344/master/config-dev.yml
http://localhost:3355/configInfo
http://localhost:3366/configInfo
版本号得出都为1。 3运行在Github上修改版本为2然后发布post请求
curl -X POST http://localhost:3344/actuator/bus-refresh
4再次访问那三个地址发现版本已经全部变为了2 11.5、Bus动态刷新定点通知
需求我们不想全部都通知只想定点通知比如只通知3355不通知3366
公式http://localhost:3344/actuator/bus-refresh/{destination}
/bus/refresh请求不再发送到具体的服务实例上而是发给config server通过destination参数类指定需要更新配置的服务或实例。
实现我们运维先将Github上的版本从2改为3然后运行下面post请求
curl -X POST http://localhost:3344/actuator/bus-refresh/config-client:3355 十二、SpringCloud Stream消息驱动
12.1、Stream为什么被引入
常见MQ(消息中间件)
ActiveMQRabbitMQRocketMQKafka
有没有一种新的技术诞生让我们不再关注具体MQ的细节我们只需要用一种适配绑定的方式自动的给我们在各种MQ内切换。类似于Hibernate
Cloud Stream是什么屏蔽底层消息中间件的差异降低切换成本统一消息的编程模型。
其实Hibernate就是这个意思我们不用关心它用的是oracle还是mysql它给我们提供了session.create()我们用就好了不用关心具体的语法我们也不可能所有数据库都精通。 12.2、Binder介绍
官方定义Spring Cloud Stream是一个构建消息驱动微服务的框架。
应用程序通过inputs或者outputs来与Spring Cloud Stream中binder对象交互。
通过我们配置来binding(绑定)而Spring Cloud Stream 的binder对象负责与消息中间件交互。所以我们只需要搞清楚如何与Spring Cloud Stream交互就可以方便使用消息驱动的方式。
通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动。
Spring Cloud Stream为一些供应商的消息中间件产品提供了个性化的自动化配置实现引用了发布-订阅、消费组、分区的三个核心概念。
目前仅支持RabbitMQ、 Kafka。 12.3、Stream的设计思想
为什么用Cloud Stream
比方说我们用到了RabbitMQ和Kafka由于这两个消息中间件的架构上的不同像RabbitMQ有exchangekafka有Topic和Partitions分区。
这些中间件的差异性导致我们实际项目开发给我们造成了一定的困扰我们如果用了两个消息队列的其中一种后面的业务需求我想往另外一种消息队列进行迁移这时候无疑就是一个灾难性的一大堆东西都要重新推倒重新做因为它跟我们的系统耦合了这时候Spring Cloud Stream给我们提供了—种解耦合的方式。 Stream凭什么可以统一底层差异
在没有绑定器这个概念的情况下我们的SpringBoot应用要直接与消息中间件进行信息交互的时候由于各消息中间件构建的初衷不同它们的实现细节上会有较大的差异性通过定义绑定器作为中间层完美地实现了应用程序与消息中间件细节之间的隔离。通过向应用程序暴露统一的Channel通道使得应用程序不需要再考虑各种不同的消息中间件实现。
通过定义绑定器Binder作为中间层实现了应用程序与消息中间件细节之间的隔离。
Binder
INPUT对应于消费者OUTPUT对应于生产者 Stream编码常用注解简介
Spring Cloud Stream标准流程套路 Binder - 很方便的连接中间件屏蔽差异。
Channel - 通道是队列Queue的一种抽象在消息通讯系统中就是实现存储和转发的媒介通过Channel对队列进行配置。
Source和Sink - 简单的可理解为参照对象是Spring Cloud Stream自身从Stream发布消息就是输出接受消息就是输入。 编码API和常用注解 案例说明
1准备RabbitMQ环境
2工程中新建三个子模块
cloud-stream-rabbitmq-provider8801作为生产者进行发消息模块cloud-stream-rabbitmq-consumer8802作为消息接收模块cloud-stream-rabbitmq-consumer8803作为消息接收模块 12.4、Stream消息驱动之生产者发送
1创建cloud-stream-rabbitmq-provider8801 2pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdcloud2020/artifactIdgroupIdcom.atguigu.springcloud/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdcloud-stream-rabbitmq-provider8801/artifactIddependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-stream-rabbit/artifactId/dependency!--基础配置--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies/project
3YML配置文件
server:port: 8801spring:application:name: cloud-stream-providercloud:stream:binders: # 在此处配置要绑定的rabbitmq的服务信息defaultRabbit: # 表示定义的名称用于于binding整合type: rabbit # 消息组件类型environment: # 设置rabbitmq的相关的环境配置spring:rabbitmq:host: localhostport: 5672username: guestpassword: guestbindings: # 服务的整合处理output: # 这个名字是一个通道的名称destination: studyExchange # 表示要使用的Exchange名称定义content-type: application/json # 设置消息类型本次为json文本则设置“text/plain”binder: defaultRabbit # 设置要绑定的消息服务的具体设置eureka:client: # 客户端进行Eureka注册的配置service-url:defaultZone: http://localhost:7001/eurekainstance:lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔默认是30秒lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔默认是90秒instance-id: send-8801.com # 在信息列表时显示主机名称prefer-ip-address: true # 访问的路径变为IP地址
4主启动类
SpringBootApplication
public class StreamMQMain8801 {public static void main(String[] args) {SpringApplication.run(StreamMQMain8801.class,args);}
}
5业务类
public interface IMessageProvider {public String send();
}
EnableBinding(Source.class) //定义消息的推送管道
public class MessageProviderImpl implements IMessageProvider {Resourceprivate MessageChannel output; // 消息发送管道Overridepublic String send(){String serial UUID.randomUUID().toString();output.send(MessageBuilder.withPayload(serial).build());System.out.println(*****serial: serial);return null;}
}
6controller
RestController
public class SendMessageController {Resourceprivate IMessageProvider messageProvider;GetMapping(value /sendMessage)public String sendMessage() {return messageProvider.send();}}
7测试
依次启动7001、RabbitMQ服务、8801
访问http://localhost:8801/sendMessage 12.5、Stream消息驱动之消费者接收
1创建cloud-stream-rabbitmq-consumer8802 2pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdcloud2020/artifactIdgroupIdcom.atguigu.springcloud/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdcloud-stream-rabbitmq-consumer8802/artifactIddependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-stream-rabbit/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!--基础配置--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies/project
3YML配置文件
server:port: 8802spring:application:name: cloud-stream-consumercloud:stream:binders: # 在此处配置要绑定的rabbitmq的服务信息defaultRabbit: # 表示定义的名称用于于binding整合type: rabbit # 消息组件类型environment: # 设置rabbitmq的相关的环境配置spring:rabbitmq:host: localhostport: 5672username: guestpassword: guestbindings: # 服务的整合处理input: # 这个名字是一个通道的名称destination: studyExchange # 表示要使用的Exchange名称定义content-type: application/json # 设置消息类型本次为对象json如果是文本则设置“text/plain”binder: defaultRabbit # 设置要绑定的消息服务的具体设置eureka:client: # 客户端进行Eureka注册的配置service-url:defaultZone: http://localhost:7001/eurekainstance:lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔默认是30秒lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔默认是90秒instance-id: receive-8802.com # 在信息列表时显示主机名称prefer-ip-address: true # 访问的路径变为IP地址
4主启动类
SpringBootApplication
public class StreamMQMain8802 {public static void main(String[] args) {SpringApplication.run(StreamMQMain8802.class,args);}
}
5业务类
Component
EnableBinding(Sink.class)
public class ReceiveMessageListenerController {Value(${server.port})private String serverPort;StreamListener(Sink.INPUT)public void input(MessageString message) {System.out.println(消费者1号,-----接受到的消息: message.getPayload()\t port: serverPort);}
}
6测试
依次启动EurekaMain7001、StreamMQMain8801、StreamMQMain8802
8801发送8802接收消息。 12.6、消息重复消费
1依照8802克隆出来一份运行8803 - cloud-stream-rabbitmq-consumer8803 2启动
依次启动7001、8801、8802、8803别忘记启动RabbitMQ
我们访问http://localhost:8801/sendMessage连续发送两次。
分别看8802和8803接收到的消息发现消息是8802/8803同时都收到了存在重复消费问题。 3如何解决消息重复消费
分组和持久化属性group重要
比如在如下场景中订单系统我们做集群部署都会从RabbitMQ中获取订单信息那如果一个订单同时被两个服务获取到那么就会造成数据错误我们得避免这种情况。这时我们就可以使用Stream中的消息分组来解决。 注意在Stream中处于同一个group中的多个消费者是竞争关系就能够保证消息只会被其中一个应用消费一次。不同组是可以全面消费的重复消费。 4实现不同分组
8802修改YML
group: A_Group 8803修改YML
group: B_Group
结论还是重复消费因为两个在不同组。 5实现相同分组
把8802和8803都改成相同组A_Group。 12.7、消息持久化
通过上述解决了重复消费问题再看看持久化。
停止8802/8803并去除掉8802的分组group: A_Group8803的分组group: A_Group没有去掉。
8801先发送4条消息到RabbitMQ。
先启动8802无分组属性配置后台没有打出来消息。
再启动8803有分组属性配置后台打出来了MQ上的消息。消息持久化体现。 十三、SpringCloud Sleuth分布式请求链路跟踪
13.1、Sleuth介绍
为什么会出现这个技术要解决哪些问题
在微服务框架中一个由客户端发起的请求在后端系统中会经过多个不同的的服务节点调用来协同产生最后的请求结果每一个前段请求都会形成一条复杂的分布式服务调用链路链路中的任何一环出现高延时或错误都会引起整个请求最后的失败。 是什么
Spring Cloud Sleuth提供了一套完整的服务跟踪的解决方案。
在分布式系统中提供追踪解决方案并且兼容支持了zipkin。 13.2、Sleuth之zipkin搭建安装
下载
SpringCloud从F版起已不需要自己构建Zipkin Server了只需调用jar包即可。
Central Repository: io/zipkin/zipkin-server
zipkin-server-2.12.9-exec.jar 运行jar
java -jar zipkin-server-2.12.9-exec.jar 运行控制台
http://localhost:9411/zipkin/ 完整的调用链路
表示一请求链路一条链路通过Trace ld唯一标识Span标识发起的请求信息各span通过parent id关联起来。 —条链路通过Trace ld唯一标识Span标识发起的请求信息各span通过parent id关联起来。 Trace类似于树结构的Span集合表示一条调用链路存在唯一标识。
span表示调用链路来源通俗的理解span就是一次请求信息。 13.3、Sleuth链路监控展现
服务提供者cloud-provider-payment8001
1pom
!--包含了sleuthzipkin--
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-zipkin/artifactId
/dependency
2YML
zipkin:base-url: http://localhost:9411sleuth:sampler:#采样率值介于 0 到 1 之间1 则表示全部采集probability: 1 3controller
GetMapping(/payment/zipkin)
public String paymentZipkin() {return hi ,iam paymentzipkin server fall backwelcome to here, O(∩_∩)O哈哈~;
} 服务消费者cloud-consumer-order80(调用方)
1pom
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-zipkin/artifactId
/dependency
2YML
spring:application:name: cloud-order-servicezipkin:base-url: http://localhost:9411sleuth:sampler:probability: 1
3OrderController
GetMapping(/consumer/payment/zipkin)
public String paymentZipkin() {String result restTemplate.getForObject(http://localhost:8001/payment/zipkin/, String.class);return result;
}
4测试
依次启动7001、8001、80
访问http://localhost/consumer/payment/zipkin多访问几次