微服务 - 图1

1. 微服务基础

  1. 怎么理解微服务?

  2. 微服务之间是怎么通信的
    在微服务架构中, 通常会使用以下两种服务调用方式:

    第一种同步, 同步通信:dubbo通过 RPC 远程过程调用、springcloud通过 REST接口json调用等。
    第二种异步, 通过在轻量级消息总线上传递消息, 类似 RabbitMq、ActiveMq、Kafka 等一些提供可靠异步交换的中间件。

  3. 你对服务治理怎么理解的?

  4. 服务治理怎么实现的?(说了限流、压测、监控等模块的实现)
  5. 微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑

    springcloud与dubbo有哪些区别

  • SpringCloud和Dubbo都是现在主流的微服务架构。
  • SpringCloud是Apache旗下的Spring体系下的微服务解决方案;Dubbo是阿里系的分布式服务治理框架从技术维度上,其实SpringCloud远远的超过Dubbo,Dubbo本身只是实现了服务治理,而SpringCloud现在以及有21个子项目以后还会更多。
  • 服务的调用方式Dubbo使用的是RPC远程调用,而SpringCloud使用的是 Rest API,其实更符合微服务官方的定义。
  • 服务的注册中心来看,Dubbo使用了第三方的ZooKeeper作为其底层的注册中心,实现服务的注册和发现,SpringCloud使用Spring Cloud Netflix Eureka实现注册中心,当然SpringCloud也可以使用ZooKeeper实现,但一般我们不会这样做服务网关,Dubbo并没有本身的实现,只能通过其他第三方技术的整合,而SpringCloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发,SpringCloud还支持断路器,与git完美集成分布式配置文件支持版本控制,事务总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素

image.png

rest与rpc区别

  • RPC最主要的缺陷就是服务提供方和调用方式之间依赖太强,我们需要为每一个微服务进行接口的定义,并通过持续继承发布,需要严格的版本控制才不会出现服务提供和调用之间因为版本不同而产生的冲突
  • 而REST是轻量级的接口,服务的提供和调用不存在代码之间的耦合,只是通过一个约定进行规范,但也有可能出现文档和接口不一致而导致的服务集成问题,但可以通过swagger工具整合,是代码和文档一体化解决,所以REST在分布式环境下比RPC更加灵活。

2. SpringCloud

SpringCloud全局图
image.png
SpringCloud组件架构图
image.png
流程:

  • 请求统一通过 API 网关(gateway或者Zuul 已淘汰)来访问内部服务。
  • 网关接收到请求后,从注册中心(Eureka)获取可用服务。
  • 由 Ribbon 进行均衡负载后,分发到后端具体实例。
  • 微服务之间通过 Feign 进行通信处理业务。
  • Hystrix 负责处理服务超时熔断。(Hystrix会搞很多个小小的线程池,比如订单服务请求库存服务是一个线程池,请求仓储服务是一个线程池。每个线程池里的线程就仅仅用于请求那个服务。)
  • Turbine 监控服务间的调用和熔断相关指标。

2.1. Springcloud 实现原理

SpringCloud是一个基于SpringBoot实现的微服务架构开发工具。它为微服务架构中涉及的配置管理、服务治理、断路器、智能路由、微代理、 控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。都可以用Spring Boot的开发风格做到一键启动和部署。Spring并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
SpringCloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品,还可能会新增), 如下所述。

  • SpringCloudConfig: 配置管理工具, 支持使用Git存储 配置内容, 可以使用它实现 应用配置的外部化存储,并支持客户端配置信息刷新、 加密/解密配置内容等。
  • SpringCloudNetflix: 核心组件, 对多个Netflix OSS开源套件进行整合。
    • Eureka: 服务治理组件, 包含服务注册中心、 服务注册与发现机制的实现。
    • Hystrix: 容错管理组件,实现断路器模式, 帮助服务依赖中出现的延迟和为故障提供强大的容错能力。
    • Ribbon: 客户端负载均衡的服务调用组件。
    • Feign: 基于伈bbon 和 Hystrix 的声明式服务调用组件。
    • Zuul: 网关组件, 提供智能路由、 访问过滤等功能。
    • Archaius: 外部化配置组件。
  • Spring Cloud Bus: 事件、 消息总线, 用于传播集群中的状态变化或事件, 以触发后续的处理, 比如用来动态刷新配置等。
  • Spring Cloud Cluster: 针对 ZooKeeper、 Redis、 Hazelcast、 Consul 的选举算法和通用状态模式的实现。
  • Spring Cloud Stream: 通过 Redis、 Rabbit 或者 Kafka 实现的消费微服务, 可以通过简单的声明式模型来发送和接收消息。
  • …….

    2.2. Spring 与SpringBoot,springcloud区别

    Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的云应用开发工具;Spring Boot专注于快速、方便集成的单个个体,Spring Cloud是关注全局的服务治理框架;Spring Boot使用了默认大于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现,可以不基于Spring Boot吗?不可以。
    Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。

    spring -> spring boot > Spring Cloud 这样的关系。

2.3. Springcloud Eureka是怎么做服务的注册发现,他底层的存储如何存储服务列表,它的筛选机制是什么.

服务发布时,指定对应的服务名,将服务注册到 注册中心eureka,注册中心加@EnableEurekaServer,服务用@EnableDiscoveryClient,然后用ribbon或feign进行服务直接的调用发现。
SpringCloud Eureka是SpringCloud Netflix服务套件中的一部分,它基于Netflix Eureka做了二次封装,主要负责完成微服务架构中的服务治理功能。本身是基于Rest的服务,它包含服务端和客户端两部分;
服务治理一般都会有两个功能:服务注册、服务发现。通常会有一个注册中心,每个服务单元向注册中心登记自己信息,比如提供的服务,ip, 端口以及一些附近加信息等。注册中心会将新的服务实例发送给其它依赖此服务的实例。
服务注册:
服务提供者在启动时会将自己的信息注册到Eureka Server, Eureka Server收到信息后, 会将数据信息存储在一个双层结构的Map中,其中第一层的key是服务名(InstanceInfo中的appName属性),第二层的key是具体服务的实例名(InstanceInfo中的instanceId属性)
Eureka Server 的数据存储分了两层:数据存储层和缓存层。数据存储层记录注册到 Eureka Server 上的服务信息,缓存层是经过包装后的数据,可以直接在 Eureka Client 调用时返回。我们先来看看数据存储层的数据结构。
Eureka Server 的数据存储层是双层的 ConcurrentHashMap,我们知道 ConcurrentHashMap 是线程安全高效的 Map 集合。

  1. private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry= new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>();

第一层的 ConcurrentHashMap 的 key=spring.application.name 也就是客户端实例注册的应用名;value 为嵌套的 ConcurrentHashMap。
第二层嵌套的 ConcurrentHashMap 的 key=instanceId 也就是服务的唯一实例 ID,value 为 Lease 对象,Lease 对象存储着这个实例的所有注册信息,包括 ip 、端口、属性等。
image.png
服务同步:
如果有多个Eureka Server,一个服务提供者向其中一个Eureka Server注册了,这个Eureka Server会向集群内的其它Eureka Server转发这个服务提供者的注册信息,从而实现实现Eureka Server之间的服务同步。
自我保护
默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。
自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制
此时会出现以下几种情况:

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

因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,
而不会像ZK(zookeeper)那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。

Eureka和ZooKeeper都可以提供服务注册与发现的功能,请说说两个的区别

  • ZooKeeper保证的是CP,Eureka保证的是APZooKeeper在选举期间注册服务瘫痪,虽然服务最终会恢复,但是选举期间不可用的;Eureka各个节点是平等关系,只要有一台Eureka就可以保证服务可用,而查询到的数据并不是最新的。 自我保护机制会导致Eureka不再从注册列表移除因长时间没收到心跳而应该过期的服务。Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点(高可用),当网络稳定时,当前实例新的注册信息会被同步到其他节点中(最终一致性),Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像ZooKeeper一样使得整个注册系统瘫痪。
  • ZooKeeper有Leader和Follower角色,Eureka各个节点平等
  • ZooKeeper采用过半数存活原则,Eureka采用自我保护机制解决分区问题
  • Eureka本质上是一个工程,而ZooKeeper只是一个进程

    什么是服务熔断?什么是服务降级

    服务熔断 (异常超时,快速响应)

    如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。熔断设计:三个模块: 熔断请求判断算法、熔断恢复机制、熔断报警
    (1)熔断请求判断机制算法:使用无锁循环队列计数,每个熔断器默认维护10个bucket,每1秒一个bucket,每个blucket记录请求的成功、失败、超时、拒绝的状态,默认错误超过50%且10秒内超过20个请求进行中断拦截。
    (2)熔断恢复:对于被熔断的请求,每隔5s允许部分请求通过,若请求都是健康的(RT<250ms)则对请求健康恢复。
    (3)熔断报警:对于熔断的请求打日志,异常请求超过某些设定则报警

    服务降级

    概念:当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。

    降级方案:

  • 服务接口拒绝服务:页面能访问,但是添加删除提示服务器繁忙。页面内容也可在 Varnish 或 CDN 内获取。

  • 页面拒绝服务:页面提示由于服务繁忙此服务暂停。跳转到 varnish 或 nginx 的一个静态页面。
  • 延迟持久化:页面访问照常,但是涉及记录变更,会提示稍晚能看到结果,将数据记录到 异步队列 或 log ,服务恢复后执行。
  • 随机拒绝服务:服务 接口随机 拒绝服务,让用户重试,目前较少有人采用。因为用户体验不佳。

    服务降级与服务熔断的区别

    降级:降级的目的是为了解决整体项目的压力,而牺牲掉某一服务模块而采取的措施。
    熔断:熔断的目的是当A服务模块中的某块程序出现故障后为了不影响其他客户端的请求而做出的及时回应。
    相同点:
  • 目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;
  • 最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用;
  • 粒度一般都是服务级别,当然,业界也有不少更细粒度的做法,比如做到数据持久层(允许查询,不允许增删改);
  • 自治性要求很高,熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段 ;

不同点:

  • 触发原因不太一样, 服务降级一般是从整体负荷考虑,而服务熔断一般是某个服务(下游服务)故障引起 ;
  • 管理目标的层次不太一样, 降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始);熔断 其实是一个框架级的处理,每个微服务都需要(无层级之分),

    Ribbon和Feign的区别?

  • Ribbon都是调用其他服务的,但方式不同。

  • 启动类注解不同,Ribbon是@RibbonClient feign的是@EnableFeignClients
  • 服务指定的位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
  • 调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。Feign需要将调用的方法定义成抽象方法即可。

什么是Spring Cloud Bus?

spring cloud bus 将分布式的节点用轻量的消息代理连接起来,它可以用于广播配置文件的更改或者服务直接的通讯,也可用于监控。如果修改了配置文件,发送一次请求,所有的客户端便会重新读取配置文件。使用:

  • 添加依赖
  • 配置rabbimq

    什么是SpringCloudConfig?

    在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。使用:

  • 添加pom依赖

  • 配置文件添加相关配置
  • 启动类添加注解@EnableConfigServer

ribbon是如何实现负载均衡的

Feign Client会在底层根据你的注解,跟你指定的服务建立连接、构造请求、发起请求求、获取响应、解析响应是如何做的?

Feign的一个关键机制就是使用了动态代理。咱们一起来看看下面的图,结合图来分析:

  • 首先,如果你对某个接口定义了@FeignClient注解,Feign就会针对这个接口创建一个动态代理
  • 接着你要是调用那个接口,本质就是会调用 Feign创建的动态代理,这是核心中的核心
  • Feign的动态代理会根据你在接口上的@RequestMapping等注解,来动态构造出你要请求的服务的地址
  • 最后针对这个地址,发起请求、解析响应

image.png

Gateway 与Zuul 区别

gateway过滤器
sprincloud gateway中主要有两种类型的过滤器:GlobalFilter 和 GatewayFilter

  • GlobalFilter : 全局过滤器,对所有的路由均起作用

只需要添加 @Component 注解,不需要进行任何额外的配置,实现GlobalFilter接口,自动会对所有的路由起作用

  • GatewayFilter : 只对指定的路由起作用

自定义GatewayFilter
自定义GatewayFilter有两种实现方式,一种是直接实现GatewayFilter接口,另一种是继承AbstractGatewayFilterFactory类 ,任意选一种即可

Spring Cloud Gateway的工作原理和设计模型,整理一下它的特点:

底层依然是servlet,但使用了webflux,多嵌套了一层框架
理解filter、handler、locator就能灵活使用它,但其大量使用的流式编程容易让人懵逼
提供了非常丰富的filter实现和灵活的RoutePredicateFactory(route匹配规则)
依赖spring-boot-starter-webflux和spring-cloud-starter
提供了异步支持
提供函数式编程api,使用起来方便快捷
提供了抽象流控,并默认实现了RedisRateLimiter
提供了抽象负载均衡
支持HttpClient、WebClient代理请求
ps.槽点就是作为Spring家族,注释竟然这么少!

对比Spring Cloud Netflix Zuul和Spring Cloud Gateway

前面整理了两者的特点,现在对比来分析,得出以下结论:

两者均是web网关,处理的是http请求
gateway对比zuul多依赖了spring-webflux,在spring的支持下,功能更强大,内部实现了限流、负载均衡等,扩展性也更强,但同时也限制了仅适合于Spring Cloud套件,而zuul则可以扩展至其他微服务框架中,其内部没有实现限流、负载均衡等
gateway很好的支持异步,而zuul仅支持同步,那么理论上gateway则更适合于提高系统吞吐量(但不一定能有更好的性能),最终性能还需要通过严密的压测来决定
从框架设计的角度看,gateway具有更好的扩展性,并且其已经发布了2.0.0的RELESE版本,稳定性也是非常好的
编码上看,zuul更加简洁易懂,注释规范清晰,而gateway作为Spring家族的一份子,竟然几乎不注释…
总的来说,在微服务架构,如果使用了Spring Cloud生态的基础组件,则Spring Cloud Gateway相比而言更加具备优势,单从流式编程+支持异步上就足以让开发者选择它了。

3. Dubbo

自己如何实现类似Dubbo的RPC框架?

  1. Dobbo如何提供服务的?有机器宕机怎么检测出来?如何找到服务?
  2. Dubbo的原理?(说了服务注册与发布以及消费者调用的过程,说了虚拟机一般要对内核进行虚拟化,docker则用cgroup和namespace分别进行硬件和命名空间的隔离。)踩过什么坑没有?(说了dubbo异常处理的和打印accesslog的问题)
  3. Dubbo的远程调用怎么实现的?(讲了读取配置、拼装url、创建Invoker、服务导出、服务注册以及消费者通过动态代理、filter、获取Invoker列表、负载均衡等过程)
  4. dubbo的生产者如何发布服务,注册服务,消费者如何调用服务?
  5. dubbo负载均衡如何做的? 负载均衡的策略有哪些?一致性哈希详细聊一下?
  6. 如何实现负载均衡,有哪些算法可以实现?
  7. Dubbo踩过哪些坑,分别是怎么解决的?(说了异常处理时业务异常捕获的问题,自定义了一个异常拦截器)
  1. Dubbo内置了哪几种服务容器?
  • Spring Container
  • Jetty Container
  • Log4j Container
  1. Dubbo 核心的配置有哪些?

其核心部分包含:

  • 远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。
  • 集群容错: 提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
  • 自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

image.png

  1. Dubbo有哪几种集群容错方案,默认是哪种?

image.png

  1. Dubbo有哪几种负载均衡策略,默认是哪种?

image.png

  1. Dubbo默认使用的是什么通信框架,还有别的选择吗?

    Dubbo 默认使用 Netty 框架,也是推荐的选择,另外内容还集成有Mina、Grizzly
    http://dubbo.apache.org/zh-cn/blog/dubbo-loadbalance.html

Dubbo的底层实现原理和机制
描述一个服务从发布到被消费的详细过程

Dubbo的服务请求失败怎么处理
重连机制会不会造成错误