irpas技术客

SpringCloud高频重点面试题,看这一篇就够了。_东北亚大中华区首席搬砖工具人_springcloud面试要点

网络投稿 3449

文章目录 Spring Cloud 相关组件1. Eureka基础知识1.1 什么是服务治理1.2 什么是服务注册与发现1.3 Eureka包含两个组件:Eureka Server 和 Eureka Client1.4 单机Eureka构建步骤1.4.1 服务端1.4.2 客户端1.4.3 将Eureka Client端中的服务消费端注册进Eureka Server称为Service Consumer 1.5 集群Eureka构建步骤1.6 负载均衡1.7 Eureka自我保护(CAP里面的AP分支)1.7.1 产生原因1.7.2 什么是自我保护模式?1.7.3 怎么禁止自我保护1.7.4 Eureka的三大角色1.7.5 Eureka和zookeeper的对比 2. SpringBoot和SpringCloud的区别?3. 微服务的优缺点4.Ribbon4.1是什么?4.2 负载均衡算法? 5.feign5.1 是什么?5.2 能干什么? 6.hystrix6.1 服务雪崩6.1.1 雪崩效应 6.2 是什么?6.3什么是服务熔断6.3.1 熔断机制 6.4服务的降级 7.zuul路由网关7.1 Gateway7.1 Gateway特性 8.SpringCloud config8.1分布式的配置问题8.2是什么? 怎么用? 9.nacos1. nacos是什么?2.命名空间,分组和DataID三者关系,如何分类配置?2.1DataID配置2.2 新建组 TEST_GROUP2.3 新建命名空间 3. Nacos集群搭建4. 各种注册中心比较 10.sentinel10.1 sentinel是什么?10.2 为什么要用?10.3 Sentinel 分为两个部分10.4 流量控制10.4.1 流控模式之直接失败10.4.2 流控模式之关联10.4.3 流控模式之链路10.4.4 Warm up 预热10.4.5 排队等待 10.5 降级规则10.5.1 RT10.5.2 异常比例10.5.3 异常数 10.6 热点Key限流10.7 系统规则10.8 sentinelResource10.8.1 按URL访问 rateLimit/byUrl10.8.2 存在问题:代码耦合10.8.3 解决方法10.8.4 实现原理 10.9 熔断10.9.1 服务熔断无配置10.9.2 只配置fallback10.9.2 只配置blockHandler10.9.3 fallback和blockHandler都配置10.9.4 异常忽略10.9.5 熔断框架比较10.9.6 限流配置规则持久化 11.seata11.1 分布式事务的由来11.2 是什么?11.3 Seata术语11.4 使用11.5 处理过程11.6 如何使用11.7 原理讲解11.7.1 整体机制11.7.2 写隔离11.7.3 读隔离11.7.4 工作机制11.7.4.1 一阶段11.7.4.2 二阶段-回滚11.7.4.3 二阶段-提交11.7.4.4 TCC模式11.7.45 Saga 模式 12.消息总线12.1 是什么?12.2 能干嘛?12.3 什么是总线?

Spring Cloud 相关组件

1. Eureka基础知识 1.1 什么是服务治理

SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理

在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂。因为管理比较复杂,所以需要使用服务治理,来管理服务与服务之间依赖关系,这样就可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

1.2 什么是服务注册与发现

Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心。 而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持 心跳链接 。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。

在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息(比如:服务地址、通讯地址等)以别名方式注册到注册中心中。

另一方(消费者/服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。

RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))

下左图是Eureka系统架构,右图是Dubbo系统架构

1.3 Eureka包含两个组件:Eureka Server 和 Eureka Client Eureka Server提供服务注册中心

各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。

Eureka Client通过注册中心进行访问

是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中表把这个服务节点移除(默认90秒)

1.4 单机Eureka构建步骤 1.4.1 服务端

引入依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>

启动类上加注解:@EnableEurekaServer

/** * @author LongXi * @create 2021-04-29 22:21 */ @SpringBootApplication @EnableEurekaServer public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class,args); } }

写配置文件

server: port: 7001 eureka: instance: hostname: localhost client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://${eureka.instance.hostname}:{server.port}/eureka/ 1.4.2 客户端

将Eureka Client端中的服务提供端注册进Eureka Server作为Service Provider

引入依赖

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>

配置文件

server: port: 8001 spring: application: name: cloud-payment-service # 入驻Eureka服务注册中心的服务名称 datasource: type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包 url: jdbc:mysql://localhost:3306/cloud20?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root eureka: client: #表示是否将自己注册进EurekaServer默认为true。 register-with-eureka: true #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true service-url: #单机版 defaultZone: http://localhost:7001/eureka # 入驻的服务注册中心地址 mybatis: mapperLocations: classpath:mapper/*.xml type-aliases-package: cn.sher6j.springcloud.entities # 所有Entity别名类所在包

启动类加注解:@EnableEurekaClient

/** * @author LongXi * @create 2021-04-25 22:02 */ @SpringBootApplication @EnableEurekaClient public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class, args); } } 1.4.3 将Eureka Client端中的服务消费端注册进Eureka Server称为Service Consumer

配置文件

server: port: 80 spring: application: name: cloud-order-service eureka: client: #表示是否将自己注册进EurekaServer默认为true。 register-with-eureka: false #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true service-url: #单机 defaultZone: http://localhost:7001/eureka

启动类

package cn.sher6j.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; /** * @author sher6j */ @SpringBootApplication @EnableEurekaClient public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class); } }

此时,再回看最开始的Eureka系统架构,在服务注册中心和服务提供者没有集群的情况下,7001端口的微服务就对应了服务注册中心,而该服务不需要向服务注册中心注册自己,8001端口的微服务作为服务提供方入住到服务注册中心,8002端口的微服务作为服务消费方也同样注册到服务注册中心

1.5 集群Eureka构建步骤 Eureka集群原理说明 服务注册中心Eureka Server中分为 服务注册 和 服务发现, 服务注册过程将服务信息注册进服务注册中心,服务发现过程从服务注册中心上获取服务信息,而这个过程的实质就是:将服务名作为key存储,然后根据value取得服务的调用地址。

整个Eureka的过程如果:

先启动Eureka注册中心启动服务提供者服务服务提供者服务将自身信息(比如服务地址)以别名方式注册到Eureka注册中心消费者服务在需要调用接口时,使用服务别名到注册中心获取实际的RPC远程调用地址消费者获得调用地址后,底层实际是利用 HttpClient 技术实现远程调用消费者获得服务地址后会缓存字本地JVM内存中,默认每间隔30秒更新一次服务调用地址

那么微服务RPC远程服务调用最核心的是什么呢???

高可用!!!,如果注册中心只有一个,而这个注册中心出现了故障,那么整个微服务就直接GG了,整个微服务环境就不可用了,所以应该搭建Eureka注册中心集群, 实现 负载均衡 + 故障容错

那怎么实现Eureka注册中心的集群呢? 用一句话总结就是——互相注册,相互守望,如下图所示: 服务注册中心实现相互注册,让彼此都知道对方的存在,也就是注册中心集群中的每一个注册中心都知道整个集群中的其他注册中心,比如如果有三个注册服务中心7001,7002,7003,那么就将7002和7003注册给7001, 将7002和7001注册给7003, 将7003和7001注册给7002, 以此类推,而这些个注册服务中心作为一个整体对外看做一个注册服务中心。

将服务提供方服务8001发布到上面2台Eureka集群配置中将服务消费方服务80发布到上面2台Eureka集群配置中

此时再回看最开始的Eureka微服务架构图,其集群架构图对应本实例应为:

1.6 负载均衡

此时,我们使用80端口的服务消费方来访问 CLOUD-PAYMENT-SERVICE 服务,输入网址http://localhost/consumer/payment/get/1,但是我们每次得到的数据都是:

{ code: 200, message: "查询数据库成功, 端口号:8001", data: { id: 1, serial: "aaaa001" } }

也就是说每次访问的具体微服务都是8001端口的CLOUD-PAYMENT-SERVICE服务,这明显是不符合业务逻辑的,原因就是在消费方代码中我们将服务访问地址写死了,没有实现负载均衡,这显然是不对的,所以我们应该让80访问服务名,而不是具体的服务,同时在配置文件中通过 @LoadBalanced 注解赋予RestTemplate负载均衡能力,该负载均衡默认为轮询方式,所以讲80服务的配置文件修改如下:

package cn.sher6j.springcloud.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * @author sher6j */ @Configuration public class ApplicationContextConfig { @Bean @LoadBalanced//使用该注解赋予RestTemplate负载均衡的能力 public RestTemplate getRestTemplate() { return new RestTemplate(); } } //applicationContext.xml <bean id="" class="">

然后重启80端口,发现每次访问 CLOUD-PAYMENT-SERVICE 服务时,具体的微服务在8001和8002之间进行轮询切换

1.7 Eureka自我保护(CAP里面的AP分支)

保护模式主要用于一组客户端和EurekaServer之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。

如果在Eureka Server的首页看到以下提示,说明Eureka进入了保护模式(上面 单机Eureka构建步骤中提到过):

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING 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不会立刻清理,而是依旧会对该微服务的信息进行保存。

1.7.1 产生原因

Q:为什么会产生Eureka自我保护机制???

A:为了防止 EurekaClient可以正常运行,但是与EurekaServer网络不通 情况下,EurekaServer不会立刻将EurekaClient服务剔除。

1.7.2 什么是自我保护模式?

默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之前无法正常通信,以上行为可能变得非常危险——因为微服务本身是健康的,只是由于网络问题链接不到EurekaServer,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障,网络延时),那么这个节点就会进入自我保护模式。

在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例,宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

1.7.3 怎么禁止自我保护 在EurekaServer端修改配置文件即可设置关闭自我保护机制 eureka: server: # 关闭自我保护机制,保证不可用服务被及时剔除 enable-self-preservation: false # 时间间隔 eviction-interval-time-in-ms: 2000 在EurekaClient端修改配置文件 eureka: instance: instance-id: payment8001 # Eureka客户单向服务端发送心跳的时间间隔,默然是30秒 lease-renewal-interval-in-seconds: 1 # Eureka服务端在收到最后一次心跳后等待时间上限,默然为90秒,超时将剔除服务 lease-expiration-duration-in-seconds: 2

这样就会使EurekaClient客户端的微服务很快死亡。

1.7.4 Eureka的三大角色 Eureka 提供服务注册和发现。Service Provider服务提供方将自身服务注册到Eureka,从而是服务消费方能够找到。Service Consumer 服务消费方从Eureka获取注册服务列表,从而能够消费服务。 1.7.5 Eureka和zookeeper的对比

Zookeeper保证了CP(C:一致性,P:分区容错性),Eureka保证了AP(A:高可用,P:分区容错)

Zookeeper-----当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的信息,但不能容忍直接down掉不可用的。也就是说服务注册功能对高可用性要求比较高,但是zk会出现这样的一种情况,当master节点因为网络故障与其他节点失去联系时,剩余的节点会重新选leader。问题在于,选取leader的时间过长(30~120s),且选取期间zk集群都不可用,这样就会导致选取期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务最终恢复,但是漫长的选择时间导致的注册长期不可用是不能容忍的Eureka则看明白这一点,因此再设计的优先保证了高可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响到正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端再向某个Eureka注册时如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保证注册服务的可用(保证可用性),只不过查到的信息可能不是最新的(不保证一致性)。除此之外Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时就会出现以下几种情况: 1>、Eureka不再从注册列表移除因为长时间没收到心跳而应该过期的服务 2>、Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(保证当前节点可用) 3>、当网络稳定时,当前实例新的注册信息会被同步到其它节点中 Eureka还有客户端缓存功能(Eureka分为客户端程序和服务器端程序两个部分,客户端程序负责向外提供注册与发现服务接口)。所以即便Eureka集群中所有节点都失效,或者发生网络分隔故障导致客户端不能访问任何一台Eureka服务器;Eureka服务的消费者任然可以通过Eureka客户端缓存来获取所有的服务注册信息。甚至最极端的环境下,所有正常的Eureka节点都不对请求产生响应也没有更好的服务器解决方案来解决这种问题时;得益于Eureka的客户端缓存技术,消费者服务仍然可以通过Eureka客户端查询与获取注册服务信息,这点很重要,因此Eureka可以很好的应对网络故障导致部分节点失去联系的情况,而不像Zookeeper那样使整个注册服务瘫痪。

CAP理论:

Consistency:指数据的强一致性。如果写入某个数据成功,之后读取,读到的都是新写入的数据;如果写入失败,读到的都不是写入失败的数据。Availability:指服务的可用性Partition-tolerance:指分区容错 2. SpringBoot和SpringCloud的区别?

SpringBoot专注于快速方便的开发单个个体微服务。

SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,

为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务

SpringBoot可以离开SpringCloud独立使用开发项目, 但是SpringCloud离不开SpringBoot ,属于依赖的关系

SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。

3. 微服务的优缺点

4.Ribbon 4.1是什么?

Ribbon是客户端负载均衡的工具。

Ribbon是本地负载均衡客户端 Nginx服务器负载均衡

客户端所有请求都会交给nginx,然后又nginx实现转发请求。

4.2 负载均衡算法?

轮询随机权重 ,响应速度越快,越被使用自定义故障最少的 5.feign 5.1 是什么?

Feign是一个声明式WebService客户端,使用Feign能让编写Web Service客户端更加简单。 它的使用方法式定义一个接口,然后在上面添加注解。

5.2 能干什么?

Feign旨在使编写Java Http客户端变得容易。 前面使用Ribbon+RestTemplate时 Feign,创建一个接口+注解 Feign也集成了Ribbon

6.hystrix 6.1 服务雪崩

6.1.1 雪崩效应 分布式系统中的服务通信依赖于网络,网络不好,必然会对分布式系统带来很大的影响。在分布式系统中,服务之间相互依赖,如果一个服务之间出现了故障或者网络延迟,在高并发的情况下,会导致线程阻塞,在很短的时间内该服务的线程资源会消耗殆尽,最终使得该服务不可用。由于服务的相互依赖,可能会导致整个系统的不可用,这就是“雪崩效应”。为了防止此类事件的发生,分布式系统必然要采取相应的措施,如熔断机制(Springcloud采用的是Hystrix) 6.2 是什么?

6.3什么是服务熔断

6.3.1 熔断机制 当一个服务出现故障时,请求失败次数超过设定的阀值(默认50)之后,该服务就会开启熔断器,之后该服务就不进行任何业务逻辑操作,执行快速失败,直接返回请求失败的信息。其他依赖于该服务的服务就不会因为得不到响应而造成线程阻塞,这是除了该服务和依赖于该服务的部分功能不可用外,其他功能正常。熔断器还有一个自我修复机制,当一个服务熔断后,经过一段时间(5s)半打开熔断器。半打开的熔断器会检查一部分请求(只能有一个请求)是否正常,其他请求执行快速失败,检查的请求如果响应成功,则可判断该服务正常了,就可关闭该服务的熔断器,反之则继续打开熔断器。这种自我熔断机制和自我修复机制可以使程序更加健壮、也可以为开发和运维减少很多不必要的工作。熔断组件往往会提供一系列的监控,如:服务可用与否、熔断器是否被打开、目前的吞吐量、网络延迟状态的监控等,从而可以让开发人员和运维人员的了解服务的状况。 6.4服务的降级

整体资源快不够了,忍痛将某些服务先关掉,待度过难关,再开启回来。

7.zuul路由网关

7.1 Gateway

是Spring Cloud生态系统中的网关,基于WebFlux实现的,而WebFlux框架底层使用的高性能Reactor模式通信框架Netty 在高并发和非阻塞式通信时非常有优势。

7.1 Gateway特性

路由,断言,过滤

8.SpringCloud config 8.1分布式的配置问题

8.2是什么? 怎么用?

9.nacos 1. nacos是什么?

nacos就是注册中心 + 配置中心的组合

可以替代Eureka做服务注册中心 可以替代Config做配置中心

但是Nacos也有自己的特性,结合【bootstrap.properties 】和【application.properties 】可以实现分区管理、

2.命名空间,分组和DataID三者关系,如何分类配置?

多环境,多项目管理出现的问题 问题1:如何保证指定环境启动时服务能正确读取到Nacos上相应环境的配置文件呢? 问题2:怎么对微服务配置进行管理呢?

解决方案:

NameSpace主要区分部署环境,实现不同环境之间隔离。 Group可以把不通的微服务划分到同一个分组里面去。 Service就是微服务。

2.1DataID配置

配置列表和dataID

bootstrap.properties 配置文件

spring.cloud.nacos.config.server-addr=127.0.0.1:8848 spring.application.name=example

【application.properties 】配置文件 略。。。下图有

在 Nacos Spring Cloud 中,dataId 的完整格式如下:

${prefix}-${spring.profiles.active}.${file-extension}

通过 Spring Cloud 原生注解 @RefreshScope 实现配置自动更新:

@RestController @RequestMapping("/config") @RefreshScope public class ConfigController { @Value("${useLocalCache:false}") private boolean useLocalCache; @RequestMapping("/get") public boolean get() { return useLocalCache; } }

总结如下:

2.2 新建组 TEST_GROUP

在配置文件中指定group就可以了。

2.3 新建命名空间

配置文件里加上命名空间就可以了

3. Nacos集群搭建

hostname -i 能识别的ip

cluster文件

编辑启动脚本,加入P参数

4. 各种注册中心比较

10.sentinel 10.1 sentinel是什么?

Sentinel: 分布式系统的流量防卫兵

10.2 为什么要用?

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 具有以下特征:

丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

10.3 Sentinel 分为两个部分

Sentinel 分为两个部分:

核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。 10.4 流量控制 10.4.1 流控模式之直接失败

QPS,线程数

QPS:御敌于国门之外 线程数:关门打狗

QPS:会把请求挡在门外面 线程:会把请求放进来,处理不过来的时候才报错,模拟controller里睡0.8秒

开两个浏览器,相当于2个线程,第二个会出错

10.4.2 流控模式之关联

我感冒你吃药

支付接口达到阈值以后,限制下订单的接口。

10.4.3 流控模式之链路

NodeSelectorSlot 中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为 machine-root 的虚拟节点,调用链的入口都是这个虚节点的子节点。

一棵典型的调用树如下图所示:

上图中来自入口 Entrance1 和 Entrance2 的请求都调用到了资源 NodeA,

Sentinel 允许只根据某个入口的统计信息对资源限流。

比如我们可以设置 strategy 为 RuleConstant.STRATEGY_CHAIN,同时设置 refResource 为 Entrance1 来表示只有从入口 Entrance1 的调用才会记录到 NodeA 的限流统计当中,而不关心经 Entrance2 到来的调用。

一句话:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,则进行限流),API级别的针对来源。

10.4.4 Warm up 预热

Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。

通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

概述: 当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启动,预热)模式就是为了实现这个目的的。

这个场景主要用于启动需要额外开销的场景,例如建立数据库连接等。

它的实现是在 Guava 的算法的基础上实现的。然而,和 Guava 的场景不同,Guava 的场景主要用于调节请求的间隔,即 Leaky Bucket,而 Sentinel 则主要用于控制每秒的 QPS,即我们满足每秒通过的 QPS 即可,我们不需要关注每个请求的间隔,换言之,我们更像一个 Token Bucket。

我们用桶里剩余的令牌来量化系统的使用率。假设系统每秒的处理能力为 b,系统每处理一个请求,就从桶中取走一个令牌;每秒这个令牌桶会自动掉落b个令牌。令牌桶越满,则说明系统的利用率越低;当令牌桶里的令牌高于某个阈值之后,我们称之为令牌桶"饱和"。

当令牌桶饱和的时候,基于 Guava 的计算上,我们可以推出下面两个公式:

rate?=m*c+ coldrate 其中,rate 为当前请求和上一个请求的间隔时间,而 rate 是和令牌桶中的高于阈值的令牌数量成线形关系的。cold rate 则为当桶满的时候,请求和请求的最大间隔。通常是 coldFactor * rate(stable)。

默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。

10.4.5 排队等待

postMan模拟

10.5 降级规则

sentinel没有半开状态

10.5.1 RT

解释:200毫秒内就的响应,在未来的一秒中,你搞不定,就得跳闸。

用postman测试

模拟

0.2秒就得响应,否则停一秒

10.5.2 异常比例

在访问,就testC就挂了,服务降级了。

postman停了之后,不会走服务降级,直接报错

10.5.3 异常数

执行5次之后会报错,被降级

10.6 热点Key限流

删除试一下,blockHandler = “deal_testHotKey”)

所以一定要用第二种

平时qps一秒一次

特殊参数1=5的时候,每秒200

10.7 系统规则

可以全局限制,整个系统

10.8 sentinelResource

8401引入pom包

点击快了,会限流

关闭8401服务端

流控规则消失了,临时的

10.8.1 按URL访问 rateLimit/byUrl

按资源配置异常处理,有就走自己配置,没有,就走系统自带的

10.8.2 存在问题:代码耦合

10.8.3 解决方法

自定义 CutomerBlockHandler 方法为static

Handler Exception Block Exception

业务类,指定Class,指定blockHandler QPS超过1,做限流 详细关系

10.8.4 实现原理

10.9 熔断 10.9.1 服务熔断无配置

没有配置,直接报出异常,对客户不友好

10.9.2 只配置fallback

参数类型,一定要对上,否则兜不了底

10.9.2 只配置blockHandler

配置异常数

缺了配置文件,sentinel控制台检测不到

只点一次,直接报error,点2次,被sentinel限流

10.9.3 fallback和blockHandler都配置

限流QPS,一秒一个

一秒点一次,报java兜底异常,一秒2次以上,被sentinel限流,

10.9.4 异常忽略

参数是4的话,不会被兜底

10.9.5 熔断框架比较

10.9.6 限流配置规则持久化

引入依赖 添加配置

新建配置 DataId 就是上面配置的DataId

11.seata

http://seata.io/zh-cn/

11.1 分布式事务的由来

全局的事务一致性问题没办法保证。

一句话:一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题。

如何解决:Seata

11.2 是什么?

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。 Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

11.3 Seata术语

TC (Transaction Coordinator) - 事务协调者 维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器 定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器 管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

11.4 使用

用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:

仓储服务:对给定的商品扣除仓储数量。订单服务:根据采购需求创建订单。帐户服务:从用户帐户中扣除余额。 架构图 11.5 处理过程

SEATA 的分布式交易解决方案

11.6 如何使用

加全局事务注解 @GlobalTransactionsl

11.7 原理讲解

11.7.1 整体机制

两阶段提交协议的演变:

一阶段:业务数据和回滚日志记录(undo_log)在同一个本地事务中提交,释放本地锁和连接资源。

二阶段:

提交异步化,非常快速地完成。 回滚通过一阶段的回滚日志进行反向补偿。 11.7.2 写隔离 一阶段本地事务提交前,需要确保先拿到 全局锁 。拿不到 全局锁 ,不能提交本地事务。拿 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。

以一个示例来说明:

两个全局事务 tx1 和 tx2,分别对 a 表的 m 字段进行更新操作,m 的初始值 1000。

tx1 先开始,开启本地事务,拿到本地锁,更新操作 m = 1000 - 100 = 900。本地事务提交前,先拿到该记录的 全局锁 ,本地提交释放本地锁。

tx2 后开始,开启本地事务,拿到本地锁,更新操作 m = 900 - 100 = 800。本地事务提交前,尝试拿该记录的 全局锁 ,tx1 全局提交前,该记录的全局锁被 tx1 持有,tx2 需要重试等待 全局锁 。

tx1 二阶段全局提交,释放 全局锁 。tx2 拿到 全局锁 提交本地事务。

如果 tx1 的二阶段全局回滚,则 tx1 需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。

此时,如果 tx2 仍在等待该数据的 全局锁,同时持有本地锁,则 tx1 的分支回滚会失败。分支的回滚会一直重试,直到 tx2 的 全局锁 等锁超时,放弃 全局锁 并回滚本地事务释放本地锁,tx1 的分支回滚最终成功。

因为整个过程 全局锁 在 tx1 结束前一直是被 tx1 持有的,所以不会发生 脏写 的问题。

11.7.3 读隔离

在数据库本地事务隔离级别 读已提交(Read Committed) 或以上的基础上,Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。

如果应用在特定场景下,必需要求全局的 读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。

SELECT FOR UPDATE 语句的执行会申请 全局锁 ,如果 全局锁 被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。 这个过程中,查询是被 block 住的,直到 全局锁 拿到,即读取的相关数据是 已提交 的,才返回。

出于总体性能上的考虑,Seata 目前的方案并没有对所有 SELECT 语句都进行代理,仅针对 FOR UPDATE 的 SELECT 语句。

11.7.4 工作机制

以一个示例来说明整个 AT 分支的工作过程。

业务表:product

FieldTypeKeyidbigint(20)PRInamevarchar(100)sincevarchar(100)

AT 分支事务的业务逻辑:

update product set name = 'GTS' where name = 'TXC'; 11.7.4.1 一阶段

过程:

解析 SQL:得到 SQL 的类型(UPDATE),表(product),条件(where name = ‘TXC’)等相关的信息。查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据。 select id, name, since from product where name = 'TXC';

得到前镜像:

idnamesince1TXC2014
执行业务 SQL:更新这条记录的 name 为 ‘GTS’。查询后镜像:根据前镜像的结果,通过 主键 定位数据。 select id, name, since from product where id = 1;

得到后镜像:

idnamesince1GTS2014
插入回滚日志:把前后镜像数据以及业务 SQL 相关的信息组成一条回滚日志记录,插入到 UNDO_LOG 表中。 { "branchId": 641789253, "undoItems": [{ "afterImage": { "rows": [{ "fields": [{ "name": "id", "type": 4, "value": 1 }, { "name": "name", "type": 12, "value": "GTS" }, { "name": "since", "type": 12, "value": "2014" }] }], "tableName": "product" }, "beforeImage": { "rows": [{ "fields": [{ "name": "id", "type": 4, "value": 1 }, { "name": "name", "type": 12, "value": "TXC" }, { "name": "since", "type": 12, "value": "2014" }] }], "tableName": "product" }, "sqlType": "UPDATE" }], "xid": "xid:xxx" } 提交前,向 TC 注册分支:申请 product 表中,主键值等于 1 的记录的 全局锁 。本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。将本地事务提交的结果上报给 TC。 11.7.4.2 二阶段-回滚 收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理,详细的说明在另外的文档中介绍。根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句: update product set name = 'TXC' where id = 1; 提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。 11.7.4.3 二阶段-提交 收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。异步任务阶段的分支提交请求将异步和批量地删除相应 UNDO LOG 记录。 11.7.4.4 TCC模式

AT 模式(参考链接 TBD)基于 支持本地 ACID 事务 的 关系型数据库:

一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。 相应的,TCC 模式,不依赖于底层数据资源的事务支持:

一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。 二阶段 commit 行为:调用 自定义 的 commit 逻辑。 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。 所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。

11.7.45 Saga 模式

Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

适用场景

业务流程长、业务流程多参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口

优势:

一阶段提交本地事务,无锁,高性能事件驱动架构,参与者可异步执行,高吞吐补偿服务易于实现

缺点:

不保证隔离性 12.消息总线 12.1 是什么?

配置的

12.2 能干嘛?

12.3 什么是总线?


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #springcloud面试要点 #Eureka基础知识11 #什么是服务治理12 #什么是服务注册与发现13 #Server #