微服务框架组件
- 1、Spring Cloud Netflix和Spring Cloud Alibaba包括哪些组件
- 2、Nacos是CP还是AP?(Nacos配置中心和注册中心)
- 3、Nacos作为注册中心应该选择是CP还是AP?
- 4、Nacos如何实现就进访问?
- 5、Nacos底层负载均衡底层原理
- 6、Nacos1.x注册中心架构流程
- 7、Nacos2.X作为注册中心架构流程
- 8、Nacos中的Distro协议
- 9、Eureka注册中心原理
- 10、Eureka自我保护机制原理
- 11、Eureka和Nacos对比
- 12、Nacos配置中心长轮询机制
- 13、引用Nacos配置的定时任务失效(Nacos工作中遇到问题)
- 14、Nacos加载那些配置,这些配置的优先级?
- 15、Nacos配置中心宕机了,我们的服务还可以读取到配置信息吗,除此之外我们服务再重启是否可以重启成功,以及它读取配置的过程?
- 16、配置中心的技术选型
- 17、Feign底层怎样实现不同服务的不同配置
- 18、生产上为什么Feign第一次调用耗时很长?
- 19、Feign怎样实现认证的传递?
- 20、Feign底层默认使用什么发送HTTP,有什么问题,我们怎样改进?
- 21、谈谈Sentienl中使用的限流算法,Sentinel哪里对这算法进行应用
- 22、谈谈Sentienl服务熔断过程
- 23、请说一下CAP和BASE理论
- 24、请简述2PC流程以及优缺点
- 25、Seata支持那些事务模式?
- 26、简述Seata的AT模式两阶段过程
- 27、Seata中xid怎样通过Feign进行全局传递
- 28、Seata TCC 模式设计思路
- 29、 TCC存在的问题
- 30、Gateway核心概念
- 31、Gateway工作原理
- 32、在Gateway中怎样实现服务平滑迁移?
- 33、Zuul架构以及怎样保证线程安全
- 34、Zuul启动注解@EnableZuulProxy 和@EnableZuulServer区别
1、Spring Cloud Netflix和Spring Cloud Alibaba包括哪些组件
Spring Cloud Netflix,主要由:Eureka
、Ribbon
、Feign
、Hystrix
、Zuul|Gateway
、Config
等组件组成。
Spring Cloud Alibaba,主要由:Nacos
、Sentinel
、Seata
等组件组成。
Apollo 携程、SkyWalking 吴晟(shèng)国产开源的
2、Nacos是CP还是AP?(Nacos配置中心和注册中心)
Nacos即能保证CP,也能保证AP,具体看如何配置,但其实只不过是Nacos中的注册中心能保证CP或AP,Nacos中的配置中心其实没什么CP或AP,因为配置中心的数据是存在一个Mysql中的,只有注册中心的数据需要进行集群节点之间的同步,从而涉及到是CP还是AP,默认是AP模式。
3、Nacos作为注册中心应该选择是CP还是AP?
注册中心应该是AP,如果注册中心是CP的,那么表示,当我们向注册中心注册实例或移除实例时,都要等待注册中心集群中的数据达到一致后,才算注册或移除成功,而这是比较耗时的,随着业务应用规模的增大,应用频繁的上下线,那么就会导致注册中心的压力比较大,会影响到服务发现的效率以及服务调用了,而如果注册中心是AP的,那么注册中心集群不管出现了什么情况,都是可以提供服务的,就算集群节点之间数据出现了不一致,对于业务应用而言,可能拉取到了一个已经下线了的服务节点,但是现在一般的微服务框架或组件都提供了服务容错和重试功能,也可以避免这个问题,而如果是AP,对于注册中心而言就不需要消耗太多的资源来实时的保证数据一致性了,保证最终一致性就可以了,这样注册中心的压力会小一点。
4、Nacos如何实现就进访问?
首先,在Nacos中,一个服务可以有多个实例,并且可以给实例设置cluster-name,就是可以再进一步的给所有实例划分集群,那如果现在某个服务A想要调用服务B,那么Naocs会看调用服务A的实例是属于哪个集群的,并且调用服务B时,那就会调用同样集群下的服务B实例,根据cluster-name来判断两个实例是不是同一个集群,这就是Nacos的就近访问。
5、Nacos底层负载均衡底层原理
通过Ribbon实现的,Ribbon中定义了负载均衡算法,然后基于这些算法从服务实例中获取一个实例为想费方的提供服务
6、Nacos1.x注册中心架构流程
1、服务启动的时候,通过api发起服务注册,来告诉nacos,我可以提供服务了
2、服务消费者在启动的时候会拉取 自已要用的服务的列表。
(这只是启动的时候拉取,那平常有上下线服务怎么办呢?定时拉取)
3、消费者会每10秒进行拉取一下数据。拉取我可以调用的服务。
(如果我们只用定时任务拉取配置,那注册服务会有一定的滞后性,那怎么让它具有实时性呢?下面udp协议)
4、Nacos服务检测到有异常(服务上下线)就会发送UDP协议给客户端进行更新
(为什么是udp写协议?
因为udp协议相对于tcp协议来说,他并不是可靠的协议,但他的优点就是他非常快,他耗时比较短,不需要跟自己目标服务器建立长连接,在服务注册这种场景,我们服务消费者要比服务提供者要多很多,所以每一次 服务的更新,nacos需要和成千上万的消费者,去建立tcp的话,他的性能一定是受不了的,所以他会选择一个udp协议进行通知,那有的同学会问了,udp他不可靠,他通知失败了怎么办? 大家可以看一下第三部,我们消费者每10秒还会拉取一下服务数据信息
上面说是检测到异常,那Nacos怎样判断异常的呢? 心跳,
)
5、客户端会每5秒定时发送心跳到服务端,来维持他的一个健康的检查,
6、Nacos定时任务检测:通过每5秒检查一下心跳信息来判断是否超时,就是用当前时间减去上次一心跳的时间,如果超过15秒则将节点设置为非健康状态并进行广播,如果超过30秒则将节点进行移除,说明节点不可用。
7、集群数据同步任务使用协议:Distro(AP) , Raft(CP)
7、Nacos2.X作为注册中心架构流程
8、Nacos中的Distro协议
- Nacos 每个节点自己负责部分的写请求。
- 每个节点会把自己负责的新增数据同步给其他节点。
- 每个节点定时发送自己负责数据的校验值到其他节点来保持数据一致性。
- 每个节点独立处理读请求,及时从本地发出响应。
- 新加入的 Distro 节点会进行全量数据拉取。
(具体操作是轮询所有的 Distro节点,通过向其他的机器发送请求拉取全量数据。)
Nacos1.4.x
Nacos2.x
1、读取方式不同
Nacos2.x无论是读还是写,都会走与当前客户端建立长连接的节点,不走服务端DistroFilter。读请求不同于1.x会打到不同节点上,一直会打到建立长连接的节点上; TODO
2、责任节点的判断
写请求不同于1.x中可能被二次转发,与客户端建立长连接的节点,就是 责任节点 。不同于1.x,基于Service设置责任节点,2.x基于Client设置责任节点。
3、集群同步
与1.x不同的是,2.x责任节点VERIFY任务不再仅发送服务实例列表的摘要md5给非责任节点。责任节点每5s向非责任节点发送VERIFY续;非责任节点定时扫描isNative=false的Client数据,如果超过3分钟没有续租,移除这些非native的Client。
9、Eureka注册中心原理
1、服务启动进行注册
2、集群内部进行数据同步(这里没有设计到什么协议,就是发送http进行数据同步)
3、客户端定时任务每30s拉取一下数据
4、客户端心跳续约,每30s一次
5、每分钟检查亦喜爱实例是否过期,如果过期就将其移除,如果出现大量掉线就进入自我保护
6、优雅下线
10、Eureka自我保护机制原理
Eureka服务端会每15分钟检查所有Eureka 实例正常心跳占比,如果低于85%就会触发自我保护机制。触发了保护机制,Eureka将暂时把这些失效的服务保护起来,不让其过期,但这些服务也并不是永远不会过期。Eureka在启动完成后,每隔60秒会检查一次服务健康状态,如果这些被保护起来失效的服务过一段时间后(默认90秒)还是没有恢复,就会把这些服务剔除。如果在此期间服务恢复了并且实例心跳占比高于85%时,就会自动关闭自我保护机制。
11、Eureka和Nacos对比
1、Nacos中注册中心会定时向消费者主动推送信息,Eureka会定时向注册中心定时拉去服务,如果不主动拉去服务,注册中心不会主动推送。
2、Nacos支持CP和AP模式,Eureka支持AP模式
3、Nacos具备服务优雅上下线和流量管理(API+后台管理页面),而Eureka的后台页面仅供展示,需要使用api操作上下线且不具备流量管理功能。
4、Nacos社区活跃,Eureka开源工作已停止,后续不再有更新和维护
5、从部署来看,Nacos整合了注册中心、配置中心功能,把原来两套集群整合成一套,简化了部署维护
12、Nacos配置中心长轮询机制
Nacos 1.4.x
客户端会轮询向服务端发出一个长连接请求,这个长连接最多30s就会超时,服务端收到客户端的请求会先判断当前是否有配置更新,有则立即返回如果没有服务端会将这个请求拿住“hold”29.5s加入队列,最后0.5s再检测配置文件无论有没有更新都进行正常返回,但等待的29.5s期间有配置更新可以提前结束并返回。
Nacos2.x
1、服务端配置发生变更后,通过长链接通知客户端服务发生变化,客户端再去拉取
2、定时任务每5秒拉取一次
13、引用Nacos配置的定时任务失效(Nacos工作中遇到问题)
1、Schedule执行原理,利用后置处理器ScheduledAnnotationBeanPostProcessor,获取@Schedule标注的方法,然后使用定时任务处理
2、然后使用@RefreshScope标注的对象,@RefreshScope中有个@Scope里面值是Refresh,他创建对象是放到对应的缓存中,我们通过GenericScope#get方法从缓存中获取对应Bean对象,在更新配置刷新容器时候会讲对应的实例对象给清除调用,这样老的数据就会清除调用,我们需要再调用一下这个对应才能创建对应的实例(BeanFactory#getBean 有对应的对象则获取,没有则进行创建),然后对应的定时任务就能正常的运行
3、解决方式:更新配置刷新容器后会发送事件RefreshScopeRefreshedEvent,我们只需监听一下这个事件,之后他就会创建对应的实例,然后定时任务就能正常执行
https://www.mashibing.com/live/2163?r=1370
14、Nacos加载那些配置,这些配置的优先级?
#作用:顺序 #{profile}.{file- extension} nacos-config-prod.yaml #{application.name}.{file-extension} nacos-config.yaml #{application.name} nacos-config #extensionConfigs 扩展配置文件 #sharedConfigs 多个微服务公共配置 redis
15、Nacos配置中心宕机了,我们的服务还可以读取到配置信息吗,除此之外我们服务再重启是否可以重启成功,以及它读取配置的过程?
1、可以从内存,客户端获取了配置中心的配置信息后,会将配置信息在本地保存一份。
2、可以
3、先读取本地文件,如果没有,则远程拉取,拉取成功则写入本地快照,拉取失败,则读取本地快照文件
16、配置中心的技术选型
功能点 | Spring Cloud Config | Apollo | Nacos |
---|---|---|---|
版本管理 | 支持(Git) | 支持 | 支持 |
配置实时推送 | 支持(Spring Cloud Bus) | 支持(HTTP长轮询1s内) | 支持(HTTP长轮询1s内 或者 grpc) |
配置回滚 | 支持(Git) | 支持 | 支持 |
灰度发布 | 支持(调用机器接口) | 支持 | 不支持 |
权限管理 | 支持(依赖Git) | 支持 | 支持 |
配置生效时间 | 重启 | 实时 | 实时 |
审计 | 支持(依赖Git) | 支持 | 不支持 |
多集群 | 支持 | 支持 | 支持 |
多环境 | 支持 | 支持 | 支持 |
client本地缓存 | 不支持 | 支持 | 支持 |
监听查询 | 支持 | 支持 | 支持 |
运维成本 | 高 | 中等 | 较低 |
多语言 | 仅Java | 主流语言,提供了Open API | 主流语言,提供了Open API |
配置项维护 | 基于git | 统一界面 | 统一界面 |
社区活跃度 | 1.8k Star | 27.4k Star | 24.2k Star |
1、社区活跃度
2、自己的技术栈,我们以前 rocketmq 和kafka。rocketmq :不支持指定时间的延时消息、不支持事务消息
Java kafka scala ,我们技术栈是java ,所以我们选择rocketmq
3、产品功能 rocketmq或者kafka技术栈是否hold住
17、Feign底层怎样实现不同服务的不同配置
为不同服务创建不同的Spring上下文,每个服务都对应一个spring上下文,并且以key-value形式存放到Map中key对应服务名称,value对应服务的上下文,我们获取应用的配置时候,就通过服务名称获取对应的上下文,然后从上下文中获取对应的配置
18、生产上为什么Feign第一次调用耗时很长?
ribbon默认是懒加载的,只有第一次调用的时候才会生成ribbon对应的组件,这就会导致首次调用的会很慢的问题。
ribbon:
eager-load:
enabled: true
clients: msb-stock
19、Feign怎样实现认证的传递?
实现接口RequestInterceptor,通过header实现认证传递
package feign;
public interface RequestInterceptor {
void apply(RequestTemplate template);
}
public class FeignAuthRequestInterceptor implements RequestInterceptor {
private String tokenId;
public FeignAuthRequestInterceptor(String tokenId) {
this.tokenId = tokenId;
}
@Override
public void apply(RequestTemplate template) {
template.header("Authorization",tokenId);
}
}
20、Feign底层默认使用什么发送HTTP,有什么问题,我们怎样改进?
Feign底层默认是 JDK自带的HttpURLConnection,它是单线程发送HTTP请求的,不能配置线程池,我们使用Okhttp或者HttpClient来发送http请求,并且它们两个都支持线程池。
常见HTTP客户端
- HttpClient HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 Http 协 议的客户端编程工具包,并且它支持 HTTP 协议最新版本和建议。HttpClient 相比传统 JDK 自带的 URLConnection,提升了易用性和灵活性,使客户端发送 HTTP 请求变得容易,提高了开发的效率。
- Okhttp 一个处理网络请求的开源项目,是安卓端最火的轻量级框架,由 Square 公司贡献,用于替代 HttpUrlConnection 和 Apache HttpClient。OkHttp 拥有简洁的 API、高效的性能,并支持多种协议 (HTTP/2 和 SPDY)。
- HttpURLConnection HttpURLConnection 是 Java 的标准类,它继承自 URLConnection,可用于向指定网站发送 GET 请求、 POST 请求。HttpURLConnection 使用比较复杂,不像 HttpClient 那样容易使用。
- RestTemplate RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 HTTP 服务的方法,能够大大提高客户端的编写效率。
21、谈谈Sentienl中使用的限流算法,Sentinel哪里对这算法进行应用
1、计数器固定窗口算法
计数器固定窗口算法是最简单的限流算法,实现方式也比较简单。就是通过维护一个单位时间内的计数值,每当一个请求通过时,就将计数值加1,当计数值超过预先设定的阈值时,就拒绝单位时间内的其他请求。如果单位时间已经结束,则将计数器清零,开启下一轮的计数。
但是这种实现会有一个问题,举个例子:
假设我们设定1s内允许通过的请求阈值是100,如果有用户在时间窗口的最后几毫秒发送了99个请求,紧接着又在下一个时间窗口开始时发送了99个请求,那么这个用户其实在一秒显然超过了阈值但并不会被限流。其实这就是临界值问题,那么临界值问题要怎么解决呢?
2、计数器滑动窗口算法
计数器滑动窗口法就是为了解决上述固定窗口计数存在的问题而诞生。前面说了固定窗口存在临界值问题,要解决这种临界值问题,显然只用一个窗口是解决不了问题的。假设我们仍然设定1秒内允许通过的请求是200个,但是在这里我们需要把1秒的时间分成多格,假设分成5格(格数越多,流量过渡越平滑),每格窗口的时间大小是200毫秒,每过200毫秒,就将窗口向前移动一格。为了便于理解,可以看下图
图中将窗口划为5份,每个小窗口中的数字表示在这个窗口中请求数,所以通过观察上图,可知在当前时间块(200毫秒)允许通过的请求数应该是70而不是200(只要超过70就会被限流),因为我们最终统计请求数时是需要把当前窗口的值进行累加,进而得到当前请求数来判断是不是需要进行限流。
那么滑动窗口限流法是完美的吗?
细心观察的我们应该能马上发现问题,滑动窗口限流法其实就是计数器固定窗口算法的一个变种。流量的过渡是否平滑依赖于我们设置的窗口格数也就是统计时间间隔,格数越多,统计越精确,但是具体要分多少格我们也说不上来呀...
3、漏桶算法
上面所介绍的两种算法都不能非常平滑的过渡,下面就是漏桶算法登场了
什么是漏桶算法?
漏桶算法以一个常量限制了出口流量速率,因此漏桶算法可以平滑突发的流量。其中漏桶作为流量容器我们可以看做一个FIFO的队列,当入口流量速率大于出口流量速率时,因为流量容器是有限的,当超出流量容器大小时,超出的流量会被丢弃。
下图比较形象的说明了漏桶算法的原理,其中水龙头是入口流量,漏桶是流量容器,匀速流出的水是出口流量。
漏桶算法的特点
- 漏桶具有固定容量,出口流量速率是固定常量(流出请求)
- 入口流量可以以任意速率流入到漏桶中(流入请求)
- 如果入口流量超出了桶的容量,则流入流量会溢出(新请求被拒绝)
不过因为漏桶算法限制了流出速率是一个固定常量值,所以漏桶算法不支持出现突发流出流量。但是在实际情况下,流量往往是突发的。
4、令牌桶算法
令牌桶算法是漏桶算法的改进版,可以支持突发流量。不过与漏桶算法不同的是,令牌桶算法的漏桶中存放的是令牌而不是流量。
那么令牌桶算法是怎么突发流量的呢?
最开始,令牌桶是空的,我们以恒定速率往令牌桶里加入令牌,令牌桶被装满时,多余的令牌会被丢弃。当请求到来时,会先尝试从令牌桶获取令牌(相当于从令牌桶移除一个令牌),获取成功则请求被放行,获取失败则阻塞活拒绝请求。
令牌桶算法的特点
- 最多可以存发b个令牌。如果令牌到达时令牌桶已经满了,那么这个令牌会被丢弃
- 每当一个请求过来时,就会尝试从桶里移除一个令牌,如果没有令牌的话,请求无法通过。
令牌桶算法限制的是平均流量,因此其允许突发流量(只要令牌桶中有令牌,就不会被限流)
流控效果:
快速失败(默认):滑动时间窗口、WarmUp:令牌桶算法、 排队等待:漏斗算法
22、谈谈Sentienl服务熔断过程
服务熔断一般有三种状态:
服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制。
后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法。
尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断关闭状态。
23、请说一下CAP和BASE理论
CAP和BASE是分布式必备理论基础
1、CAP理论
这个定理的内容是指的是在一个分布式系统中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
一致性(C)
一致性意思就是写操作之后进行读操作无论在哪个节点都需要返回写操作的值
可用性(A)
非故障的节点在合理的时间内返回合理的响应
分区容错性(P)
当出现网络分区后,系统能够继续工作。打个比方,这里个集群有多台机器,有台机器网络出现了问题,但是这个集群仍然可以正常工作。
在分布式系统中,网络无法100%可靠,分区其实是一个必然现象,如果我们选择了CA而放弃了P,那么当发生分区现象时,为了保证一致性,这个时候必须拒绝请求,但是A又不允许,所以分布式系统理论上不可能选择CA架构,只能选择CP或者AP架构。
对于CP来说,放弃可用性,追求一致性和分区容错性,我们的zookeeper其实就是追求的强一致。
对于AP来说,放弃一致性(这里说的一致性是强一致性),追求分区容错性和可用性,Nacos就是AP模式,这是很多分布式系统设计时的选择,后面的BASE也是根据AP来扩展。
2、BASE理论
BASE是Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结, 是基于CAP定理逐步演化而来的。BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
基本可用
基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性—-注意,这绝不等价于系统不可用。比如:
(1)响应时间上的损失。正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒
(2)系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面
软状态
软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时
最终一致性
最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
24、请简述2PC流程以及优缺点
1、2PC
1.1 流程
1.2 优缺点
优点: 尽量保证了数据的强一致,实现成本较低,在各大主流数据库都有自己实现,对于MySQL是从5.5开始支持(XA)。
缺点:
- 单点问题:事务管理器在整个流程中扮演的角色很关键,如果其宕机,比如在第一阶段已经完成,在第二阶段正准备提交的时候事务管理器宕机,资源管理器就会一直阻塞,导致数据库无法使用。
- 同步阻塞:在准备就绪之后,资源管理器中的资源一直处于阻塞,直到提交完成,释放资源。
- 数据不一致:两阶段提交协议虽然为分布式数据强一致性所设计,但仍然存在数据不一致性的可能,比如在第二阶段中,假设协调者发出了事务commit的通知,但是因为网络问题该通知仅被一部分参与者所收到并执行了commit操作,其余的参与者则因为没有收到通知一直处于阻塞状态,这时候就产生了数据的不一致性。
2、3PC
三段提交(3PC)是对两段提交(2PC)的一种升级优化,3PC
在 2PC
的第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前,各参与者节点的状态都一致。同时在协调者和参与者中都引入超时机制,当 参与者
各种原因未收到 协调者
的commit请求后,会对本地事务进行abort,不会一直阻塞等待,解决了 2PC
的单点故障问题,但 3PC
还是没能从根本上解决数据一致性的问题。
2.1 流程
CanCommit:协调者向所有参与者发送CanCommit命令,询问是否可以执行事务提交操作。如果全部响应YES则进入下一个阶段。
PreCommit:协调者
向所有 参与者
发送 PreCommit
命令,询问是否可以进行事务的预提交操作,参与者接收到PreCommit请求后,如参与者成功的执行了事务操作,则返回 Yes
响应,进入最终commit阶段。一旦参与者中有向协调者发送了 No
响应,或因网络造成超时,协调者没有接到参与者的响应,协调者向所有参与者发送 abort
请求,参与者接受abort命令执行事务的中断。
DoCommit: 在前两个阶段中所有参与者的响应反馈均是 YES
后,协调者向参与者发送 DoCommit
命令正式提交事务,如协调者没有接收到参与者发送的ACK响应,会向所有参与者发送 abort
请求命令,执行事务的中断
2.2 优缺点
- 优点:
1、引入超时机制。解决了事务管理器突然宕机导致资源一直处于阻塞的问题
2、多了一次询问阶段。防止个别参与者不正常的情况下,其他参与者都执行了事务,锁定资源。
- 缺点:
1、 3PC
用超时机制,同步阻塞问题,但与此同时却多了一次网络通信,性能上反而变得更差,也不太推荐。
2、没有解决数据不一致的问题
25、Seata支持那些事务模式?
概念:Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
这四种模式2PC(两阶段提交)
- AT模式:提供无侵入自动补偿的事务模式 【这里是基于本地能支持事务的关系型数据库,然后java代码可以通过JDBC访问数据库, 这里的无侵入:我们只需要加上对应的注解就可以开启全局事务】
- XA模式:支持已实现XA接口的数据库的XA模式【这里一般是需要数据库实现对应的XA模式的接口,一般像 mysql oracle 都实现了XA】
- TCC模式:TCC则可以理解为在应用层面的
2PC
,是需要我们编写业务逻辑来实现。 - SAGA模式:为长事务提供有效的解决方案
26、简述Seata的AT模式两阶段过程
两阶段提交协议的演变:
- 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
- 二阶段:
- 提交异步化,非常快速地完成。
- 回滚通过一阶段的回滚日志进行反向补偿。
第一阶段
业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。核心在于对业务sql进行解析,转换成undolog,并同时入库,这是怎么做的呢?先抛出一个概念DataSourceProxy代理数据源,通过名字大家大概也能基本猜到是什么个操作,后面做具体分析
第二阶段
分布式事务操作成功,则TC通知RM异步删除undolog
分布式事务操作失败,TM向TC发送回滚请求,RM 收到协调器TC发来的回滚请求,通过 XID 和 Branch ID 找到相应的回滚日志记录,通过回滚记录生成反向的更新 SQL 并执行,以完成分支的回滚。
Seata的AT模式
一阶段:开启全局事务、注册分支事务、储存全局锁、业务数据和回滚日志(undoLog)进行提交
二阶段:事务协调者根据所有分支的情况,决定本次全局事务是Commit还是Rollback (二阶段是完全异步删除undolog日志,全局事务、分支事务、储存的全局锁)
27、Seata中xid怎样通过Feign进行全局传递
全局事务id通过Feign的header进行传递。
ClientHttpRequestInterceptor
28、Seata TCC 模式设计思路
TCC 基于分布式事务中的二阶段提交协议实现,它的全称为 Try-Confirm-Cancel,即资源预留(Try)、确认操作(Confirm)、取消操作(Cancel),他们的具体含义如下:
- Try:对业务资源的检查并预留;
- Confirm:对业务处理进行提交,即 commit 操作,只要 Try 成功,那么该步骤一定成功;
- Cancel:对业务处理进行取消,即回滚操作,该步骤回对 Try 预留的资源进行释放。
29、 TCC存在的问题
1、 空回滚以及解决方案
空回滚指的是在一个分布式事务中,在没有调用参与方的 Try 方法的情况下,TM 驱动二阶段回滚调用了参与方的 Cancel 方法。
如上图所示,全局事务开启后,参与者 A 分支注册完成之后会执行参与者一阶段 RPC 方法,如果此时参与者 A 所在的机器发生宕机,网络异常,都会造成 RPC 调用失败,即参与者 A 一阶段方法未成功执行,但是此时全局事务已经开启,Seata 必须要推进到终态,在全局事务回滚时会调用参与者 A 的 Cancel 方法,从而造成空回滚。
要想防止空回滚,那么必须在 Cancel 方法中识别这是一个空回滚,Seata 是如何做的呢?
Seata 的做法是新增一个 TCC 事务控制表,包含事务的 XID 和 BranchID 信息,在 Try 方法执行时插入一条记录,表示一阶段执行了,执行 Cancel 方法时读取这条记录,如果记录不存在,说明 Try 方法没有执行。
2、幂等问题以及解决方案
幂等问题指的是 TC 重复进行二阶段提交,因此 Confirm/Cancel 接口需要支持幂等处理,即不会产生资源重复提交或者重复释放。
如上图所示,参与者 A 执行完二阶段之后,由于网络抖动或者宕机问题,会造成 TC 收不到参与者 A 执行二阶段的返回结果,TC 会重复发起调用,直到二阶段执行结果成功。
Seata 是如何处理幂等问题的呢?
同样的也是在 TCC 事务控制表中增加一个记录状态的字段 status,该字段有 3 个值,分别为:
- tried:1
- committed:2
- rollbacked:3
二阶段 Confirm/Cancel 方法执行后,将状态改为 committed 或 rollbacked 状态。当重复调用二阶段 Confirm/Cancel 方法时,判断事务状态即可解决幂等问题。
3、悬挂问题以及解决方案
悬挂指的是二阶段 Cancel 方法比 一阶段 Try 方法优先执行,由于允许空回滚的原因,在执行完二阶段 Cancel 方法之后直接空回滚返回成功,此时全局事务已结束,但是由于 Try 方法随后执行,这就会造成一阶段 Try 方法预留的资源永远无法提交和释放了
如上图所示,在执行参与者 A 的一阶段 Try 方法时,出现网路拥堵,由于 Seata 全局事务有超时限制,执行 Try 方法超时后,TM 决议全局回滚,回滚完成后如果此时 RPC 请求才到达参与者 A,执行 Try 方法进行资源预留,从而造成悬挂。
Seata 是怎么处理悬挂的呢?
在 TCC 事务控制表记录状态的字段 status 中增加一个状态:
- suspended:4
当执行二阶段 Cancel 方法时,如果发现 TCC 事务控制表没有相关记录,说明二阶段 Cancel 方法优先一阶段 Try 方法执行,因此插入一条 status=4 状态的记录,当一阶段 Try 方法后面执行时,判断 status=4 ,则说明有二阶段 Cancel 已执行,并返回 false 以阻止一阶段 Try 方法执行成功。
30、Gateway核心概念
路由(route)
路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组谓 词工厂、一组Filter组成。如果谓词为真,则说明请求的URL和配置的路由匹配。
谓词(predicates)
即java.util.function.Predicate , Spring Cloud Gateway使用Predicate实现路由的匹配条件。
过滤器(Filter)
SpringCloud Gateway中 的filter分为Gateway FilIer和Global Filter。Filter可以对请求和响应进行处理。
【路由就是转发规则,谓词就是是否走这个路径的条件,过滤器可以为路由添加业务逻辑,修改请求以及响应】
31、Gateway工作原理
Spring Cloud Gateway 的工作原理跟 Zuul 的差不多,最大的区别就是 Gateway 的 Filter 只有 pre 和 post 两种。
客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关 Web 处理程序,此时处理程序运行特定的请求过滤器链。
过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre 过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行 post 过滤器逻辑。
32、在Gateway中怎样实现服务平滑迁移?
使用Weight路由的断言工厂进行服务权重的配置,并将配置放到Nacos配置中心进行动态迁移
Weight路由断言工厂
规则:
该断言工厂中包含两个参数,分别是用于表示组 group,与权重 weight。对于同一组中的多个 uri 地址,路由器会根据设置的权重,按比例将请求转发给相应的 uri。实现负载均衡。
配置:
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
group
组,权重根据组来计算 weight
权重值,是一个 Int
的值
33、Zuul架构以及怎样保证线程安全
zuul Servlet 就是一个过滤器 ,其实Zuul就是一个servlet和一堆过滤器的组成,他的内容很少, 请求进入过滤器,然后进入ZullFilter Runner中会选择一个filter进行调用,这里面有前置路由过滤器、路由中过滤器、后置路由过滤器 三个。
这里注意个问题:
Servlet就是线程非安全的,他们里面会穿数据,filter就有一个非常麻烦的事情,就是filter怎样区别每一次请求的不同呢?
zuul使用 RequestContext
来在过滤器之间传递数据,数据存于每个request的ThreadLocal,包含请求路由到哪里,错误,HttpServletRequest,HttpServletResponse 等这些数据都存储于RequestContext中。RequestContext 扩展了ConcurrentHashMap,所以我们可以根据需要将信息存于context中进行传递。
总结:我们Zuul是有许多的Filter组成的,这些filter分为前置路由过滤器,后置路由过滤器,路由中路由过滤器 ,接着虽servlet、Runner、Filter都是线程非安全的,但是我们的RequestContext线程安全的,
34、Zuul启动注解@EnableZuulProxy 和@EnableZuulServer区别
我们一般引入@EnableZuulProxy 他为我们引入的类继承@EnableZuulServer对应的类,并且对其功能进行了增加。