spring cloud面试题(2024)

前言

对于spring cloud的学习和复习,这里主要分为两部分:一是spring cloud的基本概念介绍,二是spring cloud的常用组件说明

1. spring cloud概述

1.1 分布式与微服务概念

  1. 微服务:微服务是指,将一个完整的系统按照业务划分(也可以按照其他维度划分)为一个个更小系统的架构风格;举个例子说明:一个商城系统,可以按微服务的架构风格,划分出来商品服务、订单服务、库存服务等等,这每个服务是各自独立的,可以独立开发、独立部署。

  2. 分布式:分布式是指,部署这些个微服务的方式(分布式也可以是部署其他类型系统的方式),在分布式系统下,微服务架构中的一个个服务被作为一个个组件部署到不同的物理或者虚拟机器上,这些组件之间可以通过网络进行通信和协作。

    总的来说,微服务架构通常部署在分布式系统上,每个微服务部署到不同的机器上,并且可以通过网络进行通信和协作,就形成了分布式系统,而spring cloud就是一个专注于全局微服务协调和治理、简化分布式系统开发的开源框架。

1.2 spring cloud介绍

spring cloud基于spring boot集合了各种成熟的框架,提供了服务发现、配置管理、负载均衡等功能,是一个专注于全局微服务协调和治理、简化分布式系统开发的开源框架。

1.3 spring cloud的优缺点

  1. 优点:
    • 简化了分布式系统的开发:让开发人员可以专注于业务逻辑而不是解决分布式系统的各种问题
    • 快速开发和部署微服务:spring boot为其提供了默认配置和快速启动器,spring cloud本身又有自己一套微服务架构的解决方案,让开发人员可以快速开发和部署一套功能完整的微服务架构
  2. 缺点:
    • 数据管理麻烦
    • 系统集成测试麻烦

1.4 spring cloud的组件

  1. Eureka:服务注册与发现,每个微服务在启动时,会向Eureka服务器注册自己的信息,包括服务名、IP地址、端口号,其他服务可以通过Eureka来发现和调用这个服务
  2. Zuul:服务网关,提供动态路由,监控等功能
  3. Ribbon:负载均衡,对客户端进行负载均衡
  4. Feign:声明式的http客户端,简化了服务之间的调用代码
  5. Hystrix:断路器,当服务不可用时,进行熔断,防止故障扩散
  6. config:分布式统一配置管理

2. Eureka

2.1 背景介绍

在传统单体应用中,服务的调用通常以硬编码的方式实现,但是在微服务架构中,服务数量可能众多,而且服务实例可能会动态增加减少改变,这时候硬编码的方式就变得难以维护,因此需要一种机制来自动发现和管理这些服务,而Eureka就是一个实现了这样功能的组件

2.2 工作原理

  1. 一个微服务启动时,会向Eureka服务器注册自己的信息,这其中包括:服务名、IP地址、端口号
  2. Eureka服务器会维护一个服务注册表,里面记录了所有注册的服务实例信息
  3. 其他微服务可以通过Eureka服务器来查询需要调用的服务实例信息,从而实现服务之间的动态调用

2.3 高可用的实现

Eureka的高可用是通过集群的方式来实现的,通过部署多个服务器实例,并让它们相互注册,构建成为一个多节点的服务器集群。通过相互注册的方式,让这些实例相互知道对方的存在,从而当一个实例宕机时,其他实例仍能提供服务,下面是spring cloud中,Eureka相互注册的配置:

eureka:
  client:
    serviceUrl:
      defaultZone: http://eureka1:8761/eureka/,http://eureka2:8762/eureka/

这个配置中配置了eureka这个实例启动时,需要注册的其他实例(eureka1、eureka2)地址,当它启动时,它会向eureka1、eureka2注册自己的信息,同时也会接收来自eureka1、eureka2的注册信息来实现服务器实例之间的相互注册

2.4 自我保护机制

Eureka服务器会定期检查注册表中实例的健康状况,如果一个实例没有在一定时间内向服务器发送心跳,那么这个实例就会被从注册表中删除,但是会有网络故障或者其他什么原因,导致是Eureka服务器无法正常收到心跳,而不是实例没有发送心跳,这就会造成误删除。
为了解决这个问题,就引入了自我保护机制,当Eureka服务器在一定时间内没有收到一个实例的心跳,它不会立即从注册表中删除这个实例,而是把它标记为“保护”状态,让它继续对外提供服务,只有超过一定时间,仍没有收到这个实例的心跳,才会把它删除

2.5 Eureka与zooKeeper的区别

  1. Eureka是对服务发现与注册进行了专门的优化,而zooKeeper是一个分布式协调服务,服务的注册与发现只是它的功能之一
  2. Eureka集群中的节点是平级的,而zooKeeper集群中的节点有主从之分
  3. Eureka遵循CAP原则中的AP、而zooKeeper遵循CP

CAP原则:分布式系统中的三个特性:
C:一致性
A:可用性
P:分区容错性
根据CAP原则,一个分布式系统最多只能满足其中的两个特性;由于网络延迟或者其他故障等不可控的因素,分区容错性是必须保证的,剩余的两个特性中,Eureka主要用于服务之间的调用,更注重可用性,它通过集群模式实现高可用;
而zooKeeper是一个分布式协调服务,用于协调分布式系统中的各种任务和状态信息,需要保证数据的一致性;zooKeeper的一致性是强一致性,通过ZAB协议实现,简单说明ZAB协议的过程如下:
①. leader选举:zooKeeper集群中,会有一个leader节点负责处理客户端的读写请求
②. 提案:当客户端发送读写请求时,leader节点会生成一个提案,然后广播给其他节点
③. 多数派确认:从节点收到提案后,会向leader发送确认信息,只有收到了多数节点的确认信息后,提案才会被提交
④. 提交:提案被提交后,leader会把写操作广播给其他节点,从而保证数据一致性

3. Zuul

3.1 背景介绍

在客户端与后端服务之间,有一个中间层系统,用于简化它们的交互,这个中间层系统就是网关,网关可以提供路由转发、权限控制、监控等功能,Zuul就属于一个网关,它可以作为整个微服务架构的入口,为客户端提供统一的访问接口

网关可以分为:

  1. API网关:侧重于管理和暴露API,提供对外服务的统一访问方式
  2. 微服务网关,侧重于管理和路由微服务之间的通信

Zuul根据具体的配置和要求,既可以是API网关也可以是微服务网关

3.2 工作流程

  1. 客户端发送请求到Zuul
  2. Zuul根据预定义的路由规则,将请求转发到对应的后端服务
  3. 后端服务处理完成,将响应返回给Zuul
  4. Zuul将响应返回给客户端

3.3 主要功能

  1. 路由转发:Zuul可以根据路由规则,将请求转发给对应的后端服务
  2. 过滤器:允许在请求的各个阶段执行自定义逻辑,例如日志记录、性能监控
  3. 负载均衡:Zuul可以集成Ribbon,实现负载均衡,将请求转发到多个实例中

3.4 使用场景

  1. API网关:所有API请求都经过Zuul,实现统一的路由、认证、监控和日志记录
    例如:当客户端发起请求时,Zuul的过滤器拦截这个请求,记录请求的相关信息(请求的路径、参数等等),同时记录请求的处理结果(响应码、处理时间等等),实现日志记录
  2. 负载均衡:集成Ribbon,将请求分发到多个后端服务实例中
  3. 安全认证:Zuul可以实现认证、授权等安全功能
    例如:当前有一个微服务架构的电子商务系统,当一个客户端请求订单服务的时候,Zuul的过滤器可以拦截这个请求,分析请求中的身份信息(token、session),进行用户身份认证、认证成功后,通过检查用户是否有权限访问这个资源,实现授权检查,检查成功再将请求转发到对应的后端服务,防止恶意访问和非法操作

3.5 过滤器

Zuul过滤器是一种基于自身过滤体系扩展而来的机制,它允许用户在请求进入网关、路由过程中、响应返回的不同阶段,插入自定义的逻辑,实现认证,授权、日志记录等操作,具体实现过程如下:

  1. 实现Zuul提供的抽象类,编写自定义逻辑
  2. 重写filterType方法,确定过滤器类型,Zuul提供了四种标准的过滤器类型,分别是:
    ①. pre:请求被路由前
    ②. route:路由中
    ③. post:路由完成
    ④. error:发生错误时
  3. 重写run方法,进行身份验证等等操作

下面简单展示相关代码:

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Component;

@Component
public class AuthFilter extends ZuulFilter {  // 1. 实现抽象类

    @Override
    public String filterType() {  // 2. 重写filterType方法
        return "pre"; 
    }

	// ...省略其他代码,诸如定义过滤器执行顺序、是否执行

    @Override
    public Object run() {   // 3. 重写方法,实现自定义过滤逻辑
        RequestContext ctx = RequestContext.getCurrentContext();
        String token = ctx.getRequest().getHeader("Authorization");

        // 进行用户认证逻辑,这里简单地检查token是否为空
        if (token == null) {
            // 如果认证失败,拦截请求,返回401 Unauthorized错误
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.setResponseBody("Unauthorized");
        } 
        return null;
    }

}

3.6 Zuul集群

实现过程:

  1. 部署多个实例:在不同机器上部署多个实例
  2. 服务注册与发现:将每个实例都注册到注册中心(如Eureka),使得Zuul实例可以动态注册和发现其他实例,实现集群的自动扩展和缩减
  3. 负载均衡:使用负载均衡器(nginx、Ribbon等)进行请求的分发,将请求分发到不同的服务器

4. Ribbon

4.1 背景介绍

  1. 负载均衡
    顾名思义,负载均衡就是让集群(或者网络设备等等)中的每个资源(服务器实例、节点等)的负载达到均衡,不让某个资源负载过大导致性能下降,也不让某个资源负载过小导致性能浪费,实现吞吐量最大化、响应时间最小化
  2. Ribbon
    Ribbon与上面的Eureka、Zuul一样,都是Netflix开发是组件,它被用来把客户端的请求均衡地转发给多个服务实例
  3. 它与Nginx的区别和优势
    • 区别
      • Ribbon是一个客户端负载均衡库,通常嵌在应用程序客户端中,由客户端完成负载均衡策略的选择,再使用Ribbon进行请求转发
      • Nginx是一个独立的反向代理服务器,负载均衡策略的选择和请求转发都是由自己完成
    • 优势
      • 在spring cloud框架中,Ribbon相比与Nginx可以更好地与其他服务治理组件集成,实现更灵活的负载均衡

4.2 工作过程

  1. 客户端想Ribbon发起请求
  2. Ribbon根据配置的负载均衡策略选择一个服务实例
  3. Ribbon将请求转发给选定的服务器实例

4.3 与Eureka集成

Ribbon与Eureka集成后,它可以从Eureka注册中心获取当前可用的服务实例列表,然后根据自己的负载均衡策略选择服务实例,而不再需要在自己的配置文件中,以硬编码的方式配置服务实例

5. Hystrix

5.1 背景介绍

  1. 雪崩效应
    当一个服务调用另一个服务出现问题时,调用者就会等待被调用者的响应,当更多服务请求这些不能正常提供服务的资源时,就会造成更多的请求等待,这种连锁反应就是雪崩效用
  2. Hystrix
    Hystrix就是一个用于防止雪崩的工具

5.2 工作过程

  1. 封装命令:每一个可能出现故障的远程调用都需要经过Hystrix的命令模式进行注册和封装成为命令
  2. 执行命令:当远程调用发起时,Hystrix会通过命令模式执行封装好的命令;Hystrix会为每个命令维护一个线程池,和其他需要的资源,用于执行这些命令
  3. 监控命令:Hystrix会实时监控这些命令的执行情况,并根据监控数据对出现异常的调用执行对应的决策,防止出现雪崩,对系统造成进一步伤害

5.3 雪崩产生的原因

  1. 代码bug
  2. 访问量激增:Tomcat默认情况下,只有一个线程池维护客户端发送的请求,某一接口在某一时间被大量访问就会占据线程池中的现场,其他请求就会被等待
  3. 服务器硬件问题,导致服务不可用

5.4 防雪崩方式

  1. 服务降级:远程调用失败或者超时时,Hystrix可以提供降级策略,返回一个默认值或者进行其他补偿逻辑
  2. 服务熔断:当一个服务被超时等待,系统不断尝试重试也会造成资源浪费,可能导致后续影响,Hystrix可以通过断路器,对错误率超过阈值的服务进行停用,减少对系统的压力
  3. 服务隔离:通过限制资源的访问和调用,对服务进行隔离,比如说使用Hystrix的线程池隔离机制,为问题服务分配单独的线程池,防止影响其他服务
  4. 服务监控:Hystrix可以实时监控服务调用情况,记录失败率,响应时间,可以及时发现问题,防止进一步恶化雪崩

5.5 服务降级的实现

  1. 继承HystrixCommand类
  2. 重写run方法,实现调用逻辑
  3. 重写getFallback方法,实现降级逻辑,当run方法执行错误时,执行这个方法
    以下是简单代码展示:
public class RemoteCallCommand extends HystrixCommand<String> {

    @Override
    protected String run() throws Exception {
        // 在这里执行远程调用的逻辑
        // 返回远程调用的结果
        return "Remote call result";
    }

    @Override
    protected String getFallback() {
        // 降级逻辑,当远程调用失败或超时时执行
        return "Fallback result";
    }
}

6. Feign

在传统服务调用过程中,我们往往需要手动创建http请求、处理请求和响应、序列号、反序列化,这些代码是冗长且不好维护的,而Feign就可以解决这种场景的问题;我们只需要简单定义一个接口,在接口上通过注解( @RequestLine)的方式描述http请求的细节,Feign就会根据这个接口自动生成实际的http请求,可以大大简化服务调用的流程

7. config

7.1 背景介绍

spring cloud config组件可以用来集中管理微服务架构中的应用程序配置,将配置信息从应用中分离出来,集中管理

7.2 工作过程

  1. 配置文件仓库:我们把配置信息存储到一个配置仓库中,比如git,或者本地文件
  2. config server:搭建config server,从配置仓库中读取配置信息,并提供API接口供程序读取配置
  3. config 客户端:从config server处获取配置信息;在程序启动时,会向Config server请求自己的配置
  4. 动态刷新:客户端可以监听server中的配置变更时间,动态刷新并加载最新的配置

8. Gateway

8.1 背景介绍

Gateway是spring cloud提供的下一代网关服务,相比于Zuul有更好的性能,更灵活的路由配置和更丰富的过滤器功能

8.2 与Zuul的区别

Gateway在工作流程上与Zuul区别不大,都是请求先到到组件,由组件根据路由规则,选择合适的服务实例,这过程中还会经过滤器过滤,负载均衡器分发等,它与Zuul的主要区别如下:

  1. 响应式编程:Gateway提供了响应式编程支持,在响应式编程中,数据流可以被观察,可以触发响应的处理逻辑,在高并发情况下,可以提供更好的性能
  2. 过滤器链:Gateway支持过滤器链,这是一组过滤器组成的链条,请求需要依次通过这些过滤器,这种方式可以实现对请求的统一管理
  3. 动态路由:Gateway支持动态路由,支持根据请求的条件,动态选择路由规则,将请求路由到不同的服务实例,这些条件包括请求的URL、请求头、请求参数

你可能感兴趣的:(面试,spring,cloud,spring,后端)