1、Spring Cloud Netflix和Spring Cloud Alibaba包括哪些组件
Spring Cloud Netflix主要由:Eureka
、Ribbon
、Feign
、Hystrix
、Zuul|Gateway
、Config
等组件组成。
Spring Cloud Alibaba主要由:Nacos
、Sentinel
、Seata
等组件组成。
2、Nacos是CP还是AP?
Nacos即能保证CP,也能保证AP,具体看如何配置,默认是AP模式。
3、Nacos作为注册中心应该选择是CP还是AP?
CP:如果注册中心是CP的,当我们向注册中心注册实例或移除实例时,都要等待注册中心集群中的数据达到一致后,才算注册或移除成功,这是比较耗时的,随着业务应用规模的增大,应用频繁的上下线,那么就会导致注册中心的压力比较大,会影响到服务发现的效率以及服务调用。
AP:如果注册中心是AP的,注册中心集群不管出现了什么情况都是可以提供服务的,即使节点之间数据出现了不一致,例如拉取到了一个已经下线了的服务节点,但是现在一般的微服务框架或组件都提供了服务容错和重试功能,也可以避免这个问题。对于注册中心而言不需要消耗太多的资源来实时的保证数据一致性,保证最终一致性就可以了,这样注册中心的压力会小一点。
4、Nacos如何实现就近访问?
在Nacos中一个服务可以有多个实例,并且可以给实例设置cluster-name,如果现在某个服务A想要调用服务B,那么Naocs会看调用服务A的实例是属于哪个集群的,就会调用同样集群下的服务B实例,这就是Nacos的就近访问。
5、Nacos底层负载均衡底层原理
通过Ribbon实现的,Ribbon中定义了负载均衡算法,然后基于这些算法从服务实例中获取一个实例提供服务。
6、Nacos1.x注册中心架构流程
- 服务启动的时候,通过api发起服务注册。
- 服务消费者在启动的时候会拉取自已要用的服务列表。
- 服务消费者会每10秒进行拉取一下数据。
- Nacos服务检测到有异常(服务上下线)就会发送UDP协议给客户端进行更新。
- 服务会每5秒定时发送心跳到Nacos。
- Nacos每5秒检查一下心跳信息来判断是否超时,如果超过15秒则将节点设置为非健康状态并进行广播,如果超过30秒则将节点进行移除,说明节点不可用。
- Nacos集群数据同步任务使用协议:Distro(AP) , Raft(CP)
7、Nacos2.X作为注册中心架构流程
8、Nacos中的Distro协议
- Nacos 每个节点自己负责部分的写请求。
- 每个节点会把自己负责的新增数据同步给其他节点。
- 每个节点定时发送自己负责数据的校验值到其他节点来保持数据一致性。
- 每个节点独立处理读请求,及时从本地发出响应。
- 新加入的 Distro 节点会进行全量数据拉取。
9、Eureka注册中心原理
- 服务启动进行注册。
- 集群内部进行数据同步。
- 客户端定时任务每30s拉取一下数据。
- 客户端心跳续约,每30s一次。
- 每分钟检查实例是否过期,如果过期就将其移除,如果出现大量掉线就进入自我保护。
- 调用 API 优雅下线。
10、Eureka自我保护机制原理
Eureka服务端会每15分钟检查所有Eureka 实例正常心跳占比,如果低于85%就会触发自我保护机制。触发了保护机制,Eureka将暂时把这些失效的服务保护起来不让其过期,但这些服务也并不是永远不会过期。Eureka在启动完成后,每隔60秒会检查一次服务健康状态,如果这些被保护起来失效的服务过一段时间后(默认90秒)还是没有恢复,就会把这些服务剔除。如果在此期间服务恢复了并且实例心跳占比高于85%时,就会自动关闭自我保护机制。
11、Eureka和Nacos对比
- Nacos2.0中注册中心会定时向消费者主动推送信息,Eureka不会主动推送。
- Nacos支持CP和AP模式,Eureka支持AP模式。
- Nacos具备服务优雅上下线和流量管理,而Eureka的后台页面仅供展示,需要使用api操作上下线且不具备流量管理功能。
- Nacos社区活跃,Eureka开源工作已停止。
- Nacos整合了注册中心、配置中心功能,Eureka只是注册中心。
12、Nacos配置中心长轮询机制
Nacos 1.4.x
客户端会轮询向服务端发出一个长连接请求,这个长连接最多30s就会超时,服务端收到客户端的请求会先判断当前是否有配置更新,有则立即返回如果没有服务端会将这个请求加入队列“hold”29.5s,最后0.5s再检测配置文件无论有没有更新都进行正常返回,但等待的29.5s期间有配置更新可以提前结束并返回。
Nacos2.x
- 服务端配置发生变更后,通过长链接通知客户端服务发生变化,客户端再去拉取。
- 定时任务每5秒拉取一次。
13、引用Nacos配置的定时任务失效(Nacos工作中遇到问题)
- 首先我们要知道@Schedule是在加载Bean时利用后置处理器ScheduledAnnotationBeanPostProcessor,获取@Schedule标注的方法然后去执行,在Bean的生命周期中。
- @RefreshScope中有个@Scope里面值是Refresh,他创建对象是放到对应的缓存中,我们通过GenericScope#get方法从缓存中获取对应Bean对象,在更新配置刷新容器时候会将这些实例对象给清除调用,如果@RefreshScope标注的对象中有@Schedule定时任务,自然不能继续访问了,我们需要再调用一下实例中的某个接口才会创建对应的实例(BeanFactory#getBean 有对应的对象则获取,没有则进行创建),然后对应的定时任务才会正常的运行。
解决方式:更新配置刷新容器后会发送事件RefreshScopeRefreshedEvent,我们只需监听一下这个事件,之后他就会创建对应的实例,然后定时任务就能正常执行 。
14、Nacos加载那些配置,这些配置的优先级?
- sharedConfigs 公共配置,比如redis、mysql配置。
- extensionConfigs 扩展配置文件。
- ${application.name} nacos-config
- ${application.name}. ${file-extension} nacos-config.yaml
- ${application.name}- ${profile}. ${file- extension} nacos-config-prod.yaml
15、Nacos配置中心宕机了,会影响服务吗?
不会。客户端获取了配置中心的配置信息后,会将配置信息在本地保存一份。当配置中心宕机了会先读取本地文件。
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 |
- 关注社区活跃度。
- 结合自己的技术栈。
- 产品功能是否满足。
17、为什么Feign第一次调用耗时很长?
ribbon默认是懒加载的,只有第一次调用的时候才会生成ribbon对应的组件,这就会导致首次调用的会很慢的问题。
ribbon:
eager-load:
enabled: true
clients: service-1
18、Feign怎样实现认证的传递?
实现接口RequestInterceptor,通过header实现认证传递。
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);
}
}
19、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 服务的方法,能够大大提高客户端的编写效率。
Okhttp配置
feign:
okhttp:
enabled: true
20、请简述2PC流程以及优缺点
优点: 尽量保证了数据的强一致,实现成本较低,在各大主流数据库都有自己实现,对于MySQL是从5.5开始支持(XA)。
缺点:
- 单点问题:事务管理器在整个流程中扮演的角色很关键,如果其宕机,比如在第一阶段已经完成,在第二阶段正准备提交的时候事务管理器宕机,资源管理器就会一直阻塞,导致数据库无法使用。
- 同步阻塞:在准备就绪之后,资源管理器中的资源一直处于阻塞,直到提交完成,释放资源。
- 数据不一致:两阶段提交协议虽然为分布式数据强一致性所设计,但仍然存在数据不一致性的可能,比如在第二阶段中,假设协调者发出了事务commit的通知,但是因为网络问题该通知仅被一部分参与者所收到并执行了commit操作,其余的参与者则因为没有收到通知一直处于阻塞状态,这时候就产生了数据的不一致性。
21、请简述3PC流程以及优缺点
三段提交(3PC)是对两段提交(2PC)的一种升级优化,3PC
在 2PC
的第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前,各参与者节点的状态都一致。同时在协调者和参与者中都引入超时机制,当 参与者
各种原因未收到 协调者
的commit请求后,会对本地事务进行abort,不会一直阻塞等待,解决了 2PC
的单点故障问题,但 3PC
还是没能从根本上解决数据一致性的问题。
优点:引入超时机制。解决了事务管理器突然宕机导致资源一直处于阻塞的问题。
缺点:3PC
用超时机制解决同步阻塞问题,但与此同时却多了一次网络通信,性能上反而变得更差,数据不一致的问题依然存在。
22、Seata支持那些事务模式?
提供了四种模式2PC
- AT模式:提供无侵入自动补偿的事务模式 【这里是基于本地能支持事务的关系型数据库,然后java代码可以通过JDBC访问数据库, 这里的无侵入:我们只需要加上对应的注解就可以开启全局事务】
- XA模式:支持已实现XA接口的数据库的XA模式【这里一般是需要数据库实现对应的XA模式的接口,一般像 mysql oracle 都实现了XA】
- TCC模式:TCC则可以理解为在应用层面的
2PC
,是需要我们编写业务逻辑来实现。 - SAGA模式:为长事务提供有效的解决方案。
23、Seata中xid怎样通过Feign进行全局传递
全局事务id通过Feign的header进行传递。
24、Gateway核心概念
路由(route)
路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组谓词工厂、一组Filter组成。如果谓词为真,则说明请求的URL和配置的路由匹配。
- 谓词(predicates)
即java.util.function.Predicate , Spring Cloud Gateway使用Predicate实现路由的匹配条件。 - 过滤器(Filter)
SpringCloud Gateway中 的filter分为Gateway FilIer和Global Filter。Filter可以对请求和响应进行处理。
路由就是转发规则,谓词就是是否走这个路径的条件,过滤器可以为路由添加业务逻辑,修改请求以及响应
25、在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
26、Zuul架构以及怎样保证线程安全
Servlet就是线程非安全的,他们里面会穿数据,filter就有一个非常麻烦的事情,就是filter怎样区别每一次请求呢?
zuul使用 RequestContext
来在过滤器之间传递数据,数据存于每个request的ThreadLocal,包含请求路由到哪里、HttpServletRequest、HttpServletResponse 等这些数据都存储于RequestContext中。
总结:我们Zuul是有许多的Filter组成的,这些filter分为前置路由过滤器,后置路由过滤器,路由中路由过滤器 ,接着虽servlet、Runner、Filter都是线程非安全的,但是我们的RequestContext线程安全的。
27、Zuul启动注解@EnableZuulProxy 和@EnableZuulServer区别
我们一般引入@EnableZuulProxy ,该类继承@EnableZuulServer对应的类,对其功能进行了增加。