1、为什么要使用微服务?
优点:
- 易于开发于维护
- 可以独立部署
- 可以用不同语言开发,面向接口编程
- 可以灵活搭配,连接公共库/连接独立库
缺点:
- 分布式系统的责任性大
- 多服务运维难度加大
- 系统部署依赖,服务间通信成本,数据一致性,系统集成测试,性能监控
2、Spring Cloud 都有哪些组件?
Eureka、Ribbon、Feign、Hystrix、Config、Zuul、Bus。
3、Spring Cloud 和 Dubbo 的区别?
- 协议:Dubbo 支持 dubbo、rmi、hessian、http、webservice、thrift、memcached、redis、restfull 9种协议,默认是 dubbo 协议,SpringCloud 采用 http 协议。
- 服务调用方式:Dubbo 采用 RPC 远程过程调用(服务提供方和调用方式之间的依赖太强,需要对每一个微服务进行接口的定义),SpringCloud 采用 RestAPI 方式调用(轻量级的接口,服务的提供和调用不存在代码之间的耦合,只需要一个约定进行规范)。
- 注册中心:Dubbo 是 zookeeper,SpringCLoud 是 Eureka,也可以是 zookeeper。
- 服务网关:Dubbo 本身没有实现,只能通过其他第三方技术整合,SpringCloud 有 Zuul 路由网关,作为路由服务器。
- 集成:Dubbo 集成技术太少,而 SpringCloud 具有一整套微服务组件。
Dubbo 构建微服务架构就像组装电脑,各环节我们选择自由度高,但是有可能一个小问题就导致不行,让人不怎么放心。而 SpringCloud 就像品牌机,拥有很高的稳定性。
4、Ribbon 和 Feign的区别?
- 启动类上的注解不同:Ribbon 采用 @RibbonClient,Feign 采用 @EnableFeignClients。
- 服务的指定位置不同:Ribbon 是在 @RibbonClient 注解上声明,Feign 则是在定义抽象方法的接口中使用 @FeignClient 声明。
- 调用方式不同:Ribbon 需要自己模拟 http 请求,然后使用 RestTemplate 发送到其他服务,Feign 则不需要自己模拟请求,将服务定义成抽象方法就行,不过要注意,抽象方法的注解、方法签名要和服务提供方完全一致。
5、Eureka的一些概念
- 服务注册:Eureka 会通过发送 REST 请求的方式向 Eureka Server 注册自己的服务,提供自身的元数据,比如IP地址、端口、主页地址等信息,Eureka Server 接收到注册请求后,将元数据存储在一个双层 Map 中,第一层 key 是服务名称,第二层 key 是具体服务的实例名称。
- 服务同步:Eureka Server之间会互相进行注册,构建Eureka Server集群,不同Eureka Server之间会进行服务同步,用来保证服务信息的一致性。当服务提供者发送注册请求到一个服务注册中心时, 它会将该请求转发给集群中相连的其他注册中心, 从而实现注册中心之间的服务同步。通过服务同步,两个服务提供者的服务信息就可以通过这两台服务注册中心中的任意一台获取到。
- 服务续约:在服务注册后,Eureka Client 会维护一个心跳来持续通知 Eureka Server,说明服务一直处于可用状态,防止被剔除。
# 这是服务端设置
eureka:
server:
# 服务端剔除失效服务的间隔,单位:毫秒(默认60秒)
eviction-interval-timer-in-ms: 2000
# 这是客户端设置
eureka:
instance:
# 客户端向服务端发送心跳的时间间隔,单位:秒(默认30秒)
lease-renewal-interval-in-seconds: 30
# 服务端在收到最后一次心跳之后等待的时间上限,超过则剔除,单位:秒(默认90秒)
lease-expiration-duration-in-seconds: 90
以上加起来是3分钟,也就是说正常默认情况下,会有3分钟左右的剔除延迟。
- 服务获取:当启动客户端的时候,它会发送一个 REST 请求给服务注册中心,来获取上面注册的服务列表,并且缓存在 Eureka Client 本地,默认缓存30秒。Eureka Server 也会维护一份只读的服务列表来返回给客户端,同时服务消费者会在本地缓存服务列表的清单并每隔30秒更新一次。
eureka:
client:
# 启用服务消费者从注册中心拉取服务列表的功能(默认就是true)
fetch-registry: true
# 设置服务消费者从注册中心拉取服务列表的间隔,单位:秒(默认30秒)
registry-fetch-interval-seconds: 30
- 服务调用:客户端从服务端获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息。因为有这些服务实例的详细信息,所以客户端可以根据需要决定具体调用哪个实例,在 ribbon 中默认轮询调用,从而实现客户端的负载均衡。
对于访问实例的选择,Eureka 中有 Region 和 Zone 的概念,一个 Region 中可以包含多个 Zone,每个客户端需要被注册到一个 Zone 中,所以每个客户端对应一个 Region 和一个 Zone。在进行服务调用时,优先访问同处一个 Zone 中的服务,若访问不到,就访问其他的 Zone。
Region 可以简单理解为地理上的分区,比如亚洲地区,或者华北地区。没有具体大小的限制。根据项目具体的情况,可以自行合理划分 Region。
Zone:可以简单理解为 Region 内的具体机房,比如说 Region 划分为北京,然后北京有两个机房,就可以在此 Region 之下划分出 Zone1、Zone2 两个Zone。
- 服务下线:当 Eureka Client 需要正常的关闭时,就不希望这个时间段内再有请求进来,这时需要提前发送 REST 请求给 Eureka Server,告诉 Eureka Server 自己要下线了,服务端在接收到请求后,就会把该服务状态置为下线(DOWN),并把该下线事件传播出去。
- 服务剔除:服务实例并不一定会正常下线,可能由于内存溢出、网络故障等原因使得服务不能正常工作,而服务注册中心并未收到“服务下线” 的请求。为了从服务列表中将这些无法提供服务的实例剔除, Eureka Server 在启动的时候会创建一个定时任务,默认每隔一段时间(默认为60秒) 将当前清单中超时(默认为90秒)没有续约的服务剔除出去。
- 自我保护机制:既然 Eureka Server 有服务剔除机制,那就有可能出现一种场景,由于网络波动导致所有的服务都没能进行续约,如果服务端将所有服务都剔除,显然不合理,所以就有了自我保护机制。
在15分钟内没有续约的服务低于85%,Eureka Server 会将当前实例注册信息保护起来,让这些实例不会过期,等到正常后,再退出自我保护机制。但是,如果自我保护期间实例出现别的问题,那么客户端很容易拿到实际已经不存在的服务实例,会出现调用失败,所以客户端必须要有容错机制,比如可以使用请求重试、断路器等机制。
自我保护机制下,Eureka 仍然能够接收新服务的注册和查询请求,但是不会同步到其他Server节点(即保证当前节点依然可用),当网络稳定时,当前实例新的注册信息会被同步到其他节点中。
本地调试:很容易触发注册中心的保护机制,这会使得注册中心维护的服务实例不那么准确。所以,我们在本地进行开发的时候, 可以使用
eureka.server.enableself-preservation=false
参数来关闭保护机制, 以确保注册中心可以将不可用的实例正确剔除。
6、Eureka Server 集群数据同步
7、服务雪崩、服务降级、服务熔断
- 服务雪崩:一个服务失败不可用,导致整条链路的服务都失败的情形,我们称之为服务雪崩。
- 服务熔断:当下游的服务因为某种原因突然变得不可用或响应过慢,上游服务为了保证自己整体服务的可用性,不再继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。
服务熔断是框架级的处理,我们只需要实现对应接口就行。
- 最开始处于
closed
状态,一旦检测到错误达到一定阀值,便转为open
状态- 这时候会有个
reset timeout
,到了这个时间,会转移到half open
状态half open
状态尝试方形一部分请求到后端,一旦检测成功便回归到closed
状态,即恢复服务,否则继续open
状态
- 服务降级:当下游的服务因为某种原因响应过慢,下游服务主动停掉一些不太重要的业务,释放出服务器资源,增加响应速度;当下游的服务因为某种原因不可用,上游主动调用本地的一些降级逻辑,避免卡顿,迅速返回给用户。
乍看之下,很多人还是不懂熔断和降级的区别,其实应该要这么理解:
- 服务降级有很多种降级方式,如开关降级、限流降级、熔断降级
- 服务熔断属于降级方式的一种
举例说明开关降级:
做个开关,将开关放在配置中心,在配置中心更改开关,决定哪些服务进行降级。
8、微服务之间是如何独立通讯的?
- 远程调用(同步):RPC、REST API,比如Feign调用,直接通过远程来访问别的service
- 消息中间件(异步)
9、Eureka 和 Zookeeper 的区别?
- Zookeeper保证了CP(C:一致性,P:分区容错性),Eureka保证了AP(A:高可用,P:分区容错)
zookeeper 在选举期间注册服务瘫痪,虽然最终服务会恢复,但是选举期间是不可用的,而且选举时间太长(30~120s),在云部署环境下,因网络问题使得zk集群失去 master 节点是大概率事件,不能容忍。
Eureka 各个节点是平等关系,只要有一台 Eureka Server 就可以保证服务可用,但是查询到的数据并不是最新的(因为进入自我保护机制后,Eureka仍然能够接收新服务的注册和查询,但是不会同步到其他节点),所以Eureka 可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像 ZooKeeper 一样使得整个注册系统瘫痪。
在分布式领域有一个很著名的CAP定理:C:数据一致性。A:服务可用性。P:分区容错性(服务对网络分区故障的容错性)。
在分布式存储系统中,最多只能实现以上两点。而由于当前网络延迟故障会导致丢包等问题,所以我们分区容错性是必须实现的。也就是P肯定要有,我们只能在一致性和可用性中进行选择 ==>AP 或者 CP
- Zookeeper 采用过半数存活原则,Eureka 采用自我保护机制解决分区问题
- Eureka 本质是一个工程,而 ZooKeeper 只是一个进程