Spring Cloud 是一个基于 SpringBoot 实现的云原生应用开发工具,它为基于JVM的云原生应用开发中涉及的配置管理、服务发现、熔断器、智能路由、微代理、控制总线、分布式会话和集群状态管理等操作提供了一种简单的开发方式。
为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等。
1、复杂性高
整个项目包含的模块非常多、模块的边界模糊、依赖关系不清晰、代码质量参差不齐、混乱地堆砌在一起。使得整个项目非常复杂。每次修改代码都心惊胆战,甚至添加一个简单的功能,或者修改一个Bug都会带来隐含的缺陷。
2、技术债务
随着时间推移、需求变更和人员更迭,会逐渐形成应用程序的技术债务, 并且越积越多。“不坏不修(Not broker, don't fix"),这在软件开发中非常常见,在单体应用中这种思想更甚。已使用的系统设计或代码难以被修改,因为应用程序中的 其他模块可能会以意料之外的方式使用它。
3、部署频率低
随着代码的增多,构建和部署的时间也会增加。而在单体应用中,每次功能的变更或缺陷的修复都会导致需要重新部署整个应用。全量部署的方式耗时长、影响范围大、风险高,这使得单体应用项目上线部署的频率较低。而部署频率低又导致两次发布之间会有大量的功能变更和缺陷修复,出错概率比较高。
4、可靠性差
某个应用Bug,例如死循环、OOM等,可能会导致整个应用的崩溃。
5、扩展能力受限
单体应用只能作为一个整体进行扩展,无法根据业务模块的需要进行伸缩。例如:应用中有的模块是计算密集型的,它需要强劲的CPU;有的模块则是IO密集型的,需要更大的内存。由于这些模块部署在一起,不得不在硬件的选择上做出妥协。
6、阻碍技术创新
单体应用往往使用统一的技术平台或方案解决所有的问题,团队中的每个成员都必须使用相同的开发语言和框架,要想引人新框架或新技术平台会非常困难。例如:一个使用 Struts2 构建的、有100万行代码的单体应用,如果想要换用 Spring MVC,毫无疑问切换的成本是非常高的。
微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP API)这些服务围绕业务能力构建并且可通过全自动部署机制独立部置。这些服务共用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术。
架构特征
架构特点
我们使用 Spring Cloud Netflix 中的 Eureka 作为服务注册中心完成服务注册与发现;而服务间通过 Feign 和 Ribbon 实现服务的消费以及负载均衡;通过 Spring Cloud Config 实现了应用多环境的外部化配置以及版本管理。为了使得服务集群更为健壮,使用 Hystrix 的融断机制来避免在微服务架构中个别服务出现异常时引起的故障蔓延。
1、Eureka:服务治理组件
Eureka 是微服务架构中的注册中心,专门负责服务的注册与发现。
Eureka Client:是一个java客户端,用于简化与 Eureka Server 的交互,负责将这个服务的信息注册到 Eureka Server 中。
Eureka Server:注册中心,提供服务注册服务,各个节点启动后,会在 Eureka Server 中进行注册,这样 Eureka Server 中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
在应用启动后,通过 Eureka Client 向 Eureka Server 发送心跳,默认周期为30秒,如果 Eureka Server 在多个心跳周期内没有接收到某个节点的心跳,Eureka Server 将会从服务注册表中把这个服务节点移除(默认90秒),收到响应后,就可以发送请求过去调用相应的服务接口。
Eureka Server 之间通过复制的方式完成数据的同步,Eureka 还提供了客户端缓存机制,即使所有的 Eureka Server 都挂掉,客户端依然可以利用缓存中的信息消费其他服务的 API。综上,Eureka 通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。
Eureka 的高可用(Eureka集群):搭建 Eureka 集群非常简单,只要启动多个 Eureka Server 服务并且让这些 Server 端之间彼此进行注册即可实现。
打个比方:库存服务、仓储服务、积分服务中都有一个 Eureka Client 组件,这个组件专门负责将这个服务的信息注册到 Eureka Server 中。说白了,就是告诉 Eureka Server,自己在哪台机器上,监听着哪个端口。订单服务里也有一个 Eureka Client 组件,这个 Eureka Client 组件会找 Eureka Server 问一下:库存服务在哪台机器啊?监听着哪个端口啊?仓储服务呢?积分服务呢?然后就可以把这些相关信息从 Eureka Server 的注册表中拉取到自己的本地缓存中来。这时如果订单服务想要调用库存服务,不就可以找自己本地的 Eureka Client 问一下库存服务在哪台机器?监听哪个端口吗?收到响应后,紧接着就可以发送一个请求过去,调用库存服务扣减库存的那个接口!同理,如果订单服务要调用仓储服务、积分服务,也是如法炮制。
2、Ribbon:客户端负载均衡的服务调用组件
Ribbon 是 Netflix 发布的负载均衡器,它有助于控制 HTTP 和 TCP 客户端的行为。为 Ribbon 配置服务提供者地址列表后,Ribbon 就可基于某种负载均衡算法,自动地帮助服务消费者去请求。 Ribbon 默认为我们提供了很多的负载均衡算法,例如轮询、随机等。当然,我们也可为 Ribbon 实现自定义的负载均衡算法。
3、Hystrix:容错保护组件,实现了熔断器
是隔离、熔断以及降级的一个框架。
Hystrix 是由 Netflix 开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。 Hystrix 主要通过以下几点实现延迟和容错。
包裹请求:使用 Hystrixcommand(或 Hystrixobservablecommand)包裹对依赖的调用逻辑,每个命令在独立线程中执行。这使用到了设计模式中的“命令模式”。
跳闸机制:当某服务的错误率超过一定阈值时,Hystrix 可以自动或者手动跳闸,停止请求该服务一段时间。
资源隔离:Hystrix 为每个依赖都维护了一个小型的线程池(或者信号量)。如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。
监控:Hystrix 可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时以及被拒绝的请求等。
回退机制:当请求失败、超时、被拒绝或当断路器打开时执行回退逻辑,回退逻辑可由开发人员自行提供。
自我修复:断路器打开一段时间后,会自动进人“半开”状态。断路器打开、关闭、半开的逻辑转换。
打个比方:现在假设订单服务自己最多只有 100 个线程可以处理请求,然后呢,积分服务不幸的挂了,每次订单服务调用积分服务的时候,都会卡住几秒钟,然后抛出—个超时异常。然后就会导致别人请求订单服务的时候,发现订单服务也挂了,不响应任何请求了。现在很不幸,积分服务挂了,会咋样?当然会导致订单服务里那个用来调用积分服务的线程都卡死不能工作了啊!但由于订单服务调用库存服务、仓储服务的这两个线程池都是正常工作的,所以这两个服务不会受到任何影响。这个时候如果别人请求订单服务,订单服务还是可以正常调用库存服务扣减库存,调用仓储服务通知发货。只不过调用积分服务的时候,每次都会报错。但是如果积分服务都挂了,每次调用都要去卡住几秒钟干啥呢?有意义吗?当然没有!所以我们直接对积分服务熔断不就得了,比如在 5 分钟内请求积分服务直接就返回了,不要去走网络请求卡住几秒钟,这个过程,就是所谓的熔断!那人家又说,兄弟,积分服务挂了你就熔断,好歹你干点儿什么啊!别啥都不干就直接返回啊?没问题,咱们就来个降级:每次调用积分服务,你就在数据库里记录一条消息,说给某某用户增加了多少积分,因为积分服务挂了,导致没增加成功!这样等积分服务恢复了,你可以根据这些记录手工加一下积分。这个过程,就是所谓的降级。
4、Feign:声明式服务调用组件
Feign是 Netflix 开发的声明式、模板化的HTTP客户端,其灵感来自 Retrofit、JAXRS-20 以及 Websocket.Feign 可帮助我们更加便捷、优雅地调用 HTTP API。
在 Spring Cloud 中,使用 Feign 非常简单一创建一个接口,并在接口上添加一些注解,,代码就完成了。Feign 支持多种注解,例如 Feign 自带的注解或者 JAX-RS 注解等。
Spring Cloud 对 Feign 进行了增强,使 Feign 支持了 Spring MVC 注解,并整合了 Ribbon 和 Eureka,从而让 Feign 的使用更加方便。
Feign Client 会在底层根据你的注解,跟你指定的服务建立连接、构造请求、发起请求、获取响应、解析响应,等等。
对某个接口定义了 @FeignClient 注解,Feign 就会针对这个接口创建一个动态代理。
接着你要是调用那个接口,本质就是会调用 Feign 创建的动态代理,这是核心中的核心。
Feign 的动态代理会根据你在接口上的 @RequestMapping 等注解,来动态构造出你要请求的服务的地址。
针对这个地址,发起请求、解析响应。
5、Zuul:服务网关组件,提供智能路由、访问过滤等功能
微服务网关。这个组件是负责网络路由的。客户端请求微服务时,先经过 Zuul 之后再请求,这样就可以将一些类似于校验的业务逻辑放到 Zuul 中完成。而微服务自身只需要关注自己的业务逻辑即可。当然在 Zuul 上层也可以搭建 Nginx、F5
等负载均衡设施。
服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供 REST API 的过程中,除了具备服务路由、负载均衡功能之外,它还具备了权限控制等功能。Spring Cloud Netflix 中的 Zuul 就担任了这样的一个角色,为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。
Zuul 是 Netflix 开源的微服务网关,它可以和 Eureka、 Ribbon、 Hystrix 等组件配合使用 Zuul 的核心是一系列的过滤器,这些过滤器可以完成以下功能。
身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求。
审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
动态路由:动态地将请求路由到不同的后端集群。
压力测试:逐渐增加指向集群的流量,以了解性能。
负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。
静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群。
多区域弹性:跨越 AWS Region 进行请求路由,旨在实现 ELB( Elastic_ Load Balancing)使用的多样化,以及让系统的边缘更贴近系统的使用者。
Spring Cloud 对 Zuul 进行了整合与增强。目前,Zuul 使用的默认 HTTP 客户端是 Apache HTTP Client,也可以使用 Restclient 或者 okhttp3.Okhttpcliento 如果想要使用 Restclient,可以设置 ribbon.restclientenabled=true 想要使用 okhttp3.okhttpclient,可以设置 rib bon.okhttp.enabled=true。
打个比方:假设你后台部署了几百个服务,现在有个前端兄弟,人家请求是直接从浏览器那儿发过来的。人家要请求一下库存服务,你难道还让人家记着这服务的名字叫做 inventory-service?部署在 5 台机器上?就算人家肯记住这一个,你后台可有几百个服务的名称和地址呢?难不成人家请求一个,就得记住一个?所以一般微服务架构中都必然会设计一个网关在里面。像 Android、iOS、PC 前端、微信小程序、H5 等等,不用去关心后端有几百个服务,就知道有一个网关,所有请求都往网关走,网关会根据请求中的一些特征,将请求转发给后端的各个服务。而且有一个网关之后,还有很多好处,比如可以做统一的降级、限流、认证授权、安全,等等。
6、Spring Cloud Config:分布式配置中心
Spring Cloud Config 为分布式系统外部化配置提供了服务器端和客户端的支持,它包 括 Config Server 和 Config Client 两部分。由于 Config Server 和 Config Client 都实现了对 Spring Environment 和 Propertysource 抽象的映射,因此,Spring Cloud Config 非常适合 Spring 应用程序,当然也可与任何其他语言编写的应用程序配合使用。
Config Server 是一个可横向扩展、集中式的配置服务器,它用于集中管理应用程序各个环境下的配置,默认使用 Git 存储配置文件内容,也可以使用 SVN 存储,或者是本地文件存储。
Config Client 是 Config Server 的客户端,用于操作存储在 Config Server 中的配置内容。微服务在启动时会请求 Config Server 获取配置文件的内容,请求到后再启动容器。
总结
以上就是我们通过一个电商业务场景,阐述了 Spring Cloud 微服务架构几个核心组件的底层原理。
常见面试题总结
1、Spring Cloud 和 Dubbo有哪些区別?
Dubbo 由于是二进制的传输,占用带宽会更少。但是开发难度较大,原因是dubbo的jar包依赖问题很多大型工程无法解决。
Spring Cloud 是http协议传输,带宽会比较多,同时使用http协议一般会使用JSON报文,消耗会更大。但是接口协议约定比较自由且松散,需要有强有力的行政措施来限制接口无序升级
本质区别: Dubbo 是基于 RPC 远程过程调用,Spring Cloud 是基于 http rest api 调用。
从系统结构简易程序:Spring Cloud 的系统结构更简单、“注册 + SpringMVC = Spring Cloud”,而 Dubbo 各种复杂的 Url,protocol,register,invocation,dubbofilter,dubboSPI,dubbo序列化..........炫技的成分更多一些。
从性能:Dubbo 的网络消耗小于 Spring Cloud,但是在国内95%的公司内,网络消耗不是什么太大问题,如果真的成了问题,通过压缩、二进制、高速缓存、分段降级等方法,很容易解。
从开发难易度:Dubbo 的神坑是jar包依赖,开发阶段难度极大,Spring Cloud 比较自由。
从后续改进:Dubbo 的改进是通过 dubbofilter,很多东西没有,需要自己继承,如监控,如日志,如限流,如追踪。Spring Cloud 自己带了很多监控、限流措施,但是功能可能和欧美习惯相同,国内需要进行适当改造,但更简单,就是 ServletFilter 而已,但是总归比 Dubbo 多一些东西是好的。
Dubbo 实践通常以 ZooKeeper 为注册中心(Dubbo 原生支持的Redis 方案需要服务器时间同步,且性能消耗过大)。针对分布式领域著名的CAP理论(C——数据一致性,A——服务可用性,P——服务对网络分区故障的容错性),Zookeeper 保证的是CP ,但对于服务发现而言,可用性比数据一致性更加重要 ,而 Eureka 设计则遵循AP原则 。
严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避兔了上面提到的原生 RPC 带来的问题。而且 REST 相比 RPC 更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更加合适。
2、SpringBoot 和 Spring Cloud,请你谈谈对他们的理解?
SpringBoot 是一个快速整合第三方框架,关注的是微观具体关注快速方便的开发单个个体的服务
Spring Cloud 关注的是宏观具体关注全局的微服务协调整理治理框架将 SpringBoot 开发的一个个单体服务整合并管理起来
它为各个微服务之间提供 配置管理 服务发现 断路器路由 微代理 全局锁 分布式会话 等集成服务
举个例子:一所医院 SpringBoot 是一个一个科室 Spring Cloud 是把一个一个科室组合起来对外称之为医院
存在依赖关系 Spring Cloud 离不开 SpringBoot。
3、什么是服务熔断?
服务熔断 是指由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,从而采用的一种保护措施,所以很多地方把熔断亦称为过载保护。
4、什么是服务降级 微服务的优缺点分別是什么?
整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来。
5、说下你在项目开发中碰到的坑你所知道的微服务技术栈有哪些?
微服务技术栈:多种技术的结合体
我们在讨论分布式的微服务架构的时候它需要有哪些维度?服务治理、服务注册、服务调用、负载均衡、服务监控
这五点称为落地维度,为什么叫落地呢 ?天上飞的理念肯定要有落地的实现,也就是说分布式微服务架构当作天上飞的理念
落地的实现可以总结为:
6、请说说Eureka和 Zookeeper,两个的区別?
1)、Zookeeper 遵守 CP
当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。
也就是说,服务注册功能对一致性的要求要高于可用性。但是 Zookeeper 会出现这样一种情况,当 master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行 leader 选举。问题在于,选举 leader的时间太长(30~120s)目选举期间整个Zookeeper 集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得 Zookeeper 集群失去 master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。 或许这个回答太过于抽象用一种其他说法来说就是:当有一个 Zookeeper 挂了那其他的 Zookeeper 会进行一次选举(强一致性:我一定要保持数据一致性) 而在此选举期间 Zookeeper 是不可用的而当前有用户正在使用用户就不爽了。
2)、Eureka遵守 AP
在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而 Eureka的客户端在向某个 Eureka注册或时如果发现连接失败,则会自动切换至其它节点 只要有一台 Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的不保证强一致性。
除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么 Eureka 就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
因此,Eureka 可以很好的应对因网络故障导致部分节点失去联系的情況,而不会像 Zookeeper 那样使整个注册服务瘫痪。