1、什么是微服务

微服务,也叫微服务架构,微服务架构是一种架构模式,它提倡将单一应用程序划分成一组组小的服务,Spring Boot 就是提供功能的微服务,服务之间互相协调、互相配合,最终每个服务运行在其独立的进程中。

2、什么是 Spring Cloud

分布式微服务架构的一站式解决方案,是多种微服务架构落地技术的集合体,一个完整的微服务架构应该有以下功能构成。

  • 服务注册与发现
  • 服务调用
  • 服务熔断、降级
  • 负载均衡
  • 服务消息队列
  • 配置中心
  • 服务网关
  • 服务监控、全链路追踪
  • 自动化构建部署
  • 服务定时任务调度操作

Spring Boot 和 Spring Cloud 的区别?

Spring Boot 专注于快速方便的开发单个个体微服务。
Spring Cloud 是关注全局的微服务协调整理治理框架,它将 Spring Boot 开发的一个个单体微服务整合并管理起来,为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务

Spring Boot 可以离开 Spring Cloud 独立使用开发项目, 但是 Spring Cloud 离不开 Spring Boot ,属于依赖的关系.

什么是服务注册、服务发现?

服务注册:当服务器启动的时候,会把当前自己服务器的信息,比如服务地址、通讯地址等以别名的方式添加到注册中心上。

服务发现:另一方(消费者、服务提供者) ,以该别名的方式去注册中心上获取到实际的服务通讯地址,即可实现服务的远程调用。

Eureka 了解过吗?

了解过

  • Eureka 实现了服务治理,这是一种专门管理服务之间依赖关系的一种机制,实现了服务注册与发现、服务调用、负载均衡、容错等功能
  • Eureka 采用了 CS 的设计架构,Eureka Server 作为服务注册功能的服务器,它是服务注册中心。
  • 系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server 时,会同时维持心跳连接,这样系统的维护人员就可以通过 Eureka Server,来监控系统中各个微服务是否正常运行。
  • 本质上是一个存 key,取 value 的过程,存的是服务名,取的是调用地址

Eureka 的两个组件

Eureka Server:提供服务注册服务

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

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

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

Eureka 的自我保护机制是怎么实现的?

当 Eureka Server 节点在短时间内丢失了过多实例的连接时,比如网络故障或频繁启动关闭客户端,节点会进入自我保护模式,保护注册信息,不再删除注册数据,故障恢复时,会自动退出自我保护模式。

Eureka 和 Zookeeper 的区别

  1. Eureka 取 CAP 的 AP,注重可用性,Zookeeper 取 CAP的 CP 注重一致性。
  2. Zookeeper 在选举期间注册服务瘫痪,虽然服务最终会恢复,但选举期间不可用。
  3. Eureka 的自我保护机制,不会再从注册列表移除因长时间没收到心跳而过期的服务。依然能接受新服务的注册和查询请求,但不会被同步到其他节点。不会服务瘫痪。
  4. Zookeeper 有 Leader 和 Follower 角色,Eureka 各个节点平等。
  5. Zookeeper 采用过半数存活原则,Eureka 采用自我保护机制解决分区问题。
  6. Eureka 本质是一个工程,Zookeeper 只是一个进程。

什么是负载均衡

负载均衡(Load Balance)就是将用户的请求平摊的分配到多个服务上,从而达到系统的高可用,分为分为集中式 LB,与进程内 LB

集中式 LB

即在服务的消费方和提供方之间使用独立的 LB 设施(如 Nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方;

进程内 LB

将 LB 逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。

Ribbon 本地负载均衡客户端与 Nginx 服务端负载均衡区别

Nginx 是服务器负载均衡,客户端所有请求都会交给 Nginx,然后由 Nginx 实现转发请求。即负载均衡是由服务端实现的。

Ribbon 是本地负载均衡,在调用微服务接口时候,会在注册中心上获取到注册信息服务列表,之后将其缓存到 JVM 本地,从而在本地实现RPC 远程服务调用技术。

什么是 Ribbon?

Ribbon 是一个负载均衡客户端,可以很好的控制 HTTP 和 TCP 的一些行为。Feign 默认集成了 Ribbon。

什么是 Feign?

Feign 是 Spring Cloud 组件中的一个轻量级 RESTful 的 HTTP 服务客户端。Feign 在 Ribbon+ RestTemplat 基础上做了进一步封装, 它来帮助我们定义和实现依赖服务接口的定义。在 Feign 的实现下,我们只需创建一个接口并使用注解的方式来配置它,即可完成对服务提供方的接口绑定,简化了使用 Ribbon 时,自动封装服务调用客户端的开发量。

说一下 Feign 的调用流程

  1. 构造请求数据,将对象转为 Json
  2. 发送请求进行执行(执行成功会解码响应数据)
  3. 当然执行请求期间会有重试机制

说一下 Hystrix 的作用

Hystrix是一个用于处理分布式系统的延迟容错的开源库,它可以保证在一个依赖出问题的情况下, 不会导致整体服务失败,避免级联故障,以提高分布式系统的可用性

Hystrix 是如何工作的?

当 Hystrix 监控到某个服务在使用期间发生故障时,它会向调用方返回一个符合预期的、可处理的备选响应(FallBack) ,而不是长时间的等待或者抛出调用方无法处理的异常这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

说一下 Gateway

Spring Cloud Gateway 是 Spring Cloud 官方推出的第二代网关框架,目标是取代 Zuul 网关,它旨在提供一种简单而且有效的方式来对API 进行路由,以及提供一些强大的过滤器功能,例如:熔断,限流,重试等。Spring Cloud Gateway 是基于 WebFlux 框架实现的,而WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty

Gateway 和 Zuul 的区别

在Spring Cloud Gateway Finchley正式版发布之前,Spring Cloud推荐的网关是NetFlix提供的Zuul

  1. Zuul 1.x 是一个基于阻塞IO的API Gateway
  2. Zuul 1.x 基于 Servlet 2.5 使用阻塞架构,它不支持任何长连接,Zuul 的设计模式和 Nginx 比较像,每次 IO 操作都是从工作线程中选择一个执行,请求线程被阻塞直到工作线程完成,但是差别是 Nginx 用 C++ 实现,Zuul 用 Java 实现,而 JVM 本身会有第一次加载较慢的情况,所以导致 Zuul 的性能较差。
  3. Zuul 2.x 理念更先进,想基于 Netty 非阻塞和支持长连接,但 Spring Cloud并没有整合。Zuul 2.X 的性能相比于 1.X 有较大提升,
  4. Spring Cloud Gateway 建立在 Spring 5,Spring Boot 2.X 之上,使用非阻塞API
  5. Spring Cloud Gateway 还支持 WebSocket,并且与 Spring 紧密集成,拥有更好的开发体验。
  6. 在性能方面,根据官方提供的基准测试,Spring Cloud Gateway 的RPS(每秒请求数)是 Zuul 的 1.6倍。

Gateway 的路由、断言、过滤

Route 路由

  • 路由就是构建网关的基本模块,它由 ID、目标 URI、一系列的断言和过滤器组成,如果断言为 True 则匹配该路由

Predicate 断言

  • 开发人员可以匹配 HTTP 请求中的所有内容,例如请求头和请求参数,如果请求与断言相匹配则进行路由

Filter 过滤

  • 指的是 Spring 框架中 GatewayFilter 的实例,使用过滤器,可以在路由前后对请求进行修改。

Gateway 的工作流程

客户端向Spring Cloud Gateway发出请求,然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。

Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。

过滤器可以在请求之前(pre)做参数校验、权限校验、流量监控、日志输出、协议转换等。

也可以在请求之后(post)做响应内容、响应头的修改、日志的输出、流量监控等有着非常重要的作用。

Spring Cloud Config 分布式配置中心

Spring Cloud Config 为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用提供了一个中心化的外部配置

Spring Cloud Config 分为两部分

  • 服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。
  • 客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息,配置服务器默认采用 git 来存储配置信息,这样有助于对环境配置进行版本管理,并且可以通过 git 客户端工具来方便的管理和访问配置内容。

Spring Cloud Config 的主要作用

  • 集中管理配置文件
  • 不同环境不同配置,动态化的配置更新,分布式部署,比如 dev/test/prod/beta/release,开发/测试/产品/预发布/灰度
  • 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取自己的信息
  • 当配置发生变动时,服务不需要重启即可感知配置的变化并应用新的配置
  • 将配置信息以 REST接口的形式暴露:post,cur l命令刷新

什么是 Spring Cloud Bus

Spring Cloud Bus 是用来将分布式系统的节点与轻量级消息系统链接起来的框架,它整合了 Java 的事件处理机制和消息中间件的功能,它能管理和传播分布式系统的消息,就像一个分布式执行器,可用于广播状态更改,事件推送等,也可以当做微服务的通信通道。

Spring Cloud Sleuth分布式请求链路跟踪

在微服务框架中,一个由客户端发起的请求,在后端系统中会经过多个不同的服务节点调用,来协同产生最后的请求结果,每一个前端请求都会形成一条复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求最后的失败。

当链路特别多的时候,就需要有一个用于调用链路的监控和服务跟踪的解决方案

Spring Cloud Sleuth提供了一套完整的服务跟踪解决方案,在分布式系统中,提供了追踪解决方案,并且兼容支持了zipkin。

Spring Cloud Alibaba

采用 Spring Cloud Alibaba 主要是因为 Spring Cloud 项目进入了维护模式,这就意味着 Spring Cloud 不再开发新的组件了。

用过以下产品

  • Sentinel:阿里巴巴开源产品,把流量作为切入点,从流量控制,熔断降级,系统负载 保护等多个维度保护系统服务的稳定性
  • Nacos:阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台
  • Seata:一个易于使用的高性能微服务分布式事务解决方案
  • Alibaba Cloud OOS:阿里云对象存储(Object Storage Service,简称OOS),是阿里云提供的海量,安全,低成本,高可靠的云存储服务,您可以在任何应用,任何时间,任何地点存储和访问任意类型的数据。

你们项目为什么采用 Nacos

它是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台,Nacos 它集成了服务注册与配置中心,Nacos 等价于 Eureka + Config + Bus,它不仅实现了 CAP 模型中的 AP 原则,同时它还支持 CP。

Nacos 支持的这两种模式有什么区别呢?

一般来说,如果不需要存储服务级别的信息且服务实例是通过nacos-client注册,并能够保持心跳上报,那么就可以选择 AP 模式

CP 模式下则支持注册持久化实例,此时则是以 Raft 协议为集群运行模式,该模式下注册实例之前必须先注册服务,如果服务不存在,则会返回错误

Nacos 为什么创建两个配置文件

Nacos 同 Spring Cloud Config 一样,在项目初始化时,要保证先从配置中心拉取配置,拉取配置之后,才能保证项目的正常运行。

Spring Boot 中配置文件的加载是存在优先级顺序的:bootstrap 优先级高于 application

如何保证不同生产环境下,服务能正确读取到 Nacos上相应环境的配置文件呢?

Nacos 采用 Namespace + Group + DataID 进行区分,最外层的 Namespace 是可以用于区分部署环境的,Group 和 DataID逻辑上区分两个目标对象

默认情况:

Namespace=publicGroup=DEFAULT_GROUPCluster=DEFAULT

Nacos 默认的 Namespace(命名空间)是public,Namespace主要用来实现隔离

  • 比如说我们现在有三个环境:开发,测试,生产环境,我们就可以建立三个 Namespace,不同的 Namespace 之间是隔离的。

Group默认是DEFAULT_GROUP

  • Group可以把不同微服务划分到同一个分组里面去

Service 就是微服务,一个 Service 可以包含多个 Cluster(集群)

  • Nacos 默认 Cluster 是 DEFAULT,Cluster 是对指定微服务的一个虚拟划分。
  • 比如说为了容灾,将 Service 微服务分别部署在了杭州机房,这时就可以给杭州机房的 Service 微服务起一个集群名称(HZ),给广州机房的 Service 微服务起一个集群名称,还可以尽量让同一个机房的微服务相互调用,以提升性能,最后 Instance,就是微服务的实例。

Nacos 的集群部署了解吗

Nacos支持三种部署模式

  • 单机模式:用于测试和单机使用
  • 集群模式:用于生产环境,确保高可用
  • 多集群模式:用于多数据中心场景

在部署之前,需要先解决一个问题,Nacos 默认使用嵌入式数据库 derby 实现数据的存储,所以,如果启动多个默认配置下的 Nacos 节点,数据存储是存在一致性问题的。为了解决这个问题,Nacos 采用了集中式存储的方式来支持集群化部署,目前只支持 MySQL 的存储,因此我们需要完成从 derby 到 mysql 切换。

说一下 Sentinel

Sentinel 等同于 Hystrix,但是实现了很多 Hystrix 没有实现的功能,比如一个更加细粒度化配置服务限流、熔断、降级的 web 界面,Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 的规则如何持久化

将限流配置规则持久化进Nacos保存,只要刷新某个 rest 地址,Sentinel 控制台的流控规则就能看到,只要 Nacos 里面的配置不删除,针对端口上的流控规则一直有效

说说你对 Seata 的理解

Seata 是一款开源的分布式事务解决方案,可以在微服务架构下提供高性能和简单易用的分布式事务服务。Seata 默认使用 AT 模式。

Seata是由1+3的套件所组成

  • Transaction ID XID:全局唯一的事务ID,只要在同一ID下,不管几个库,3个就是3个,10个就是10,说明它们是一个整体。
    三组件的:
  • Transaction Coordinator(TC):事务协调者,维护全局事务,驱动全局事务提交或者回滚
  • Transaction Manager(TM):事务管理器,定义全局事务的范围,开始全局事务、提交或回滚全局事务
  • Resource Manager(RM):资源管理器,管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

Seata 的工作流程

我们现在要执行一个大下单业务 Business

大下单业务的 TM(事务管理器)先会告诉 TC(事务协调者)它要准备开启一个全局事务。

事务协调者就知道,TM(事务管理器)现在可能要跨服务开一个全局的事务,要么这些都成功,要么这些都失败。

只要TM(事务管理器)告诉了这个TC(事务协调者),它要开始全局事务了,那接下来它调用第一个微服务的事务方法的时候。

我们这个 Storage 服务就会在 TC(事务协调者)注册一下,我们称为分支。我们把这个事务称为分支事务,就是最上面 Storage 那个

相当于它的 RM(资源管理器)会告诉 TC(事务协调者),它有一个分支事务,并且它要实时汇报它的事务状态,它这个分支是提交成功还是失败回滚, TC(事务协调者)都能实时的知道。

然后我们这个大业务,调完了它第一个远程服务,

接下来调我们第二个远程服务 Order

第二个远程服务的 RM(资源管理器)也会在 TC(事务协调者)注册自己的分支事务,并且实时给TC(事务协调者)汇报它当前的事务状态。

接下来要调到第三个远程服务 Account,然后第三个微服务的RM(资源管理器)也会在 TC(事务协调者)注册自己的分支事务,并且汇报状态。

那这样就好了。

大事务只要一开启,每调一个小事务,TC(事务协调者)都知道这个小事务成了还是败了。

假设我们调到最后一个,最后一个这个小事务给 TC(事务协调者)汇报状态。说执行失败了,我得回滚了。

所以呢第四个分支事务相当于回滚了,回滚了怎么办?

TC(事务协调者)知道我们的大事务,已经调成功两个了。前两个事务都已经提交了,但是第三个事务给回滚了,TC(事务协调者)就会命令前两个事务也回滚。

这就是他们三者的关系。

Seata 是怎么回滚已提交的事务的?

已提交的我们只能做一个反向补偿。

这个反向补偿,我们以前如果使用 TCC 模式,我们自己可以写一段代码,比如我们之前加二了,我们调用自己写的反向补偿代码给它减二。

但是我们现在是自动模式,用户不用写这个代码,不写这个代码怎么办呢?

所以我们就需要一个UNDO_LOG 表,每一个微服务都需要。

比如 Storage 服务,在它的数据库里边,除了它正常的业务表以外,它还需要有一个回滚日志表。

相当于它无论干了什么,比如说给这条记录加二了,都得在回滚日志里边记录一下:给谁谁谁刚才加二了。

那如果它都提交成功了,当执行到最后一个的时候,TC 又让它回滚,怎么办呢?

它其实没法回滚,只能说恢复以前的状态。我们加二前的状态呢是减二,那我呢就给你再减二,恢复以前的状态。

它是这么做的,它先在UNDO_LOG 里面记录了一下这条记录没改变之前值,比如是八。

如果它失败回滚了,那它就回过头把我们数据库里边的这个十再改回去,改成八。

所以它相当于在我们事务执行之前,它先读取一下这个状态是几,最后再改回来,这就是它的这种模式,AT 模式。