Spring Cloud 高频面试题

一、使用 Spring Cloud 有什么优势

使用 Spring Boot 开发分布式微服务时,我们面临以下问题:

  • 与分布式系统相关的复杂性:这种开销包括网络问题,延迟开销,带宽问题,安全问题。

  • 服务发现:服务发现工具管理群集中的流程和服务如何查找和互相交谈。它涉及一个服务目录,在该目录中注册服务,然后能够查找并连接到该目录中的服务。

  • 冗余:分布式系统中的冗余问题。

  • 负载平衡:负载平衡改善跨多个计算资源的工作负荷,诸如计算机,计算机集群,网络链路,中央处理单元,或磁盘驱动器的分布。

  • 性能:问题 由于各种运营开销导致的性能问题。

  • 部署复杂性:Devops 技能的要求。

二、什么是 Hystrix?它如何实现容错

Hystrix 是 Netflix 开源的一个用于实现容错的库,它主要用于处理分布式系统中的延迟和故障。Hystrix 可以帮助开发人员实现服务的容错和降级,从而提高系统的可用性和稳定性。

Hystrix 的容错机制主要包括以下几个方面:

1、服务降级

当服务不可用或响应时间超过阈值时,Hystrix 会自动将请求转发到服务的备用实现或缓存中,从而避免服务的故障影响到整个系统的性能和可用性。

2、服务熔断

Hystrix 可以根据一定的规则来监控服务的健康状态,当服务出现故障或响应时间超过阈值时,Hystrix 会自动断开服务的调用,避免服务的故障对整个系统的性能和可用性造成影响。

3、服务限流

Hystrix 可以根据一定的规则来限制服务的请求流量,当服务的请求流量超过一定阈值时,Hystrix 会自动拒绝部分请求或延迟部分请求的执行,从而保护服务的可用性和稳定性。

4、监控和报警

Hystrix 可以实时监控服务的健康状态和性能指标,包括响应时间、失败率、请求量等,同时可以通过报警机制来及时发现和处理服务的异常情况,从而保障系统的可用性和稳定性。

总之,Hystrix 是一个用于实现容错的库,它通过服务降级、服务熔断、服务限流和监控报警等机制来保障系统的可用性和稳定性。在分布式系统的开发中,Hystrix 是一个非常重要的工具,可以帮助开发人员实现高可用、高性能的分布式系统。

三、Feign 是什么

Feign 集成了 Ribbon、RestTemplate 实现了负载均衡的执行 HTTP 调用,只不过对原有的方式(Ribbon+RestTemplate)进行了封装,开发者不必手动使用 RestTemplate 调服务,而是定义一个接口,在这个接口中标注一个注解即可完成服务调用,这样更加符合面向接口编程的宗旨,简化了开发。

四、OpenFeign 是什么

OpenFeign 是 Spring Cloud 在 Feign 的基础上支持了 SpringMVC 的注解,如 @RequestMapping 等等。OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

五、Feign 和 OpenFeign 有什么区别

Feign 是 Spring Cloud 组件中一个轻量级 RESTful 的 HTTP 服务客户端,Feign 内置了 Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign 的使用方式是:使用 Feign 的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。

OpenFeign 是 Spring Cloud 在 Feign 的基础上支持了 SpringMVC 的注解,如 @RequestMapping 等。OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

六、OpenFeign 如何传参

1、传递 JSON 数据

这个也是接口开发中常用的传参规则,在 Spring Boot 中通过 @RequestBody 标识入参。

/** * 参数默认是@RequestBody标注的,这里的@RequestBody可以不填 * 方法名称任意 */@PostMapping("/openfeign/provider/order2")Order createOrder2(@RequestBody Order order);

注意:OpenFeign 默认的传参方式就是 JSON 传参(@RequestBody),因此定义接口的时候可以不用 @RequestBody 注解标注,不过为了规范,一般都填上。

2、POJO 表单传参

/** * 参数默认是@RequestBody标注的,如果通过POJO表单传参的,使用@SpringQueryMap标注 */@PostMapping("/openfeign/provider/order1")Order createOrder1(@SpringQueryMap Order order);

图片

OpenFeign 提供了一个注解 @SpringQueryMap 完美解决 POJO 表单传参。

3、URL 中携带参数
@GetMapping("/openfeign/provider/test/{id}")String get(@PathVariable("id")Integer id);

使用注解 @PathVariable 接收 URL 中的占位符,这种方式很好理解。

4、另类传参
/** * 必须要@RequestParam注解标注,且value属性必须填上参数名 * 方法参数名可以任意,但是@RequestParam注解中的value属性必须和provider中的参数名相同 */@PostMapping("/openfeign/provider/test2")String test(@RequestParam("id") String arg1,@RequestParam("name") String arg2);

七、如何处理超时

@PostMapping("/test2")public String test2(String id,String name) throws InterruptedException {        // 休眠3秒    Thread.sleep(3000);        return MessageFormat.format("accept on msg id={0},name={1}",id,name);}

OpenFeign 其实是有默认的超时时间的,默认分别是连接超时时间10秒、读超时时间 60 秒,源码在 feign.Request.Options#Options() 这个方法中,如下图:

图片

那么问题来了:为什么我只设置了睡眠 3 秒就报超时呢?

其实 OpenFeign 集成了 Ribbon,Ribbon 的默认超时连接时间、读超时时间都是是 1 秒,源码在 org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer#execute() 方法中,如下图:

图片

图片

源码大致意思:如果 OpenFeign 没有设置对应得超时时间,那么将会采用Ribbon的默认超时时间。

理解了超时设置的原理,由之产生两种方案也是很明了,如下:

  • 设置 openFeign 的超时时间

  • 设置 Ribbon 的超时时间

1、设置 Ribbon 的超时时间(不推荐)

设置很简单,在配置文件中添加如下设置:

ribbon:  # 值的是建立链接所用的时间,适用于网络状况正常的情况下, 两端链接所用的时间  ReadTimeout: 5000  # 指的是建立链接后从服务器读取可用资源所用的时间  ConectTimeout: 5000
2、设置 OpenFeign 的超时时间(推荐)

OpenFeign 设置超时时间非常简单,只需要在配置文件中配置,如下:

feign:  client:    config:      ## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间      default:        connectTimeout: 5000        readTimeout: 5000

default 设置的是全局超时时间,对所有的 OpenFeign 接口服务都生效。

八、如何开启日志增强?

OpenFeign 虽然提供了日志增强功能,但是默认是不显示任何日志的,不过开发者在调试阶段可以自己配置日志的级别。

OpenFeign 的日志级别如下:

  • NONE:默认的,不显示任何日志;

  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;

  • HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息;

  • FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。

1、配置类中配置日志级别

图片

注意:这里的 logger 是 feign 包里的。

2、yaml 文件中设置接口日志级别

只需要在配置文件中调整指定包或者 OpenFeign 的接口日志级别,如下:

logging:  level:    cn.xx.service: debug

这里的 cn.xx.service 是 OpenFeign 接口所在的包名,当然你也可以配置一个特定的 OpenFeign 接口。

上述步骤将日志设置成了 FULL,此时发出请求,日志效果如下图:

图片

日志中细的打印出了请求头、请求体的内容。

九、如何替换默认的 HttpClient

Feign 在默认情况下使用的是 JDK 原生的 URLConnection 发送 HTTP 请求,没有连接池,但是对每个地址会保持一个长连接,即利用 HTTP 的 persistence connection。

在生产环境中,通常不使用默认的 HttpClient,通常有如下两种选择:

  • 使用 Apache HttpClient

  • 使用 OkHttp

至于哪个更好,其实各有千秋,我比较倾向于 Apache HttpClient,毕竟老牌子了,稳定性不在话下。

那么如何替换掉呢?其实很简单,下面演示使用 Apache HttpClient 替换。

1、添加 Apache HttpClient 依赖

在 OpenFeign 接口服务的 pom 文件添加如下依赖:

<!-- 使用Apache HttpClient替换Feign原生httpclient--><dependency>  <groupId>org.apache.httpcomponents</groupId>  <artifactId>httpclient</artifactId></dependency>
<dependency>  <groupId>io.github.openfeign</groupId>  <artifactId>feign-httpclient</artifactId></dependency>

为什么要添加上面的依赖呢?

从源码中不难看出,请看org.springframework.cloud.openfeign.FeignAutoConfiguration.HttpClientFeignConfiguration 这个类,代码如下:

图片

图片

上述红色框中的生成条件,其中的 @ConditionalOnClass(ApacheHttpClient.class),必须要有 Apache HttpClient 这个类才会生效,并且 feign.httpclient.enabled 这个配置要设置为 true。

2、配置文件中开启

在配置文件中要配置开启,代码如下:

feign:  client:    httpclient:      # 开启 Http Client      enabled: true
3、如何验证已经替换成功?

其实很简单,在 feign.SynchronousMethodHandler#executeAndDecode() 这个方法中可以清楚的看出调用哪个 client,如下图:

图片

上图中可以看到最终调用的是 Apache HttpClient。

4、总结

上述步骤仅仅演示一种替换方案,剩下的一种不再演示了,原理相同。

十、如何优化通讯

在讲如何优化之前先来看一下 GZIP 压缩算法,概念如下:

gzip 是一种数据格式,采用用 deflate 算法压缩数据;gzip 是一种流行的数据压缩算法,应用十分广泛,尤其是在 Linux 平台。

当 GZIP 压缩到一个纯文本数据时,效果是非常明显的,大约可以减少 70% 以上的数据大小。

网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是 GZIP 与搜索引擎的抓取工具有着更好的关系。例如  Google 就可以通过直接读取 GZIP 文件来比普通手工抓取更快地检索网页。

GZIP 压缩传输的原理如下图:

图片

按照上图拆解出的步骤如下:

  • 客户端向服务器请求头中带有:Accept-Encoding:gzip,deflate 字段,向服务器表示,客户端支持的压缩格式(gzip 或者 deflate),如果不发送该消息头,服务器是不会压缩的。

  • 服务端在收到请求之后,如果发现请求头中含有 Accept-Encoding 字段,并且支持该类型的压缩,就对响应报文压缩之后返回给客户端,并且携带 Content-Encoding:gzip 消息头,表示响应报文是根据该格式压缩过的。

  • 客户端接收到响应之后,先判断是否有 Content-Encoding 消息头,如果有,按该格式解压报文。否则按正常报文处理。

OpenFeign 支持请求/响应开启 GZIP 压缩,整体的流程如下图:

图片

图片

上图中涉及到GZIP传输的只有两块,分别是Application client -> Application Service、 Application Service->Application client。

注意:openFeign支持的GZIP仅仅是在openFeign接口的请求和响应,即是openFeign消费者调用服务提供者的接口。

OpenFeign 开启 GZIP 步骤也是很简单,只需要在配置文件中开启如下配置:

feign:  ## 开启压缩  compression:    request:      enabled: true      ## 开启压缩的阈值,单位字节,默认2048,即是2k,这里为了演示效果设置成10字节      min-request-size: 10      mime-types: text/xml,application/xml,application/json    response:      enabled: true

上述配置完成之后,发出请求,可以清楚看到请求头中已经携带了 GZIP 压缩,如下图:

图片

十一、如何熔断降级

常见的熔断降级框架有 Hystrix、Sentinel,OpenFeign 默认支持的就是 Hystrix,这个在官方文档上就有体现,毕竟是一奶同胞嘛,哈哈。

但是阿里的 Sentinel 无论是功能特性、简单易上手等各方面都完全秒杀 Hystrix,因此此章节就使用 OpenFeign+Sentinel 进行整合实现服务降级。

1、添加 Sentinel 依赖

在 openFeign-consumer9006 消费者的 pom 文件添加 Sentinel 依赖(由于使用了聚合模块,不指定版本号),如下:

<dependency>    <groupId>com.alibaba.cloud</groupId>    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>

2、配置文件中开启 Sentinel 熔断降级

要想 OpenFeign 使用 Sentinel 的降级功能,还需要在配置文件中开启,添加如下配置:

feign:  sentinel:    enabled: true

3、添加降级回调类

这个类一定要和 OpenFeign 接口实现同一个类,如下图:

图片

 

OpenFeignFallbackService 这个是降级回调的类,一旦 OpenFeignService 中对应得接口出现了异常则会调用这个类中对应得方法进行降级处理。

4、添加 fallback 属性

在 @FeignClient 中添加 fallback 属性,属性值是降级回调的类,如下:

@FeignClient(value = "openFeign-provider",fallback = OpenFeignFallbackService.class)public interface OpenFeignService {}
5、演示

经过如上 4 个步骤,OpenFeign 的熔断降级已经设置完成了,此时演示下效果。

通过 postman 调用 http://localhost:9006/openfeign/order3 这个接口,正常逻辑返回如下图:

图片

现在手动造个异常,在服务提供的接口中抛出异常,如下图:

图片

 

此时重新调用 http://localhost:9006/openfeign/order3,返回如下图:

图片

 

十二、Sentinel 如何做分布式限流

Sentinel 是一种分布式系统的流量控制组件,可以实现流量控制、服务降级、熔断降级等功能。在 Sentinel 中,可以通过配置流控规则来控制每个服务的请求流量,防止服务被过度请求而导致服务宕机或者响应变慢。

Sentinel 中的分布式限流是通过令牌桶算法和滑动窗口算法实现的。具体来说,Sentinel 会在每个服务的入口处配置流控规则,根据规则来限制每个服务的请求流量。当某个服务的请求量超过流控规则中设置的阈值时,Sentinel 会根据算法来拒绝或者延迟请求,从而达到限流的效果。

在令牌桶算法中,Sentinel 会为每个服务配置一个令牌桶,令牌桶中存储了一定数量的令牌,每次请求时需要从令牌桶中获取令牌,如果令牌不足则请求被拒绝或者延迟。在滑动窗口算法中,Sentinel 会将每个服务的请求量按照时间窗口进行统计,如果请求量超过了设置的阈值,请求会被拒绝或者延迟。

总的来说,Sentinel 的分布式限流是通过令牌桶算法和滑动窗口算法实现的,可以根据业务需求进行配置和调整,从而实现对服务的流量控制和限制。

十三、Sentinel 限流策略

Sentinel 提供了多种限流策略,可以根据实际情况选择合适的限流策略。以下是 Sentinel 支持的一些限流策略:

  • 直接拒绝:当请求超出阈值时,直接拒绝请求,返回错误信息。

  • 预热/冷启动:在系统启动时,逐渐增加流量,以避免系统在刚启动时被大量请求压垮。

  • 排队等待:当请求超出阈值时,将请求放入队列中等待处理,避免请求被拒绝后直接影响用户体验。

  • 慢启动:在系统启动时,逐渐增加流量,避免系统在刚启动时被大量请求压垮。

  • 平滑降级:当系统负载过高时,逐渐降低系统的处理能力,避免系统崩溃。

  • 热点参数限流:根据请求参数进行限流,避免热点请求对系统造成过大的压力。

  • 熔断降级:当系统负载过高或者出现异常时,将请求拦截或者延迟处理,避免系统崩溃或者响应时间过长。

以上是 Sentinel 支持的一些限流策略,根据业务需求和实际情况选择合适的策略进行配置和应用。在配置限流规则时,需要综合考虑多个方面,例如系统负载、业务需求、用户体验等因素,从而达到合理的限流效果。

十四、Sentinel 线程池隔离和信号量隔离

Sentinel 提供了两种隔离策略,分别是线程池隔离和信号量隔离。

线程池隔离是将每个被保护的资源分配到一个线程池中进行处理,每个资源都有自己的线程池,不同资源之间相互独立。在线程池隔离的模式下,当一个资源被限流或者熔断时,只会影响当前资源的请求,不会影响到其他资源的请求。线程池隔离的优点是隔离性好,可以有效地限制每个资源的请求量,避免资源互相影响,但是线程池的创建和销毁会占用系统资源。

信号量隔离是将每个被保护的资源分配到一个信号量中进行处理,每个资源都有自己的信号量,不同资源之间相互独立。在信号量隔离的模式下,当一个资源被限流或者熔断时,会影响到同一信号量下的所有资源的请求。信号量隔离的优点是资源消耗少,但是隔离性相对较差,容易造成资源互相影响。

在选择线程池隔离和信号量隔离时,需要根据实际情况进行选择。如果需要更好的隔离性和更精细的流量控制,可以选择线程池隔离;如果需要更高的性能和更少的资源消耗,可以选择信号量隔离。另外,在配置隔离策略时,需要根据业务需求和实际情况选择合适的配置参数,例如线程池大小、并发度等,以达到更好的效果。

十五、Nacos 怎么实现配置动态更新

Nacos 通过监听配置数据变更的方式实现配置动态更新。具体来说,当 Nacos 中的配置数据发生变化时,Nacos 会通过监听器机制将变化的信息通知给客户端,客户端在接收到通知后会重新获取最新的配置数据,并更新本地的配置信息。

Nacos 的配置监听机制包括两个部分:客户端监听和服务端监听。客户端监听是指客户端通过订阅 Nacos 的配置服务,当配置数据发生变化时,Nacos 会主动通知客户端,客户端在接收到通知后会重新获取最新的配置数据。服务端监听是指 Nacos 在配置数据发生变化时,会通知所有订阅该配置的客户端,以便客户端能够及时更新配置信息。

Nacos 中的配置监听机制是基于长连接实现的,客户端和服务端之间通过长连接来实现实时通信。当客户端与 Nacos 建立长连接后,Nacos 会将客户端所订阅的配置信息发送给客户端,并保持连接状态。当配置数据发生变化时,Nacos 会主动向客户端发送通知,客户端在接收到通知后会重新获取最新的配置数据,并更新本地的配置信息。

总之,Nacos 通过监听配置数据变化的方式实现配置动态更新,利用长连接实现实时通信,保证配置信息的及时更新和同步。这种机制能够满足配置实时更新的需求,提高了系统的可靠性和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值