[Java EE]Spring Boot 与 Spring Cloud的关系/过去-现在-未来

1 微服务架构

定义

  • 微服务 (Microservices) 是一种软件架构风格
  • 它是以专注于单一责任功能的小型功能区块 (Small Building Blocks) 为基础,
  • 利用模块化的方式组合出复杂的大型应用程序,
  • 各功能区块使用与语言无关 (Language-Independent/Language agnostic) 的 API 集相互通信。

目前业界跟微服务相关的开发平台和框架更是不胜枚举:Spring CloudService FabricLinkerdEnvoyIstio ...

单体应用架构 => 微服务应用架构

从【单体应用】向【微服务架构】的转型,已成为企业数字化转型的主流趋势。

在微服务模式下,企业内部服务少则几个到几十个,多则上百个,每个服务一般都以集群方式部署。

微服务架构的问题?

分布式架构的4个核心问题?
1 这么多服务,客户端如何访问? - 客户端访问 => API网关
2 这么多服务,服务(端)之间如何通信? - 服务端通信 => HTTP/RPC调用
3 这么多服务,如何治理? - 微服务治理 => 服务注册/发现
4 服务挂了,该怎么办? - 容灾 => 熔断机制

微服务的特征

2 总体解决方案

2-0 Spring Cloud

0 Spring Cloud 是一套生态,就是来解决上述分布式架构的问题的。

1 Spring Cloud的生态中存在众多的解决方案/子框架
Spring Cloud 是一系列框架的有序集合。它利用SpringBoot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等,都可以用SpringBoot的开发风格做到一键启动和部署。
	例如:
		Spring Cloud Netflix
		[ Apache Dubbo Zookeeper ]
		Spring Cloud Alibaba
		...

2 想使用Spring Cloud,必须掌握Spring Boot,因为Spring Cloud是基于/依赖于 Spring Boot
	=> 随着新功能的加入,Spring变得越来越复杂。无论何时启动新项目,都必须添加新的构建路径或Maven依赖项。简而言之,你需要从头开始做每件事。SpringBoot是一种帮助您避免所有代码配置的解决方案。
	=> Spring boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring boot

3 Spring Cloud 并没有重复制造轮子,它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

PS: 如果某不知名团队X,基于上述4个核心问题开发一套解决方案,也叫 Spring Cloud!

  • Spring Boot 与 Spring Cloud的关系?

    Spring Cloud 基于/依赖于 Spring Boot

    Spring Cloud 包含:

    • 微服务(Spring Boot) /
    • API网关: API Gateway /
    • 服务注册/发现 : Service Registry Center / Config Server /
    • 通信调用
    • 熔断机制
    • ...

Spring Boot - Build Anything

Spring Cloud - Coordinate(协调) Anything

Spring Cloud Data Flow - Connect Everything

2-0-2 Spring Cloud和SpringBoot版本对应关系

Spring Cloud Version Spring Boot Version
Hoxton 2.2.X
Greenwich 2.1.X
Finchley 2.0.X
Edgware 1.5.X
Dalston

2-1 Spring Cloud Netflix

NetFlix: 出来了一套解决方案——Spring Cloud Netflix! 
  • API网关 - zuul组件 (NetFlix开源)

  • 网络通信/HTTP调用 - Feign (NetFlix开源)

    Feign --> 基于 HTTPClient --> HTTP的通信方式 [同步且阻塞]

  • 服务注册/发现 - Eureka (NetFlix开源)

  • 熔断机制 - Hystrix (NetFlix开源)

Hystrix [hɪst'rɪks],译为 豪猪(因其背上长满棘刺,从而拥有了自我保护的能力)

Hystrix是Netflix开源的一款容错框架,同样具有自我保护能力。

2018年底,NetFlix宣布无限期停止维护。

开源软件不再维护,就会脱节,乃至被社区和生态弃用? 下一步怎么走?

2-2 Apache Dubbo Zookeeper

Alibaba: 出来了一套解决方案——Apache Dubbo Zookeeper!

Alibaba开源的, 一款基于Java的、高性能的RPC通信框架

http://dubbo.apache.org/zh-cn/ / https://zookeeper.apache.org/

  • API网关 -

需使用第三方组件 或 自己实现

  • 网络通信/RPC调用 - Dubbo (Alibaba开源)
  • 服务注册/发现 - Zookeeper

Zookeeper: 动物园管理者 (Hadoop / Hive / ...)

  • 熔断机制 - Hystrix (NetFlix开源)

继续 借用 Hystrix

2-3 Spring Cloud Alibaba

https://spring.io/projects/spring-cloud-alibaba

简述

Alibaba: 又出来了一套解决方案——Spring Cloud Alibaba

Spring Cloud Alibaba 提供分布式应用开发的一站式解决方案。它包含开发分布式应用程序所需的所有组件,使您可以轻松地使用 Spring Cloud 开发应用程序。
使用 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,即可将 Spring Cloud 应用连接到阿里巴巴的分布式解决方案,并通过阿里巴巴中间件构建分布式应用系统。

特征

  • Spring Cloud

    • 流量控制和服务降级: Alibaba Sentinel的流量控制、断路和系统自适应保护
    • 服务注册与发现:实例可以注册到阿里巴巴的 Nacos,客户端可以通过 Spring 管理的 bean 发现实例。通过 Spring Cloud Netflix 支持客户端负载均衡器 Ribbon
    • 分布式配置:使用阿里巴巴Nacos作为数据存储
    • 事件驱动:构建与Spring Cloud Stream RocketMQ Binder连接的高度可扩展的事件驱动微服务
    • Message Bus : 用 Spring Cloud Bus RocketMQ 链接分布式系统的节点
    • Distributed Transaction :支持Seata高性能、易用的分布式事务解决方案
    • Dubbo RPC :通过Apache Dubbo RPC扩展Spring Cloud service-to-service调用的通信协议
  • Spring Boot

    • 所有的 Spring Boot Starter 都在阿里云 Spring Boot Project中维护。
    • 阿里云对象存储服务Spring Boot Starter
    • 阿里云短信服务Spring Boot Starter
    • 阿里云 Redis的 Spring Boot Starter
    • 阿里云RDS MySQL的Spring Boot Starter
    • 阿里云 SchedulerX的 Spring Boot Starter

...

2-4 Future: 服务网格——Service Mesh

目前,又提出了一种解决方案————服务网格(下一代微服务标准, Service Mesh)
	代表性的具体解决方案: Istio (未来,可能需要掌握)

Service Mesh 是微服务时代的 TCP/IP 协议。

3 小结: Spring Cloud

万变不离其宗,一通百通!

网关(流量网关)

解决方案1: Nginx 【推荐】

网关(API网关) - 服务路由(客户端访问)

参考文献

问题背景

不同的微服务一般会有不同的网络地址,客户端在访问这些微服务时必须记住几十甚至几百个地址,这对于客户端方来说太复杂也难以维护。如下图:

如果让客户端直接与各个微服务通讯,可能会有很多问题:

  • 1.客户端会请求多个不同的服务,需要维护不同的请求地址,增加【开发/维护难度】
  • 2.在某些场景下存在【跨域请求】的问题
  • 3.加大【身份认证】的难度,每个微服务需要【独立认证】

因此,我们需要一个微服务网关,介于客户端与服务器之间的中间层,所有的外部请求都会先经过微服务网关。客户端只需要与网关交互,只知道一个网关地址即可,这样简化了开发还有以下优点:

  • 1、易于【监控】
  • 2、易于【认证】
  • 3、减少了客户端与各个微服务之间的交互复杂度和次数

定义: 什么是微服务网关?

  • API网关是一个服务器,是系统对外的唯一入口。
  • API网关封装了系统内部架构,为每个客户端提供一个定制的API。
  • API网关方式的核心要点是:
所有的客户端和消费端都通过【统一的网关接入微服务】,在网关层处理所有的【非业务功能】.
通常,网关也是提供REST/HTTP的访问API。服务端通过【API-GW注册】和【管理服务】。

主要功能

微服务网关作为微服务后端服务的统一入口,它可以统筹管理后端服务,主要分为数据平面和控制平面:

  • 数据平面主要功能是接入用户的HTTP请求和微服务被拆分后的聚合。使用微服务网关统一对外暴露后端服务的API和契约,路由和过滤功能正是网关的核心能力模块。另外,微服务网关可以实现拦截机制和专注跨横切面的功能,包括协议转换、安全认证、熔断限流、灰度发布、日志管理、流量监控等。

  • 控制平面主要功能是对后端服务做统一的管控和配置管理。例如,可以控制网关的弹性伸缩;可以统一下发配置;可以对网关服务添加标签;可以在微服务网关上通过配置Swagger功能统一将后端服务的API契约暴露给使用方,完成文档服务,提高工作效率和降低沟通成本。

作用/应用场景

网关具有的职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。
当然,最主要的职责还是与“外界联系”。

  • 路由功能:路由是微服务网关的核心能力。通过路由功能微服务网关可以将请求转发到目标微服务。在微服务架构中,网关可以结合注册中心的动态服务发现,实现对后端服务的发现,调用方只需要知道网关对外暴露的服务API就可以透明地访问后端微服务。

  • 负载均衡:API网关结合负载均衡技术,利用Eureka或者Consul等服务发现工具,通过轮询、指定权重、IP地址哈希等机制实现下游服务的负载均衡。

  • 统一鉴权:一般而言,无论对内网还是外网的接口都需要做用户身份认证,而用户认证在一些规模较大的系统中都会采用统一的单点登录(Single Sign On)系统,如果每个微服务都要对接单点登录系统,那么显然比较浪费资源且开发效率低。API网关是统一管理安全性的绝佳场所,可以将认证的部分抽取到网关层,微服务系统无须关注认证的逻辑,只关注自身业务即可。

  • 协议转换:API网关的一大作用在于构建异构系统,API网关作为单一入口,通过协议转换整合后台基于REST、AMQP、Dubbo等不同风格和实现技术的微服务,面向Web Mobile、开放平台等特定客户端提供统一服务。

  • 指标监控:网关可以统计后端服务的请求次数,并且可以实时地更新当前的流量健康状态,可以对URL粒度的服务进行延迟统计,也可以使用Hystrix Dashboard查看后端服务的流量状态及是否有熔断发生。

  • 限流熔断:在某些场景下需要控制客户端的访问次数和访问频率,一些高并发系统有时还会有限流的需求。在网关上可以配置一个阈值,当请求数超过阈值时就直接返回错误而不继续访问后台服务。当出现流量洪峰或者后端服务出现延迟或故障时,网关能够主动进行熔断,保护后端服务,并保持前端用户体验良好。

  • 黑白名单:微服务网关可以使用系统黑名单,过滤HTTP请求特征,拦截异常客户端的请求,例如DDoS攻击等侵蚀带宽或资源迫使服务中断等行为,可以在网关层面进行拦截过滤。比较常见的拦截策略是根据IP地址增加黑名单。在存在鉴权管理的路由服务中可以通过设置白名单跳过鉴权管理而直接访问后端服务资源。

  • 灰度发布:微服务网关可以根据HTTP请求中的特殊标记和后端服务列表元数据标识进行流量控制,实现在用户无感知的情况下完成灰度发布。

  • 流量染色:和灰度发布的原理相似,网关可以根据HTTP请求的Host、Head、Agent等标识对请求进行染色,有了网关的流量染色功能,我们可以对服务后续的调用链路进行跟踪,对服务延迟及服务运行状况进行进一步的链路分析。

  • 文档中心:网关结合Swagger,可以将后端的微服务暴露给网关,网关作为统一的入口给接口的使用方提供查看后端服务的API规范,不需要知道每一个后端微服务的Swagger地址,这样网关起到了对后端API聚合的效果。

  • 日志审计:微服务网关可以作为统一的日志记录和收集器,对服务URL粒度的日志请求信息和响应信息进行拦截。

解决方案1: Tyk

解决方案2: Kong(基于Nginx+Lua)

github: https://github.com/traefik/traefik

特点: 基于Nginx+Lua开发,性能高,稳定,有多个可用的插件(限流、鉴权等等)可以开箱即用。

不足:只支持Http协议;二次开发,自由扩展困难;提供管理API,缺乏更易用的管控、配置方式。

解决方案3: Orange

解决方案4: Netflix zuul 【推荐】

特点: Netflix开源,功能丰富,使用JAVA开发,易于二次开发;需要运行在web容器中,如 Tomcat。

不足:缺乏管控,无法动态配置;依赖组件较多;处理Http请求依赖的是Web容器,性能不如 Nginx;
Zuul 1.0 : Netflix开源的网关,使用Java开发,基于Servlet架构构建,便于二次开发。因为基于Servlet内部延迟严重,并发场景不友好,一个线程只能处理一次连接请求。

Zuul 2.0 : 采用Netty实现异步非阻塞编程模型,一个CPU一个线程,能够处理所有的请求和响应,请求响应的生命周期通过事件和回调进行处理,减少线程数量,开销较小

解决方案4: apiaxle

解决方案5: api-umbrella

解决方案6: Traefik

特点: Go语言开发;轻量易用;提供大多数的功能:服务路由,负载均衡等等;提供 WebUI

不足:二进制文件部署,二次开发难度大;UI更多的是监控,缺乏配置、管理能力;

解决方案6: Spring Cloud Gateway 【推荐】

Spring Cloud的一个全新的API网关项目,替换Zuul开发的网关服务

基于Spring5.0 + SpringBoot2.0 + WebFlux(基于性能的Reactor模式响应式通信框架Netty,异步阻塞模型)等技术开发,性能高于Zuul

解决方案6: Nginx

特点: 使用Nginx的【反向代理】和【负载均衡】,可实现对api服务器的【负载均衡】及【高可用】
不足:自注册的问题和网关本身的扩展性

解决方案6: Envoy

envoy 是作为微服务服务架构中以独立进程方式实现高级网络功能的,轻量级的7层服务代理程序,通常以sidecar的方式运行在应用程序的周边,也可以作为网络的边缘代理来运行

envoy 的特性 进程外体系结构 ,L3/L4过滤器体系结构,HTTP L7过滤器体系结构, 一流的HTTP/2支持, HTTP/3支持(目前为alpha),HTTP L7路由,gRPC支持,服务发现和动态配置,健康检查,高级负载平衡,前端/边缘代理支持, 一流的可观察性

小结

2022.7.12

API 网关方案 发起方 社区活跃度(github star数) 编程语言 优点 缺点
spring-cloud-gateway(2016) spring cloud 3.6K Java 异步、配置灵活方便、性能优于zuul(因zuul老是跳票而另起炉灶) 晚期产品
zuul(2012) Netflix 12K Java 成熟、简略/门槛低 (...)
nginx(2004) Nginx Inc 16.7K C/Lua 高性能、成熟稳固 门槛高、偏运维、可编程弱
Envoy(2006) Lyft 20K C++ 高性能、可编程、API/ServiceMesh集成 门槛较高
Kong(2004) Kong Inc 32.4K OpenResty/Lua 高性能、可编程 API 门槛较高
Traefik(2015) Containous 38.8K Golang 云原生、可编程 API、对接各种服务发现 生产案例不多

负载均衡

  • 负载均衡的解决方案种类
  • 服务端负载均衡:可细分为硬件负载均衡(如:F5)、软件负载均衡(如:Nginx)

【服务端负载均衡】维护一个可用的服务端清单,通过心跳检测来剔除故障的服务端节点,保证清单中都是可正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(轮询、加权等)从维护的可用服务端清单中取出一台服务端端地址,然后进行转发。

  • 客户端负载均衡:(如:Ribbon)

【客户端负载均衡】和服务端负载均衡最大的不同点在于服务清单所存储的位置。在客户端负载均衡中,所有客户端节点都维护着自己要访问的服务端清单,而这些服务端端清单来自于服务注册中心。

解决方案1: Nginx(服务端负载均衡) 【推荐】

解决方案2: Ribbon (客户端负载均衡解决方案) 【推荐】

  • Ribbon实现客户端的负载均衡,负载均衡器提供很多对http和tcp的行为控制。

微服务环境中,常常同一个服务有N多实例,我们不希望所有调用都涌向1个实例,这个时候就要用到负载均衡。

  • 客户端负载均衡,即是当浏览器向业务后台服务发出请求时,
  • 业务后台服务的负载均衡客户端(如:Ribbon)会向 服务注册与发现中心(如: Eureka Server) 读取注册到服务器的可用服务信息列表
  • 然后,根据设定的负载均衡策略(没有设置即用默认的),抉择出向哪台服务器发送请求。

  • 主要包含如下组件:
  • IRule:根据特定算法中从服务列表中选取一个要访问的服务
  • IPing:在后台运行的一个组件,用于检查服务列表是否都活
  • ServerList:存储服务列表。分为静态和动态。如果是动态的,后台有个线程会定时刷新和过滤服务列表;
  • ServerListFilter:DynamicServerListLoadBalancer用于过滤从ServerList实现返回的服务器的组件
  • ServerListUpdater:被DynamicServerListLoadBalancer用于动态的更新服务列表
  • IClientConfig:定义各种配置信息,用来初始化ribbon客户端和负载均衡器
  • ILoadBalancer:定义软件负载平衡器操作的接口。动态更新一组服务列表及根据指定算法从现有服务器列表中选择一个服务
  • 作用
  • 服务器发现
  • 选择服务器操作
  • 获取所有的服务器列表------不再硬编码服务的地址
  • 服务监听
  • Ribbon是一个为客户端提供负载均衡功能的服务,它内部提供了一个叫做ILoadBalance的接口代表负载均衡器的操作。

我们可以在配置文件中Load Balancer后面的所有机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。

  • 负载均衡的策略(Ribbon)
内置负载均衡规则类&规则描述

1、RoundRobinRule: 
    简单轮询服务列表来选择服务器,它是Ribbon默认的负载均衡策略

2、AvailabilityFilterRule
    对以下两种服务器进行忽略:
    (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态,短路状态将持续30秒,如果再次连接失败,短路持续时间就会几何级地增加。
    (2)并发数过高的服务器,如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的ActiveConnectionsLimit进行配置。

3、WeightedResponseTimeRule 
    为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重会影响服务器的选择。 

4、ZoneAvoidanceRule
    以区域可用的服务器为基础进行服务器的选择,使用Zone对服务器进行分类,这个Zone可用理解为一个机房,一个机架等。而后再对Zone内对多个服务做轮询。

5、BestAvailableRule 
    忽略那些短路等服务器,并选择并发数较低的服务器

6、RandomRule 
    随机选择一个可用的服务器

7、RetryRule 
    重试机制的选择逻辑
  • spring-cloud的组件集成

只需要使用@LoadBalance注解和其他配置(暂不细讲),不同实例可以通过调节权重来改变调用的优先级。(spring.cloud.nacos.discovery.weight=浮点数)
一般地,Spring cloud Feign已经集成Ribbon。所以,注解@FeignClient的类,默认实现了ribbon的功能。

  • [1] ErukaNacosRibbon 提供 服务发现地址信息
  • [2] ribbonRestTemplate, Feign 等服务调用框架提供客户端负载均衡解决方案

  • spring-cloud 中启用spring-cloud-ribbon
  • [1] Spring Cloud Ribbon是一个基于HTTPTCP客户端负载均衡工具,它基于Netflix Ribbon实现,通过Spring Cloud Ribbon的封装,在微服务架构中使用客户端负载均衡调用非常简单。Ribbon是Spring Cloud整个大家庭中相对而言比较复杂的模块,直接影响到服务调度的质量和性能。
  • [2] 启用 ribbon 作为 loadbalancer
spring:
  cloud:
    loadbalancer:
      ribbon: # 使用 ReactiveLoadBalancerClient 时通过本参数禁用调 ribbon
        enabled: true
  • [3] 支持基于ribbon重试

application-common.yml中添加如下配置:

# 设置服务名称  会在Eureka中显示 而且其他方也要用的
spring:
  cloud:
    loadbalancer:
      retry:
        enabled: true # 开启Spring Cloud 的重试功能

# 服务异常重试配置
ribbon:
  ConnectTimeout: 1000 # Ribbon的连接超时时间
  ReadTimeout: 5000 # Ribbon的数据读取超时时间
  OkToRetryOnAllOperations: true  #默认只对GET请求重试, 当设置为true时, 对POST等所有类型请求都重试
  MaxAutoRetriesNextServer: 1 # 最大重试次数
  MaxAutoRetries: 2 # 切换实例的重试次数
  ServerListRefreshInterval: 2000  #Ribbon更新服务注册列表的频率
  • [4] maven 依赖 (eruka + ribbon)
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
 
//--------------springcloud-H 版引入 eureka-client 自带ribbon-----------------------//
 <!-- eureka client -->
  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

解决方案2: Spring Cloud LoadBlancder(客户端负载均衡解决方案) 【推荐】

  • Spring Cloud 生态 对 Ribbon 的 替换方案————Spring Cloud LoadBlancder(亲儿子)

注册中心 - 服务注册/发现(微服务治理、高可用)

解决方案1: Nacos 【推荐】

Nacos

解决方案2: Eureka

解决方案3: Zookeeper

解决方案4: consul

HTTP/RPC框架(同步/异步 | 阻塞/非阻塞) - 服务通信/调用(服务端通信)

若项目涉及多个语言平台之间的相互调用,就应该选择跨语言平台的 RPC 框架。

解决方案(RPC调用框架)A1: Dubbo(Alibaba/Java)

解决方案(RPC调用框架)A2: gRPC(Google/支持多语言)

解决方案(RPC调用框架)A3: Thrift (Facebook/支持多语言)

解决方案(RPC调用框架)A4: Tars(Tencent/C++)

解决方案(HTTP调用框架)B1: Feign(from NetFlix)

注:
RestFul API规范
底层网络通信框架: Netty / ...

服务容灾与监控(解决服务雪崩后怎么办?)

  • 微服务中的雪崩效应
  • 当山坡积雪内部的内聚力抗拒不了它所受到的重力拉引时,便向下滑动,引起大量雪体崩塌,人们把这种自然现象称作雪崩。
  • 微服务中,一个请求可能需要多个微服务接口才能实现,会形成复杂的调用链路。
  • 服务雪崩效应:是一种因“服务提供者的不可用”(原因)导致“服务调用者不可用”(结果),并将不可用逐渐放大的现象。

  • 扇入:代表着该微服务被调用的次数,扇入大,说明该模块复用性好
  • 扇出:该微服务调用其他微服务的个数,扇出大,说明业务逻辑复杂
  • 扇入大是一个好事,扇出大不一定是好事

在微服务架构中,一个应用可能会有多个微服务组成,微服务之间的数据交互通过远程过程调用完成。

这就带来一个问题:假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。
如图中所示,最下游商品微服务响应时间过长,大量请求阻塞,大量线程不会释放,会导致服务器资源耗尽,最终导致上游服务甚至整个系统瘫痪。

  • 微服务雪崩效应的【形成原因】

服务雪崩的过程可以分为3个阶段:

  • 服务提供者不可用
  • 重试加大请求流量
  • 服务调用者不可用

服务雪崩的每个阶段都可能由不同的原因造成:

  • 雪崩效应的【解决方案】

可从可用性可靠性着想,为防止系统的整体缓慢,甚至崩溃,采用的技术手段:

  • 服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制。
我们在各种场景下都会接触到熔断这两个字:
  高压电路中,如果某个地方的电压过高,熔断器就会熔断,对电路进行保护。
  股票交易中,如果股票指数过高,也会采用熔断机制,暂停股票的交易。

同样,在微服务架构中,熔断机制也是起着类似的作用: 
  当扇出链路的某个微服务不可用或者响应时间太长时,熔断该节点微服务的调用,进行服务的降级,快速返回错误的响应信息。
  当检测到该节点微服务调用响应正常后,恢复调用链路。

注意:
  1)服务熔断重点在“断”,切断对下游服务的调用
  2)服务熔断和服务降级往往是一起使用的,Hystrix就是这样
  • 服务降级

通俗讲就是整体资源不够用了,先将一些不关紧的服务停掉(调用我的时候,给你返回一个预留的值,也叫做兜底数据),待渡过难关高峰过去,再把那些服务打开。
服务降级一般是从整体考虑,就是当某个服务熔断之后,服务器将不再被调用,此刻客户端可以自己准备一个本地的fallback回调,返回一个缺省值。这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强。

  • 服务限流

服务降级是当服务出问题或者影响到核心流程的性能时,暂时将服务屏蔽掉,待高峰或者问题解决后再打开;
但是有些场景并不能用服务降级来解决,比如:秒杀业务这样的核心功能,这个时候可以结合服务限流来限制这些场景的并发/请求量
限流措施也很多,比如

  • 限制总并发数(比如数据库连接池、线程池)
  • 限制瞬时并发数(如nginx限制瞬时并发连接数)
  • 限制时间窗口内的平均速率(如Guava的RateLimiter、nginx的limit_req模块,限制每秒的平均速率)
  • 限制远程接口调用速率限制MQ的消费速率

[容灾]熔断/降级机制:Hystrix

  • 参考与推荐文献
  • 定义

Hystrix(豪猪),宣言“defend your application”是由Netflix开源的一个延迟容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性容错性

  • Hystrix 延迟/容错的实现措施

Hystrix主要通过以下几点实现延迟和容错。

  • 包裹请求:使用HystrixCommand包裹对依赖的调用逻辑。 页面静态化微服务方法(@HystrixCommand 添加Hystrix控制)
  • 跳闸机制:当某服务的错误率超过一定的阈值时,Hystrix可以跳闸,停止请求该服务一段时间。
  • 资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(舱壁模式)。如果该线程池已满, 发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。
  • 监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝 的请求等。
  • 回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑由开发人员 自行提供,例如返回一个缺省值。
  • 自我修复:断路器打开一段时间后,会自动进入“半开”状态(探测服务是否可用,如还是不可用,再次退回打开状态)。
  • 作用
  【1】Hystrix是Spring Cloud的组件之一,Hystrix 可以让我们在分布式系统中对服务间的调用进行控制加入一些调用延迟或者依赖故障的容错机制。

  【2】Hystrix 通过将依赖服务进行资源隔离进而阻止某个依赖服务出现故障时在整个系统所有的依赖服务调用中进行蔓延;【防止服务雪崩】

  【3】其核心功能:
  1)服务隔离(服务限流)
    通过线程池或者信号量判断是否已满,超出容量的请求直接降级,以达到限流的作用。

  2)服务熔断
    当失败率达到阈值自动触发降级,熔断器触发的快速失败会有助于系统防止崩溃。【可以说熔断是特定条件的降级】

  3)服务降级
    服务降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
  • 2 快速使用

step1 引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

step2 启动类开启hystrix功能

@SpringBootApplication
//注册到eureka
@EnableEurekaClient
//开启断路器功能
@EnableCircuitBreaker
public class WebApplication {
    ...
}

step3 注解@HystrixCommand参数分析

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HystrixCommand {
    // HystrixCommand 命令所属的组的名称:默认注解方法类的名称
    String groupKey() default "";
    // HystrixCommand 命令的key值,默认值为注解方法的名称
    String commandKey() default "";
    // 线程池名称,默认定义为groupKey
    String threadPoolKey() default "";
    // 定义回退方法的名称, 此方法必须和hystrix的执行方法在相同类中
    String fallbackMethod() default "";
    // 配置hystrix命令的参数
    HystrixProperty[] commandProperties() default {};
    // 配置hystrix依赖的线程池的参数
    HystrixProperty[] threadPoolProperties() default {};
    // 如果hystrix方法抛出的异常包括RUNTIME_EXCEPTION,则会被封装HystrixRuntimeException异常。我们也可以通过此方法定义哪些需要忽略的异常
    Class<? extends Throwable>[] ignoreExceptions() default {};
    // 定义执行hystrix observable的命令的模式,类型详细见ObservableExecutionMode
    ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER;
    // 如果hystrix方法抛出的异常包括RUNTIME_EXCEPTION,则会被封装HystrixRuntimeException异常。此方法定义需要抛出的异常
    HystrixException[] raiseHystrixExceptions() default {};
    // 定义回调方法:但是defaultFallback不能传入参数,返回参数和hystrix的命令兼容
    String defaultFallback() default "";
}

step4 使用示例

//线程池隔离的设置,线程池隔离与信号量隔离的最大区别在于发送请求的线程,信号量是采用调用方法的线程,而线程池则是用池内的线程去发送请求
@HystrixCommand(
        groupKey="test-provider",
        threadPoolKey="test-provider",
        threadPoolProperties = {
                @HystrixProperty(name = "coreSize", value = "20"),//线程池大小
                @HystrixProperty(name = "maximumSize", value = "30"),//最大线程池大小
                @HystrixProperty(name = "maxQueueSize", value = "20"),//最大队列长度
                @HystrixProperty(name =  "keepAliveTimeMinutes", value = "2")//线程存活时间
        },commandProperties = {
        @HystrixProperty(name = "execution.isolation.strategy",value = "THREAD")
}
//信号量隔离的设置
@HystrixCommand(
        //用来设置降级方法
        fallbackMethod = "myTestFallbackMethod",
        commandProperties = {
                //进行熔断配置
                //条件1,设置在滚动时间窗口中,断路器的最小请求数(没有达到不会熔断)。默认20。
                @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold" ,value = "10"),
                //条件2,设置断路器打开的错误百分比。在滚动时间内,在请求数量超过requestVolumeThreshold的值,且错误请求数的百分比超过这个比例,断路器就为打开状态。
                @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage" ,value = "30"),
                //条件3,设置滚动时间窗的长度,单位毫秒。这个时间窗口就是断路器收集信息的持续时间。断路器在收集指标信息的时会根据这个时间窗口把这个窗口拆分成多个桶,每个桶代表一段时间的指标,默认10000.
                @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds" ,value = "10000"),
                //设置当断路器打开之后的休眠时间,休眠时间结束后断路器为半开状态,断路器能接受请求,如果请求失败又重新回到打开状态,如果请求成功又回到关闭状态
                //单位是毫秒
                @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds" ,value = "3000"),

                //配置信号量隔离
                //配置信号量的数值
                @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests",value = "100"),
                //选择策略为信号量隔离
                @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"),
                //设置HystrixCommand执行的超时时间,单位毫秒
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000000000")
        }
)
public String Test(){
    ....
}

public String myTestFallbackMethod() {
    log.info("========myTestFallbackMethod=========");
    return "myTestFallbackMethod";
}

[容灾]流量控制 : Sentinel

[跟踪]链路追踪 : Skywalking

  • 官网

https://github.com/apache/skywalking

[跟踪]服务指标监控与可视化 : Grafana

  • 定义

Grafana是一个监控仪表可视化系统,由Grafana Labs公司开源的的一个系统监测 (System Monitoring) 工具。帮助用户简化监控的复杂度,用户只需要提供需要监控的数据,它就可以生成各种可视化仪表。同时它还支持报警功能,可以在系统出现问题时通知用户。
Grafana允许查询、可视化、报警和理解数据,无论它们存储在何处。但最迷人的一点是,Grafana主要的特点是面向时序数据设计的。

  • 特点
  • 可视化:具有多种选项的快速灵活的客户端图形。面板插件提供了许多不同的方法来可视化度量和日志。
  • 动态仪表板:使用模板变量创建动态和可重复使用的仪表板,这些模板变量显示为仪表板顶部的下拉列表。
  • 探索指标:通过特殊查询和动态向下钻取来探索数据。拆分视图并并排比较不同的时间范围、查询和数据源。
  • 探索日志:体验从指标切换到带有保留标签过滤器的日志的魔力。快速搜索所有日志或实时流媒体。
  • 警报:直观地定义最重要指标的警报规则。
  • 混合数据源:在同一图表中混合不同的数据源,可以基于每个查询指定数据源。这甚至适用于自定义数据源。
  • Grafana内置支持的数据源
  • Promethus

Prometheus是一个时间序列数据库。
但是,它不仅仅是一个时间序列数据库。
它涵盖了可以绑定的整个生态系统工具集及其功能。
Prometheus主要用于对基础设施的监控,包括:服务器(CPU、MEM等)、数据库(MYSQL、PostgreSQL等)、Web服务等,几乎所有东西都可以通过Prometheus进行监控。
而它的数据,则是通过配置,建立与数据源的联系来获取的。

虽然Grafana可以从多种数据(如Prometheus、MySQL/PostgreSQL、OpenTSDB)等等中获取数据;
不过Prometheus天生就是为了监控而生,所以Grafana中用的最多的还是Prometheus。

在Prometheus的架构设计中,Prometheus并不直接服务监控特定的目标,就比如我们监控linux系统,Prometheus不会自己亲自去监控linux的各项指标。
其主要任务负责数据的收集,存储并且对外提供数据查询支持。

因此,为了能够监控到某些东西,如主机的CPU使用率,我们需要使用到Exporter。
Exporter是一个相对开放的概念,不是专门指某一个程序。
它可以是一个独立运行的程序,独立于监控目标以外(如Node Exporter程序,独立于操作系统,却能获取到系统各类指标)。
也可以是直接内置在监控目标中的代码(如在项目代码层面接入普罗米修斯API,实现指标上报)。
总结下来就是,只要能够向Prometheus提供标准格式的监控样本数据,那就是一个Exporter。

而Prometheus周期性的从Exporter暴露的HTTP服务地址(通常是/metrics)拉取监控样本数据。

Grafana不仅仅只支持Prometheus作为查询的数据库,它还支持如下:

  • Alertmanager
  • AWS CloudWatch
  • Azure Monitor
  • Elasticsearch
  • Google Cloud Monitoring
  • Graphite
  • InfluxDB
  • OpenTSDB
  • Jaeger
  • Loki
  • Microsoft SQL Server (MSSQL)
  • MySQL
  • PostgreSQL
  • Tempo
  • Testdata
  • Zipkin

其他#配置中心

解决方案1:nacos 【推荐】

  • 官网

https://github.com/alibaba/nacos

解决方案2:spring cloud config

  • SpringCloud Config 官网

https://spring.io/projects/spring-cloud-config/

  • 定义

Spring Cloud Config 是 Spring Cloud 家族中最早的配置中心,虽然后来又发布了 Consul 可以代替配置中心功能,但是 Config 依然适用于 Spring Cloud 项目,通过简单的配置即可实现功能。

其他#分布式事务

解决方案1:seata 【推荐】

  • 官网

http://seata.io/zh-cn/

  • 定义

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

X 参考/推荐资料

posted @ 2020-10-13 15:50  千千寰宇  阅读(310)  评论(0编辑  收藏  举报