SpringCloud知识概括
Posted GeorgeLin98
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud知识概括相关的知识,希望对你有一定的参考价值。
SpringCloud知识概括
SpringCloud简介
SpringCloud与SpringBoot的依赖版本:
- Finchley是基于Spring Boot 2.0.x构建的不再Boot 1.5.x。
- Dalston和Edgware是基于Spring Boot 1.5.x构建的,不支持Spring Boot 2.0.x。
- Camden构建于Spring Boot 1.4.x, 但依然能支持Spring Boot 1.5.x。
SpringCloud组件简介:
SpringCloud组件变化:
Eureka
什么是服务治理:
- Spring Cloud封装了Netflix 公司开发的Eureka模块来实现服务治理。
- 在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。
什么是服务注册与发现:
- Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
- 在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者|服务提供 者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一一个注册中心(存放服务地址相关信息(接口地址))。
Eureka两组件:
- Eureka包含两个组件:Eureka Server和Eureka Client
- Eureka Server提供服务注册服务:各个微服务节点通过配置启动后,会在EurekaServer中进行注册, 这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
- EurekaClient通过注册中心进行访问:是一个Java客户端, 用于简化Eureka Server的交互, 客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)。
Eureka Server使用:
- pom:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- application.yml:
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名字
client:
register-with-eureka: false #表识不向注册中心注册自己
fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://$eureka.instance.hostname:$server.port/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
- 主启动类:使用@EnableEurekaServer。
Eureka Client使用:
- pom:
<dependency>
<groupId>org.springframework.cloud</ groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- application.yml:
eureka:
client:
register-with-eureka: true
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
- 主启动类:使用@EnableEurekaClient。
- 微服务注册名配置说明:
集群Eureka构建:
-
问题:微服务RPC远程服务调用最核心的是什么 可用,试想你的注册中心只有一个only one,它出故障了那就呵呵了,会导致整个为服务环境不可用, 所以 解决办法:搭建Eureka注册中心集群,实现负载均衡+故障容错。
-
Eureka Server改application.yml:
------------集群A:------------
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名字
client:
register-with-eureka: false #表识不向注册中心注册自己
fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://eureka7002.com:7002/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
------------集群B:------------
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com #eureka服务端的实例名字
client:
register-with-eureka: false #表识不向注册中心注册自己
fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
- Eureka Client改application.yml:
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
actuator微服务信息完善:
- 主机名称:服务名称修改:改application.yml
instance:
instance-id: payment8001
- 访问信息有ip信息提示:改application.yml
instance:
prefer-ip-address: true
服务发现Discovery:
- 对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息。
- 代码:
@Resource
private DiscoveryClient discoveryClient;
- 方法:
①discoveryClient.getServices():获取所有服务信息。
②discoveryClient.getInstances(“服务名称”):获取指定服务名称信息。 - 在主启动类上加@EnableDiscoveryClient。
Eureka自我保护:
- 概述:保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式, EurekaServer将会尝试保护其服务注册表中的信息, 不再删除服务注册表中的数据,也就是不会注销任何微服务。
- 如果在Eureka Server的首页看到以下这段提示,则说明Eureka进入了保护模式:
EMERGENCY! EUREKA MAY BE INCORRECTLY CL AIMING INSTANCES ARE UP WHEN THEY'RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
- 为什么产生Eureka自我保护机制?
①为了防止EurekaClient可以正常运行但是与EurekaServer网络不通情况下,EurekaServer不会立刻将EurekaClient服务剔除 - 什么是自我保护模式?
①默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳, EurekaServer将会注销该实例(默认90秒)。但当网络分区故障发生(延时、 卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了。因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过 ”自我保护模式”来解决这个问题一 当EurekaServer节点在时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。
②在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着。
- 综上:
①自我保护模式是一 种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、 稳定。
②一句话:某时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存。
③属于CAP里面的AP分支。
- 怎么禁止自我保护(一般生产环境中不会禁止自我保护):
一、改EurekaSever的application.yml:
#出厂默认,自我保护机制是开启的:
eureka.server.enable-self-preservation = true
二、改EurekaClient的application.yml:
#心跳检测与续约时间
#开发时没置小些,保证服务关闭后注册中心能即使剔除服务
instance :
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
lease-expiration-duration-in-seconds: 2
Zookeeper
注册中心Zookeeper:
- zookeeper是一个分布式协调工具,可以实现注册中心功能。
- 关闭Linux服务器防火墙后启动zookeeper服务器。
- zookeeper服务器取代Eureka服务器,zk作为服务注册中心。
- zookeeper服务节点是临时节点还是持久节点?
①客户端断开连接后配置信息消失,所以是临时节点。
Zookeeper Client使用:
- pom:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
- 改application.yml:
server:
port: 8004
spring:
application:
name: cloud-provider-payment
cloud:
zookeeper:
connect-string: 192.168.136.140:2181
- 主启动类上使用@EnableDiscoveryClient。
①@EnableDiscoveryClient注解是基于spring-cloud-commons依赖,并且在classpath中实现;
②@EnableEurekaClient注解是基于spring-cloud-netflix依赖,只能为eureka作用;
③其实用更简单的话来说,就是如果选用的注册中心是eureka,那么就推荐@EnableEurekaClient,如果是其他的注册中心,那么推荐使用@EnableDiscoveryClient。
- 其他与Eureka没区别。
Consul
Consul简介:
- 是什么:
①Consul是一开源的分布式服务发现和配置管理系统,由HashiCorp公司用Go语言开发。
②提供了微服务系统中的服务治理、I配置中心、控制总线等功能。这些功能中的每一个 都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之Consul提供了一种完整的服务网格解决方案。
③它具有很多优点。包括:基于raft协议,比较简洁;支持健康检查, 同时支持HTTP和DNS协议支持跨数据中心的WAN集群提供图形界面跨平台,支持Linux、Mac、 Windows。 - 能干嘛:
①服务发现:提供HTTP和DNS两种发现方式。
②健康监测:支持多种协议,HTTP、TCP、Docker、Shell脚本定制化。
③KV存储:key , Value的存储方式。
④多数据中心:Consul支持多数据中心。
⑤可视化Web界面。 - 安装运行:
①下载完成后只有一个consul.exe文件,硬盘路径下双击运行。
②使用开发模式启动:consul agent -dev。
③通过以下地址可以访问Consul的首页:http://localhost:8500。
Consul Client使用:
- pom:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
- 改application.yml:
server:
port: 8006
spring:
application:
name: consul-provider-payment
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: $spring.application.name
- 其他与Zookeeper没区别。
三个注册中心异同点:
- CAP:CAP理论关注粒度是数据,而不是整体系统设计的策略
①C:Consistency(强一致性)
②A:Availability(可用性)
③P:Partition tolerance(分区容错) - CAP理论的核心是一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。因此,根据CAP原理将NoSQL数据库分成了满足CA原则、满足CP原则和满足AP原则三大类:
①CA-单点集群,满足一致性,可用性的系统,通常在可扩展性不太强大。
②CP -满足一致性,分区容忍必的系统,通常性能不是特别高。
③AP -满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。 AP(Eureka)
CP(Zookeeper/Consul)
Ribbon
Ribbon简介:
- Spring Cloud Ribbon是基于Netflix Ribbon实现的一 套客户端负载均衡的工具。
- 简单的说,Ribbon是Netflix发布的开源项目, 主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。
- 不过Ribbon目前也进入维护模式,未来的替代方案:LoadBalancer。
- LB(负载均衡):
①集中式LB:
即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5,也可以是软件,如nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方。
②进程内LB:
将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。 Ribbon就属于进程内LB,它只是一个类库, 集成于消费方进程,消费方通过它来获取到服务提供方的地址。
Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。
使用:
- pom:
<dependency>
<groupld> org.springframework.cloud </groupld>
<artifactld> spring-cloud-starter-netflix-ribbon </artifactld>
</dependency>
- 使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
@Configuration
public class ApplicationContextConfig
@LoadBalanced
@Bean
public RestTemplate getRestTemplate()
return new RestTemplate();
Ribbon核心组件IRule:
- IRule:根据特定算法从服务列表中选取一个要访问的服务
①com.netflix.loadbalancer.RoundRobinRule:轮询
②com.netflix.loadbalancer.RandomRule:随机
③com.netflix.loadbalancer.RetryRule:先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试
④WeightedResponseTimeRule :对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
⑤BestAvailableRule :会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
⑥AvailabilityFilteringRule :先过滤掉故障实例,再选择并发较小的实例
⑦ZoneAvoidanceRule:默认规则,复合判断server所在区域的性能和server的可用性选择服务器 - 如何替换:
①官方文档明确给出了警告:这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。
②代码:
----------------配置类----------------
@Configuration
public class MySelfRule
@Bean
public IRule myRule()
return new RandomRule();//定义为随机
----------------主启动类----------------
@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain80
public static void main(String[] args)
SpringApplication.run(OrderMain80.class,args);
Ribbon负载均衡算法:
负载均衡算法: rest接口第几次请求数%服务器集群总数量=实际调用服务器位置下标,每次服务重启动后rest接口计数从1开始。
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD- PAYMENT-SERVICE");
如:
List [0] instances = 127.0.0.1:8002
List [1] instances = 127.0.0.1:8001
8001+ 8002组合成为集群,它们共计2台机器,集群总数为2, 按照轮询算法原理:
当总请求数为1时: 1 %2 =1对应下标位置为1,则获得服务地址为1 27.0.0.1:8001
当总请求数位2时: 2 % 2 =0对应下标位置为0 ,则获得服务地址为127.0.0.1:8002
当总请求数位3时: 3 %2 =1对应下标位置为1 ,则获得服务地址为127.0.0.1:8001
当总请求数位4时: 4 % 2 =0对应下标位置为0 ,则获得服务地址为127.0.0.1:8002
如此类推.....
- 自己试着写一个本地负载均衡器试试:
----------------负债均衡接口----------------
public interface LoadBalancer
//收集服务器总共有多少台能够提供服务的机器,并放到list里面
ServiceInstance instances(List<ServiceInstance> serviceInstances);
----------------负债均衡实现类----------------
@Component
public class MyLB implements LoadBalancer
private AtomicInteger atomicInteger = new AtomicInteger(0);
//坐标
private final int getAndIncrement()
int current;
int next;
do
current = this.atomicInteger.get();
next = current >= 2147483647 ? 0 : current + 1;
while (!this.atomicInteger.compareAndSet(current,next)); //第一个参数是期望值,第二个参数是修改值是
System.out.println("*******第几次访问,次数next: "+next);
return next;
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) //得到机器的列表
int index = getAndIncrement() % serviceInstances.size(); //得到服务器的下标位置
return serviceInstances.get(index);
OpenFeign
简介:
- 是什么:
①Feign是一个声明式WebService客户端。 使用Feign能让编写Web Service客户端更加简单。它的使用方法是定义一个服务接口然后在上面添加注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
②Feign是一个声明式的web服务客户端,让编写web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可。 - Feign能干什么:
①Feign旨在使编写Java Http客户端变得更容易。
②前面在使用Ribbon+ RestTemplate时
,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下
我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。
③Feign集成了Ribbon:
利用Ribbon维护了Payment的服务列表信息, 并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。
Feign和OpenFeign两者区别:
- Feign:
①Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon, 用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。
②pom:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
- OpenFeign:
①OpenFeign是Spring Cloud在Feign的基础 上支持了SpringMVC的注解,如@RequesMapping等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
②pom:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
OpenFeign使用步骤:
- pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 主启动类:@EnableFeignClients
- 微服务调用接口+@FeignClient
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService
@GetMapping(value = "/payment/get/id")
public CommonResult getPaymentById(@PathVariable("id") Long id);
Feign自带负载均衡配置项
OpenFeign超时控制:
- 默认Feign客户端只等待一秒钟, 但是服务端处理需要超过1秒钟,导致Feign客户端不想等待了,直接返回报错。为了避免这样的情况,有时候我们需要设置Feign客户端的超时控制。
- OpenFeign默认支持Ribbon:
- YML文件里需要开启OpenFeign客户端超时控制:
ribbon:
ReadTimeout: 5000
ConnectTimeout: 5000
OpenFeign日志打印功能:
- Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节。说白了就是对Feign接口的调用情况进行监控和输出。
- 日志级别:
①NONE:默认的,不显示任何日志。
②BASIC:仅记录请求方法、URL、 响应状态码及执行时间。
③HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息。
④FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。 - 配置日志bean:
@Configuration
public class FeignConfig
@Bean
Logger.Level feignLoggerLevel()
return Logger.Level.FULL;
- YML文件里需要开启日志的Feign客户端:
logging:
level:
com.atguigu.springcloud.service.PaymentFeignService: debug
Hystrix
分布式系统面临的问题:
- 复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。
- 服务雪崩:
①多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。
②如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。
③对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
④所以通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。
Hystrix是什么:
- 是什么:
①Hystrix是一个用于处理分布式系统的延迟和容错的开源库, 在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
②"断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝) ,向调用方返回-个符合预期的、可处理的备选响应(FallBack) ,而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。 - 能干嘛:
①服务降级
②服务熔断
③接近实时的监控
配置:
- pom:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
服务降级:
- 降级配置:@HystrixCommand
- 主启动类激活:添加注解@EnableCircuitBreaker或者@EnableHystrix。
①这两个注解都是激活hystrix的功能,我们根据上面代码得出来结论,只需要在服务启动类加入@EnableHystrix注解即可,无须增加@EnableCircuitBreaker注解,本身@EnableHystrix注解已经涵盖了EnableCircuitBreaker的功能。
- 设置自身调用超时时间的峰值,峰值内可以正常运行,超过了需要有兜底的方法处理,作服务降级fallback。
//失败
@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"+"哭了哇呜";
每个业务方法对应一个兜底的方法,代码膨胀,可以把统一和自定义的分开。
①没有特别指明就使用统一的。
@DefaultProperties (defaultFallback = "payment_ Global_ FallbackMethod" )
public class PaymentControllerFeign
@Autowired
private PaymentService paymentService;
@GetMapping(" /consumer/payment/id" )
public String paymentInfo(@PathVariable("id") Integer id)
return paymentService . getPaymentInfo(id);
@GetMapping("/consumer/ paymentTimeOuE/id" )
@HystrixCommand
//@HystrixCommand(fallbackMethod = "paymentTimeOutFal lbackMethod")
public String payment TimeOut (@PathVariable("id") Integer id)
return paymentService . paymentTime0ut(id);
//throw new Runt imeException(*"********Exception 2001 ");
public String paymentTime0utF allbackMethod(@PathVariable("id") Integer id)
return "对方系统繁忙或者已经down机,请10秒钟后再次尝试";
- 但是这样还是和业务逻辑混在一起。
①本次案例服务降级处理是在客户端80实现完成的,与服务端8001没有关系,只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦。
------------------接口------------------
@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);
------------------实现类------------------
@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 , (┬_┬)";
---------------application.yml---------------
feign:
hystrix:
enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
服务熔断:
- 代码:
//服务熔断
@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;
-
大神结论:
-
熔断类型:
①熔断打开:请求不再进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入熔断状态。
②熔断关闭:熔断关闭不会对服务进行熔断。
③熔断半开:部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断。 -
断路器在什么情况下开始起作用:
①涉及到断路器的三个重要参数:快照时间窗、请求总数阀值、错误百分比阀值。
<1>快照时间窗:断路器确定是否打开需要统计- 些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。
<2>请求总数阀值:在快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。
<3> 错误百分比阀值:当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阀值情况下,这时候就会将断路器打开。 -
断路器开启或者关闭的条件:
①当满足一定阀值的时候(默认10秒内超过20个请求次数)
②当失败率达到一定的时候(默认10秒内超过50%请求失败)
③到达以上阀值,断路器将会开启
④当开启的时候,所有请求都不会进行转发
⑤一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。重复4和5。 -
断路器打开之后:
①再有请求调用的时候,将不会调用主逻辑,而是直接调用降级allback。通过断路器,实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟的效果。
②原来的主逻辑要如何恢复呢?
<1>对于这一问题,hystrix也为我们实现了自动恢复功能。
<2>当断路器打开,对主逻辑进行熔断之后, hystrix会启动- 个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,
<3>当休眠时间窗到期,断路器将进入半开状态,释放-次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,
<4>主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。 -
All配置:
Hystrix重要概念:
- 服务降级:
①服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示,fallback
②哪些情况会触发降级:
<1>程序运行异常
<2>超时
<3>服务熔断触发服务降级
<4>线程池/信号量打满也会导致服务降级 - 服务熔断:
①类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示
②就是保险丝:服务的降级->进而熔断->恢复调用链路
- 服务限流:秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行。
hystrix工作流程:
服务监控hystrixDashboard:
- 除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,拟统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合, 对监控内容转化成可视化界面。
- 仪表盘工程:
--------------pom.xml-----------------
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
--------------主启动类加@EnableHystrixDashboard-----------------
- 被监控工程:
所有Provider微服务提供类(8001/8002/8003)都需要监控依赖配置
--------------pom.xml-----------------
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
新版本Hystrix需要在主启动类中指定监控路径
--------------主启动类加-----------------
@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;
- 仪表盘地址:localhost:端口号/hystrix
- 如何看仪表盘:
Gateway
Gateway概述:
- Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5, Spring Boot 2和Project Reactor等技术。Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一 些强大的过滤器功能,例如:熔断、限流、重试等。
- SpringCloud Gateway是Spring Cloud的一个全新项目,纡Spring 5.0+ Spring 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链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
Spring Cloud Gateway 使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架。
Gateway简介:
- 是什么:
①Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;但在2.x版本中,zuul的升级一 直跳票, SpringCloud最后自2研发了一个网关替代Zuul,那就是SpringCloud Gateway-句话: gateway是原zuul1 .x版的替代。 - 能干嘛:
①反向代理
②鉴权
③流量控制
④熔断
⑤日志监控 - 微服务架构中网关在哪里
有了Zuul了怎么又出来了gateway:
-
我们为什么选择Gatway?
①neflix不太靠谱,zuul2.0一直跳票,迟迟不发布:
<1>一方面因为Zuul1.0已经进入 了维护阶段,而且Gateway是SpringCloud团队研发的, 儿子产品,值得信赖。而且很多功能Zuul都没有用起来也非常的简单便捷。
<2>Gateway是基于异步非阻塞模型上进行开发的,性能方面不需要担心。虽然Netflix早就发布 了最新的Zuul 2.x,但Spring Cloud貌似没有整合计划。而且Netflix相关组件都宣布进入维护期;不知前景如何?
<3>多方面综合考虑Gateway是很理想的网关选择。
②Spring Cloud Gateway具有如下特性:
<1>基于Spring Framework 5, Project Relactor和Spring Boot 2.0进行构建;
<2>动态路由:能够匹配任何请求属性;
<3>可以对路由指定Predicate (断言)和Filter (过滤器) ;
<4>集成Hystrix的断路器功能;
<5>集成Spring Cloud服务发现功能;
<6>易于编写的Predicate (断言)和Filter (过滤器) ;
<7>请求限流功能;
<8>支持路径重写。
③Spring Cloud Gateway与Zuul的区别:
<1>Zuul 1.x,是一个基于阻塞|/ 0的API Gateway
<2>Zuul 1.x基于Servlet 2. 5使用阻塞架构它不支持任何长连接(如WebSocket) Zuul的设计模式和Nginx较像,每次|/ O操作都是从工作线程中选择一 个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx用C++实现,Zuul用Java实现,而JVM本身会有第一次加载较慢的情况,使得Zuul的性能相对较差。
<3> Zuul 2.x理念更先进,想基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合。 Zuul 2.x的性能较Zuul 1.x有较大提升在性能方面,根据官方提供的基准测试,Spring Cloud Gateway的RPS (每秒请求数)是Zuul的1.6倍。
<4>Spring Cloud Gateway建立在Spring Framework
<5>Project Reactor和Spring Boot2之上,使用非阻塞API。
<6>Sprina Cloud Gatewav还支持WebSocket. 并目与Sprina紧宓集成拥有更好的开发体验 -
Zuul1.x模型:
①Springcloud中所集成的Zuu|版本,采用的是Tomcat容器,使用的是传统的Servlet I0处理模型。Servlet的生命周期?servlet由servlet container进行生命周期管理。
<1>container启动时构造servlet对象并调用servlet init()进行初始化;
<2>container运行时接受请求,并为每个请求分配一个线程 (一 般从线程池中获取空闲线程) 然后调用service()。
<3>container关闭时调用servlet destory0销毁servlet;
②上述模式的缺点:
<1>servlet是一 个简单的网络IO模型,当请求进入servlet container时, servlet container就会为其绑定一 个线程,在并发不高的场景下这种模型是适用的。但是一旦高并发(比如抽风用jemeter压),线程数量就会上涨,而线程资源代价是昂贵的(上线文切换,内存消耗大)严重影响请求的处理时间。在一些简单业务场景下,不希望为每个request分配一 个线程,只需要1个或几个线程就能应对极大并发的请求,这种业务场景下servlet模型没有优势。
<2>所以Zuul 1.X是基于servlet之上的一个阻塞式处理模型,即spring实现了处理所有request请求的一个servlet (DispatcherServlet) 并由该servlet阻塞式处理处理。所以Springcloud Zuul无法摆脱servlet模型的弊端。 -
GateWay模型:
①传统的Web框架,比如说: struts2, springmvc等 都是基于Servlet API与Servlet容器基础之上运行的。但是在Servlet3.1之后有了异步非阻塞的支持。而WebFlux是一 个 典型非阻塞异步的框架,它的核心是基于Reactor的相关 API实现的。相对于传统的web框架来说,它可以运行在诸如Netty, Undertow及支持Servlet3.1的容器上。非阻塞式+函数式编程(Spring5必须让你使用java8)
②Spring WebFlux是Spring 5.0引入的新的响应式框架,区别于Spring MVC,它不需要依赖Servlet API,它是完全异步非阻塞的,并且基于Reactor来实现响应式流规范。
三大核心概念:
- Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由。
- Predicate(断言):参考的是java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由。
- Filter(过滤):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
- 总体:
Gateway工作流程:
- 官网总结:
①客户端向Spring Cloud Gateway发出请求。然后在Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway Web Handler。
②Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前( “pre” )或之后( “post” )执行业务逻辑。
③Filter在"pre" 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在"post"类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。 - 核心逻辑
以上是关于SpringCloud知识概括的主要内容,如果未能解决你的问题,请参考以下文章