热点面试题之springBoot、springCloud

1.SpringBoot面试题

1.1.简单聊聊SpringBoot的作用是什么?

知识背景:

SpringBoot采用默认配置,帮助我们快速的构建和运行Spring项目:

  • 简化spring初始搭建和开发过程
  • 提供了大量的starter,集成了spring及大量第三方应用的自动配置
  • 允许使用配置文件(properties或者yml文件)覆盖默认配置
  • 创建独立的spring应用程序,使用main方法运行
  • 内嵌Tomcat无需部署war包,直接打成jar包,用nohup java -jar – & 启动就好

面试话术

SpringBoot是一个快速构建项目并简化项目配置的工具,内部集成了Tomcat及大多数第三方应用和Spring框架的默认配置。与我们学习的SpringMVC和SpringCloud并无冲突,SpringBoot提供的这些默认配置,大大简化了SpringMVC、SpringCloud等基于Spring的Web应用的开发。

1.2.SpringBoot的自动配置原理?

**问题1:**那你说说SpringBoot的自动配置是如何实现的?

面试话术:

一般我们的SpringBoot项目启动类都会添加@SpringBootApplication注解,而这个注解的其中一个二级注解是@EnableAutoConfiguration注解。而@EnableAutoConfiguration注解通过@Import注解,以ImportSelector接口的方法来导入classpath下的META-INF/spring.factories文件,这些文件中会指定需要加载的一些类名称。

这些类一般都加了@Configuration注解,并且完成了对某框架(例如Redis、SpringMVC)的默认配置,当这些类符合条件时,就会被实例化,其中的配置生效,那么自动配置自然生效了。

问题2:满足怎样的条件配置才会生效?

面试话术:

一般提供默认配置的类都会添加@ConditionalOnXxx这样的注解,例如:@ConditionalOnClass@ConditionalOnProperties等。@ConditionalOnClass表示只有classpath中存在某些指定的类时,条件满足,此时该配置类才会生效。例如Redis的默认配置其实早就有了,但是只有你引入redis的starter依赖,才满足了条件,触发自动配置。

问题3:那如果我需要覆盖这些默认配置呢?

有两种方式可以覆盖默认配置:

  • SpringBoot提供默认配置时,会在提供的Bean上加注解@ConditionalOnMissingBean,意思是如果这个Bean不存在时条件满足,那么我们只要配置了相同的Bean,那么SpringBoot提供的默认配置就会失效
  • SpringBoot提供默认配置时,一些关键属性会通过读取application.yml或者application.properties文件来获取,因此我们可以通过覆盖任意一个文件中的属性来覆盖默认配置。

1.3.有没有自定义过SpringBoot的stater?

面试话术

有,项目中某些中间件的客户端(如Redis、ElasticSearch)会进行二次封装,并通过starter方式提供jar包,供大家使用。

一般定义starter包括下面几个子工程:

  • xxx-spring-boot-starter:pom格式,管理当前starter中需要的各种依赖
  • xxx-spring-boot-autoconfigure:jar格式,自动配置的核心代码

我以elasticsearch为例来说说autoconfigure中包含哪些

  • elasticsearch的工具类
  • 属性加载的类,一般通过@ConfigurationProperties注解读取yaml文件中的es地址
  • 添加了@Configuration的配置类,作用是初始化elasticsearch工具类,初始化elasticsearch客户端,初始化一些其它必备的实例。
  • resource下定义META-INF文件夹,并且文件夹下定义spring.factories文件,文件中是key-value形式
    • key是EnableAutoConfiguration这个注解的全路径名
    • value是我们自定义自动配置类(加了@Configuration的类),如果有多个以","隔开

1.4.SpringBoot项目的启动流程

话术:

SpringBoot项目启动第一步就是创建SpringApplication的实例,并且调用SpringApplication.run()这个方法。

创建SpringApplication实例主要完成三件事情:

  • 记录当前启动类字节码
  • 判断当前项目类型,普通Servlet、响应式WebFlux、NONE
  • 加载/META-INF/spring.factories文件,初始化ApplicationContextInitializer和ApplicationListener实例

而后的run()方法则会创建spring容器,流程如下:

  • 准备监听器,监听Spring启动的各个过程
  • 创建并配置环境参数Environment
  • 创建ApplicationContext
  • prepareContext():初始化ApplicationContext,准备运行环境
  • refreshContext(context):准备Bean工厂,调用一个BeanDefinition和BeanFactory的后处理器,初始化各种Bean,初始化tomcat
  • afterRefresh():拓展功能,目前为空
  • 发布容器初始化完毕的事件

1.5.SpringBoot的配置加载优先级

面试话术:

SpringBoot参数配置方式很多,比较常用参数配置方式按照优先级从高到低分别是:

  • 在命令行中传入的参数

  • java 的系统属性,可以通过System.getProperties()获得的内容

  • 操作系统的环境变量

  • 针对不同{profile}环境的配置文件内容,例如 applicaiton-{profile}.yaml

  • application.yml或application.proerties文件

  • 在@Configration注解修改的类中,通过@PropertySource注解定义的属性

2.SpringCloud相关

2.1.SpringCloud和Dubbo的区别

聊聊看SpringCloud和Dubbo有什么区别?

面试话术:

两者都是现在主流的微服务框架,但却存在不少差异:

  • 初始定位不同:SpringCloud定位为微服务架构下的一站式解决方案;Dubbo 是 SOA 时代的产物,它的关注点主要在于服务的调用和治理
  • 生态环境不同:SpringCloud依托于Spring平台,具备更加完善的生态体系;而Dubbo一开始只是做RPC远程调用,生态相对匮乏,现在逐渐丰富起来。
  • 调用方式:SpringCloud是采用Http协议做远程调用,接口一般是Rest风格,比较灵活;Dubbo是采用Dubbo协议,接口一般是Java的Service接口,格式固定。但调用时采用Netty的NIO方式,性能较好。
  • 组件差异比较多,例如SpringCloud注册中心一般用Eureka,而Dubbo用的是Zookeeper

SpringCloud生态丰富,功能完善,更像是品牌机,Dubbo则相对灵活,可定制性强,更像是组装机。

相关资料:

SpringCloud:Spring公司开源的微服务框架,SpirngCloud 定位为微服务架构下的一站式解决方案,生态丰富,功能完善。

Dubbo:阿里巴巴开源的RPC框架,Dubbo 是 SOA 时代的产物,它的关注点主要在于服务的调用,流量分发、流量监控和熔断。

SpringCloudAlibaba

两者的生态对比:

功能DubboSpringCloud
服务注册中心ZookeeperEureka(主流)、Consul、zookeeper
服务调用方式RPC基于Dubbo协议REST API 基于Http协议
服务监控Dubbo-MonitorSpring Boot Admin
熔断器不完善Spring Cloud Netflix Hystrix
服务网关Spring Cloud Netflix Zuul、Gateway
分布式配置Spring Cloud Config
服务跟踪Spring Cloud Sleuth+Zipkin(一般)
数据流Spring Cloud Stream
批量任务Spring Cloud Task
信息总线Spring Cloud Bus

Spring Cloud 的功能很明显比 Dubbo 更加强大,涵盖面更广,而且作为 Spring 的旗舰项目,它也能够与 Spring Framework、Spring Boot、Spring Data、Spring Batch 等其他 Spring 项目完美融合,这些对于微服务而言是至关重要的。

使用 Dubbo 构建的微服务架构就像组装电脑,各环节选择自由度很高,但是最终结果很有可能因为一条内存质量不行就点不亮了,总是让人不怎么放心,但是如果使用者是一名高手,那这些都不是问题。

而 Spring Cloud 就像品牌机,在 Spring Source 的整合下,做了大量的兼容性测试,保证了机器拥有更高的稳定性,但是如果要在使用非原装组件外的东西,就需要对其基础原理有足够的了解。

2.2.dubbo和Feign远程调用的差异

面试话术:

Feign是SpringCloud中的远程调用方式,基于成熟Http协议,所有接口都采用Rest风格。因此接口规范更统一,而且只要符合规范,实现接口的微服务可以采用任意语言或技术开发。但受限于http协议本身的特点,请求和响应格式臃肿,其通信效率相对会差一些。

Dubbo框架默认采用Dubbo自定义通信协议,与Http协议一样底层都是TCP通信。但是Dubbo协议自定义了Java数据序列化和反序列化方式、数据传输格式,因此Dubbo在数据传输性能上会比Http协议要好一些。

不过这种性能差异除非是达极高的并发量级,否则无需过多考虑。

相关资料:

Dubbo采用自定义的Dubbo协议实现远程通信,是一种典型的RPC调用方案,而SpringCloud中使用的Feign是基于Rest风格的调用方式。

1)Rest风格

REST是一种架构风格,指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。

Rest的风格可以完全通过HTTP协议实现,使用 HTTP 协议处理数据通信。REST架构对资源的操作包括获取、创建、修改和删除资源的操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。

因此请求和想要过程只要遵循http协议即可,更加灵活

SpringCloud中的Feign就是Rest风格的调用方式。

2)RPC

Remote Procedure Call,远程过程调用,就是像调用本地方法一样调用远程方法。RPC架构图:

20190526223643953

RPC一般要确定下面几件事情:

  • 数据传输方式:多数RPC框架选择TCP作为传输协议,性能比较好。
  • 数据传输内容:请求方需要告知需要调用的函数的名称、参数、等信息。
  • 序列化方式:客户端和服务端交互时将参数或结果转化为字节流在网络中传输,那么数据转化为字节流的或者将字节流转换成能读取的固定格式时就需要进行序列化和反序列化

因为有序列化和反序列化的需求,因此对数据传输格式有严格要求,不如Http灵活

Dubbo协议就是RPC的典型代表。

我们看看Dubbo协议和Feign的调用区别:

DubboFeign(Http调用)
传输协议TCPTCP
开发语言java不限
性能一般
灵活性一般

2.3.Eureka和Zookeeper注册中心的区别

面试话术:

SpringCloud和Dubbo都支持多种注册中心,不过目前主流来看SpringCloud用Eureka较多,Dubbo则以Zookeeper为主。两者存在较大的差异:

  • 从集群设计来看:Eureka集群各节点平等,没有主从关系,因此可能出现数据不一致情况;ZK为了满足一致性,必须包含主从关系,一主多从。集群无主时,不对外提供服务
  • CAP原则来看:Eureka满足AP原则,为了保证整个服务可用性,牺牲了集群数据的一致性;而Zookeeper满足CP原则,为了保证各节点数据一致性,牺牲了整个服务的可用性。
  • 服务拉取方式来看:Eureka采用的是服务主动拉取策略,消费者按照固定频率(默认30秒)去Eureka拉取服务并缓存在本地;ZK中的消费者首次启动到ZK订阅自己需要的服务信息,并缓存在本地。然后监听服务列表变化,以后服务变更ZK会推送给消费者。

相关资料:

首先,Eureka和Zookeeper都是服务治理框架,但是设计上有一定的差别。

先看下CAP原则:C-数据一致性;A-服务可用性;P-服务对网络分区故障的容错性,这三个特性在任何分布式系统中不能同时满足,最多同时满足两个。

  • Eureka满足AP,Zookeeper满足CP

    当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是Zookeeper和Eureka在一致性与可用性间做出了不同的选择。

    • Zookeeper:Zookeeper的设计追求数据的一致性,不保证服务的可用性。当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。

    • Eureka:Eureka追求的是服务的可用性,从而牺牲了数据的一致性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况。

      • Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
      • Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)
      • 当网络稳定时,当前实例新的注册信息会被同步到其它节点中

      因此, Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。

  • Eureka集群各节点平等,Zookeeper中有主从之分

    • 如果Zookeeper集群中部分宕机,可能会导致整个集群因为选主而阻塞,服务不可用
    • eureka集群宕机部分,不会对其它机器产生影响
  • Eureka的服务发现需要主动去拉取,Zookeeper服务发现是监听机制

    • eureka中获取服务列表后会缓存起来,每隔30秒重新拉取服务列表
    • zookeeper则是监听节点信息变化,当服务节点信息变化时,客户端立即就得到通知

2.4.SpringCloud中的常用组件有哪些?

Spring Cloud的子项目很多,比较常见的都是Netflix开源的组件:

  • Spring Cloud Config
    集中配置管理工具,分布式系统中统一的外部配置管理,默认使用Git来存储配置,可以支持客户端配置的刷新及加密、解密操作。

  • Spring Cloud Netflix
    Netflix OSS 开源组件集成,包括Eureka、Hystrix、Ribbon、Feign、Zuul等核心组件。

    • Eureka:服务治理组件,包括服务端的注册中心和客户端的服务发现机制;
    • Ribbon:负载均衡的服务调用组件,具有多种负载均衡调用策略;
    • Hystrix:服务容错组件,实现了断路器模式,为依赖服务的出错和延迟提供了容错能力;
    • Feign:基于Ribbon和Hystrix的声明式服务调用组件;
    • Zuul:API网关组件,对请求提供路由及过滤功能。
  • Spring Cloud Bus
    用于传播集群状态变化的消息总线,使用轻量级消息代理链接分布式系统中的节点,可以用来动态刷新集群中的服务配置。

  • Spring Cloud Consul
    基于Hashicorp Consul的服务治理组件。

  • Spring Cloud Security
    安全工具包,对Zuul代理中的负载均衡OAuth2客户端及登录认证进行支持。

  • Spring Cloud Sleuth
    Spring Cloud应用程序的分布式请求链路跟踪,支持使用Zipkin、HTrace和基于日志(例如ELK)的跟踪。

  • Spring Cloud Stream
    轻量级事件驱动微服务框架,可以使用简单的声明式模型来发送及接收消息,主要实现为Apache Kafka及RabbitMQ。

  • Spring Cloud Task
    用于快速构建短暂、有限数据处理任务的微服务框架,用于向应用中添加功能性和非功能性的特性。

  • Spring Cloud Zookeeper
    基于Apache Zookeeper的服务治理组件。

  • Spring Cloud Gateway
    API网关组件,对请求提供路由及过滤功能。

  • Spring Cloud OpenFeign
    基于Ribbon和Hystrix的声明式服务调用组件,可以动态创建基于Spring MVC注解的接口实现用于服务调用,在Spring Cloud 2.0中已经取代Feign成为了一等公民。

2.5.微服务调用关系复杂,如何做监控和错误排查?

面试话术:

企业中对于微服务监控有一套东西,叫做APM。比如:SpringCloudSeluth+Zipkin,Pinpoint、Skywalking,可以实现性能监控、链路跟踪(精确到某个代码,某条sql)、CPU运行情况,链路运行耗时。

当然, 还可以借助于分布式日志管理系统。把项目运行的日志收集,形成统计报表,放入elasticsearch,便于搜索查看。比如:ELK技术栈、GrayLog

2.6.Hystix的作用是什么?

话术:

Hystix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败。比较常用的手段就是线程隔离和服务熔断。

资料:

1)什么是雪崩问题(级联失败)?

在大中型分布式系统中,微服务间调用关系复杂,可能业务会调用多个其它服务,
在高并发访问下,这些依赖的稳定性与否对系统的影响非常大,但是依赖有很多不可控问题:如网络连接缓慢,资源繁忙,暂时不可用,服务脱机等.

如下图:依赖 I 出现不可用,但是其他依赖仍然可用.访问服务A或H的不会有问题,但是访问服务I的请求会阻塞。

当依赖I 阻塞时,当前服务接收的请求会越来越多被阻塞,直到当前tomcat资源被耗尽,没有更多线程可用,导致整个服务崩溃。

2)线程隔离

线程隔离示意图:
在这里插入图片描述

解读:

Hystrix为每个依赖服务调用分配一个小的线程池,如果线程池已满调用将被立即拒绝,默认不采用排队.加速失败判定时间。

用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,或者请求超时,则会进行降级处理,执行fallback(降级)逻辑

3)服务熔断

尽管隔离可以避免服务出现级联失败,但是对于访问**服务I(异常服务)**的其它服务,每次处理请求都要等待数秒直至fallback,显然是对系统资源的浪费。

因此,当Hystix判断一个依赖服务失败比例较高时,就会对其做熔断处理,快速失败,不再阻塞等待。

Hystix的熔断状态机模型:

在这里插入图片描述

状态机有3个状态:

  • Closed:关闭状态(断路器关闭),所有请求都正常访问。
  • Open:打开状态(断路器打开),所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器打开。默认失败比例的阈值是50%,请求次数最少不低于20次。
  • Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放1次请求通过,若这个请求是健康的,则会关闭断路器,否则继续保持打开,再次进行5秒休眠计时。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值