Featured image of post SpringCloud概述

SpringCloud概述

Spring Cloud就是微服务系统架构的一站式解决方案,在平时我们构建微服务的过程中需要做如 ** 服务发现注册 、配置中心 、消息总线 、负载均衡 、断路器 、数据监控 ** 等操作,而 Spring Cloud 为我们提供了一套简易的编程模型,使我们能在 Spring Boot 的基础上轻松地实现微服务项目的构建。

服务发现框架

Eureka

服务注册 Register :

当 Eureka 客户端(服务提供者)向 Eureka Server 注册时,它存储该服务的信息 ,比如IP地址、端口,运行状况指示符URL,主页等。

服务续约 Renew :

Eureka 客户端会每隔30秒(默认情况下)发送一次心跳来续约 。 通过续约来告知 Eureka Server 该 Eureka 客户仍然存在,没有出现问题。正常情况下,如果 Eureka Server 在90秒没有收到 Eureka 客户端的续约,它会将实例从其注册表中删除。

获取注册列表信息 Fetch Registries :

Eureka 客户端从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其他服务,从而进行远程调用。该注册列表信息定期(每30秒钟)更新一次。Eureka 客户端和 Eureka 服务器可以使用JSON / XML格式进行通讯。

服务下线 Cancel :

Eureka 客户端在程序关闭时向 Eureka 服务器发送取消请求。发送请求后,该客户端实例信息将从服务器的实例注册表中删除。该下线请求不会自动完成,它需要调用以下内容:DiscoveryManager.getInstance().shutdownComponent();

服务剔除 Eviction :

在默认的情况下,当 Eureka 客户端连续90秒(3个续约周期)没有向服务器发送服务续约,即心跳,服务器会将该服务实例从服务注册列表删除,即服务剔除。

另外还有:Zookeeper、Consul、SpringCloudAlibaba等都可以实现服务发现。

Eureka 原理⭐

Eureka 主要包括两块: Eureka Server 和 Eureka Client。

Eureka Server,服务端,有三个功能: 服务注册 提供注册表 同步状态

Eureka Client,客户端,是一个 Java 客户端,用于简化与 Eureka Server 的交互。它会拉取、更新和缓存 Eureka Server 中的信息。因此当所有的 Eureka Server 节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者。服务续约, 服务剔除, 服务下线 的功能。

Eurka 工作流程是这样的:

  1. Eureka Server 启动成功,等待服务端注册。
  2. Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务
  3. Eureka Client 会每 30s 向 Eureka Server 发送一次心跳请求服务续约,证明客户端服务正常
  4. 当 Eureka Server 90s 内没有收到 Eureka Client 的心跳,注册中心则认为该节点失效,会注销该实例
  5. 单位时间内 Eureka Server 统计到有大量的 Eureka Client 没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端
  6. 当 Eureka Client 心跳请求恢复正常之后,Eureka Server 自动退出自我保护模式
  7. Eureka Client 定时从注册中心获取服务注册表,并且将获取到的信息缓存到本地
  8. 服务调用时,Eureka Client 会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存
  9. Eureka Client 获取到目标服务器信息,发起服务调用
  10. Eureka Client 程序关闭时向 Eureka Server 发送取消请求,Eureka Server 将实例从注册表中删除

注意:重点介绍一下Eureka自我保护机制。如果出现大量的服务实例过期被剔除,则注册中心进入自我保护模式,注册表中信息不再被剔除,目的是提高eureka的可用性。默认情况下,统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,让这些实例不会过期。可能造成显示注册成功的服务无法访问服务,设置enableSelfPreservation=false关闭自我保护机制,把renewalPercentThreshold 比例降低,在Eureka Server端,如果出现无效的服务就会将该服务剔除。

Eureka 和 ZooKeeper 的区别 ⭐

  • C (Consistency) 强一致性
  • A(Availability) 可用性
  • P (Partition tolerance) 分区容错性

Zookeeper保证的是CP,Eureka保证的是AP。

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

nacos

nacos是springcloud的扩展,注册中心功能通过NacosDiscoveryClient 继承DiscoveryClient,在springcloud中,与Eureka可以无侵入的切换。注册中心可以手动剔除服务实例,通过消息通知客户端更新缓存的实例信息; 数据模型 Key 由三元组唯一确定, Namespace命名空间,分组group,service服务。nacos保证的也是AP。

nacos与Eureka对比

  • nacos在自动或手动下线服务,使用消息机制通知客户端,服务实例的修改很快响应;Eureka只能通过任务定时剔除无效的服务。
  • nacos可以根据namespace命名空间,DataId,Group分组,来区分不同环境(dev,test,prod),不同项目的配置。
模块 Nacos Eureka 说明
注册中心 服务治理基本功能,负责服务中心化注册
配置中心 Eureka需要配合Config实现配置中心,且不提供管理界面
动态刷新 Eureka需要配合MQ实现配置动态刷新,Nacos采用Netty保持TCP长连接实时推送
可用区AZ 对服务集群划分不同区域,实现区域隔离,并提供容灾自动切换
分组 Nacos可用根据业务和环境进行分组管理
元数据 提供服务标签数据,例如环境或服务标识
权重 Nacos默认提供权重设置功能,调整承载流量压力
健康检查 Nacos支持由客户端或服务端发起的健康检查,Eureka是由客户端发起心跳
负载均衡 均提供负责均衡策略,Eureka采用Ribion
管理界面 Nacos支持对服务在线管理,Eureka只是预览服务状态

配置中心

Spring Cloud Config

当我们的微服务系统开始慢慢地庞大起来,那么多 Consumer 、Provider 、Eureka Server 、Zuul 系统都会持有自己的配置,这个时候我们在项目运行的时候可能需要更改某些应用的配置,如果我们不进行配置的统一管理,我们只能去每个应用下一个一个寻找配置文件然后修改配置文件再重启应用 。

首先对于分布式系统而言我们就不应该去每个应用下去分别修改配置文件,再者对于重启应用来说,服务无法访问所以直接抛弃了可用性,这是我们更不愿见到的。

Spring Cloud Config 就是能将各个 应用/系统/模块的配置文件存放到 统一的地方然后进行管理 (Git 或者 SVN)。

我们的应用只有启动的时候才会进行配置文件的加载,那么我们的 Spring Cloud Config 就暴露出一个接口给启动应用来获取它所想要的配置文件,应用获取到配置文件然后再进行它的初始化工作。

怎么进行动态修改配置文件呢? 一般我们会使用 Bus 消息总线 + Spring Cloud Config 进行配置的动态刷新。

Nacos 对比apollo 和 Spring Cloud Config

对比项目/配置中心 spring cloud config apollo nacos
开源时间 2014.9 2016.5 2018.6
配置实时推送 支持(Spring Cloud Bus) 支持(HTTP长轮询1s内) 支持(HTTP长轮询1s内)
版本管理 支持(Git) 自动管理 自动管理
配置回滚 支持(Git) 支持 支持
灰度发布 支持 支持 待支持
权限管理 支持 支持 待支持
多集群多环境 支持 支持 支持
监听查询 支持 支持 支持
多语言 只支持Java Go,C++,Python,Java,.net,OpenAPI Python,Java,Nodejs,OpenAPI
分布式高可用最小集群数量 Config-Server2+Git+MQ Config2+Admin3+Portal*2+Mysql=8 Nacos*3+MySql=4
配置格式校验 不支持 支持 支持
通信协议 HTTP和AMQP HTTP HTTP
数据一致性 Git保证数据一致性,Config-Server从Git读取数据 数据库模拟消息队列,Apollo定时读消息 HTTP异步通知
单机读(tps) 7(限流所制) 9000 15000
单机写(tps) 5(限流所制) 1100 1800
3节点读 21(限流所制) 27000 45000
3节点写 5(限流所制) 3300 5600

总结

  1. Apollo和Nacos相对于Spring Cloud Config的生态支持更广,在配置管理流程上做的更好。
  2. Apollo相对于Nacos在配置管理做的更加全面,不过使用起来也要麻烦一些。
  3. apollo容器化较困难,Nacos有官网的镜像可以直接部署,总体来说,Nacos比apollo更符合KISS原则。
  4. Nacos部署和使用起来相对比较简洁,在对性能要求比较高的大规模场景更适合。

此外,Nacos除了提供配置中心的功能,还提供了动态服务发现、服务共享与管理的功能,降低了服务化改造过程中的难度。

消息总线

Spring Cloud Bus

你可以简单理解为 Spring Cloud Bus 的作用就是管理和广播分布式系统中的消息 ,也就是消息引擎系统中的广播模式。当然作为 消息总线 的 Spring Cloud Bus 可以做很多事而不仅仅是客户端的配置刷新功能。

而拥有了 Spring Cloud Bus 之后,我们只需要创建一个简单的请求,并且加上 @ResfreshScope 注解就能进行配置的动态修改了 。

负载均衡

Ribbon

Ribbon 是一个客户端/进程内负载均衡器,运行在消费者端

其工作原理就是 Consumer 端获取到了所有的服务列表之后,在其内部 使用负载均衡算法 ,进行对多个系统的调用。

Nginx 和 Ribbon 的对比 nginx 是客户端所有请求统一交给 nginx,由 nginx 进行实现负载均衡请求转发,属于服务器端负载均衡

Ribbon 是从 eureka 注册中心服务器端上获取服务注册信息列表,缓存到本地,然后在本地实现轮询负载均衡策略,属于客户端负载均衡

负载均衡,不管 Nginx 还是 Ribbon 都需要其算法的支持。

Nginx

  • 轮询:轮询是默认的方式,每个请求按时间顺序逐一分配到不同的后端服务器上。
  • 加权轮询算法:指定轮询的几率,wight和访问比率成正比,用于后台服务器性能不均匀的情况。
  • ip_hash:根据每个请求的ip的hash结果分配,因此每个固定ip能访问到同一个后端服务器,可以解决session问题。
  • fair(第三方):按照后端服务器的响应时间来分配请求,响应时间短的优先分配。
  • url_hash(第三方):按照访问url的hash结果来分配请求,每个固定的url访问同一个后端服务器。如果后端服务器是缓存时效率高。

Ribbon

  1. RoundRobinRule:轮询;Ribbon 默认采用的策略。若经过一轮轮询没有找到可用的 provider,其最多轮询 10 轮。若最终还没有找到,则返回 null。
  2. RandomRule:随机;
  3. AvailabilityFilteringRule:会先过滤掉由于多次访问故障而处于断路器状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问;
  4. WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快的服务权重越大被选中的概率越大。刚启动时如果统计信息不足,则使用RoundRobinRule(轮询)策略,等统计信息足够,会切换到WeightedResponseTimeRule;
  5. RetryRule:先按照RoundRobinRule(轮询)策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务;
  6. BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;
  7. ZoneAvoidanceRule:复合判断Server所在区域的性能和Server的可用性选择服务器,在没有Zone的情况下是类似轮询的算法;

Open Feign

也是运行在消费者端的,使用 Ribbon 进行负载均衡,所以 OpenFeign 直接内置了 Ribbon。 主要用于消费者和服务者的调用。

OpenFeign是Spring Cloud在Feign的基础上支持了Spring MVC的注解,列如@RequestMapping等,OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

微服务网关

Zuul

ZUUL 是为了实现动态路由、监视、弹性和安全性而构建的。就是这样的一个对于消费者的统一入口。

路由功能 Zuul 需要向 Eureka 进行注册, 以此来拿到所有 Consumer 的信息,从而直接可以做路由映射。

基本配置:

1
2
3
4
5
6
7
server:
  port:9000
eureka:
  client:
    service-url:
      # 这里只要注册 Eureka 就行了
      defaultZone:http://localhost:9997/eureka

然后在启动类上加入 @EnableZuulProxy 注解就行了。没错,就是那么简单。

统一前缀

这个很简单,就是我们可以在前面加一个统一的前缀,比如我们刚刚调用的是 localhost:9000/consumer1/studentInfo/update,这个时候我们在 yaml 配置文件中添加如下。

1
zuul:  prefix:/zuul

这样我们就需要通过 localhost:9000/zuul/consumer1/studentInfo/update 来进行访问了。

路由策略配置

你会发现前面的访问方式(直接使用服务名),需要将微服务名称暴露给用户,会存在安全性问题。所以,可以自定义路径来替代微服务名称,即自定义路由策略。

1
zuul:  routes:    consumer1:/FrancisQ1/**    consumer2:/FrancisQ2/**

这个时候你就可以使用 localhost:9000/zuul/FrancisQ1/studentInfo/update 进行访问了。

服务名屏蔽

这个时候你别以为你好了,你可以试试,在你配置完路由策略之后使用微服务名称还是可以访问的,这个时候你需要将服务名屏蔽。

1
zuul:  ignore-services:"*"

路径屏蔽

Zuul 还可以指定屏蔽掉的路径 URI,即只要用户请求中包含指定的 URI 路径,那么该请求将无法访问到指定的服务。通过该方式可以限制用户的权限。

1
zuul:  ignore-patterns:**/auto/**

这样关于 auto 的请求我们就可以过滤掉了。

** 代表匹配多级任意路径

*代表匹配一级任意路径

敏感请求头屏蔽

默认情况下,像 Cookie、Set-Cookie 等敏感请求头信息会被 zuul 屏蔽掉,我们可以将这些默认屏蔽去掉,当然,也可以添加要屏蔽的请求头。

过滤功能 所有请求都经过网关(Zuul),那么我们可以进行各种过滤,这样我们就能实现 限流 ,灰度发布 ,权限控制 等等。

过滤器类型:Pre、Routing、Post。前置Pre就是在请求之前进行过滤,Routing路由过滤器就是我们上面所讲的路由策略,而Post后置过滤器就是在 Response 之前进行过滤的过滤器。

SpringCloud Gateway

Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用。

gateway特性

  • 基于Spring 5,Reactor(模式) 和 SpringBoot 2.0
  • 能够在任何请求属性上匹配路由
  • 断言和过滤器是特定于路由的
  • Hystrix断路器集成
  • SpringCloud DiscoveryClient集成
  • 易于编写断言和过滤器
  • 请求速率限制
  • 路径重写

gateway与zuul区别

Zuul:

  • 使用的是阻塞式的 API,不支持长连接,比如 websockets。
  • 底层是servlet,Zuul处理的是http请求
  • 没有提供异步支持,流控等均由hystrix支持。
  • 依赖包spring-cloud-starter-netflix-zuul。

Gateway:

  • Spring Boot和Spring Webflux提供的Netty底层环境,不能和传统的Servlet容器一起使用,也不能打包成一个WAR包。
  • 依赖spring-boot-starter-webflux和/ spring-cloud-starter-gateway
  • 提供了异步支持,提供了抽象负载均衡,提供了抽象流控,并默认实现了RedisRateLimiter。

相同点:

  1. 底层都是servlet
  2. 两者均是web网关,处理的是http请求

不同点:

  1. 内部实现:
  • gateway对比zuul多依赖了spring-webflux,在spring的支持下,功能更强大,内部实现了限流、负载均衡等,扩展性也更强,但同时也限制了仅适合于Spring Cloud套件
  • zuul则可以扩展至其他微服务框架中,其内部没有实现限流、负载均衡等。
  1. 是否支持异步
  • zuul仅支持同步
  • gateway支持异步。理论上gateway则更适合于提高系统吞吐量(但不一定能有更好的性能),最终性能还需要通过严密的压测来决定
  1. 框架设计的角度
  • gateway具有更好的扩展性,并且其已经发布了2.0.0的RELESE版本,稳定性也是非常好的
  1. 性能
  • WebFlux 模块的名称是 spring-webflux,名称中的 Flux 来源于 Reactor 中的类 Flux。Spring webflux 有一个全新的非堵塞的函数式 Reactive Web 框架,可以用来构建异步的、非堵塞的、事件驱动的服务,在伸缩性方面表现非常好。使用非阻塞API。 Websockets得到支持,并且由于它与Spring紧密集成,所以将会是一个更好的 开发 体验。

  • Zuul 1.x,是一个基于阻塞io的API Gateway。Zuul已经发布了Zuul 2.x,基于Netty,也是非阻塞的,支持长连接,但Spring Cloud暂时还没有整合计划。

  1. 总结
  • 在微服务架构,如果使用了Spring Cloud生态的基础组件,则Spring Cloud Gateway相比而言更加具备优势,单从流式编程+支持异步上就足以让开发者选择它了。
  • 对于小型微服务架构或是复杂架构(不仅包括微服务应用还有其他非Spring Cloud服务节点),zuul也是一个不错的选择。

断路器

Hystrix

就是一个能进行 熔断降级 的库,通过使用它能提高整个系统的弹性。

所谓 熔断 就是服务雪崩的一种有效解决方案。当指定时间窗内的请求失败率达到设定阈值时,系统将通过 断路器 直接将此请求链路断开。

也就是我们上面服务A调用服务B在指定时间窗内,调用的失败率到达了一定的值,那么 Hystrix 则会自动将服务A与B之间的请求都断了,以免导致服务雪崩现象。

其实这里所讲的 熔断 就是指的 Hystrix中的 断路器模式 ,你可以使用简单的 @HystrixCommand 注解来标注某个方法,这样 Hystrix 就会使用 断路器 来“包装”这个方法,每当调用时间超过指定时间时(默认为1000ms),断路器将会中断对这个方法的调用。比如:

1
2
3
4
5
6
@HystrixCommand(
    commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1200")}
)
public List<Xxx> getXxxx() {
    // ...省略代码逻辑
}

降级是为了更好的用户体验,当一个方法调用异常时,通过执行另一种代码逻辑来给用户友好的回复 。这也就对应着 Hystrix 的 后备处理 模式。你可以通过设置 fallbackMethod 来给一个方法设置备用的代码逻辑。比如这个时候有一个热点新闻出现了,用户会通过id去查询新闻的详情,但是因为这条新闻太火了,大量用户同时访问可能会导致系统崩溃,那么我们就进行 服务降级 ,一些请求会做一些降级处理比如当前人数太多请稍后查看等等。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 指定了后备方法调用
@HystrixCommand(fallbackMethod = "getHystrixNews")
@GetMapping("/get/news")
public News getNews(@PathVariable("id") int id) {
    // 调用新闻系统的获取新闻api 代码逻辑省略
}
//
public News getHystrixNews(@PathVariable("id") int id) {
    // 做服务降级
    // 返回当前人数太多,请稍后查看
}

服务熔断原理

hystrix会监控微服务之间调用的状况,当失败的调用到一定阀值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。 是通过spring 的 AOP 功能实现的 HystrixCommand 注解的方法是一个切点,有一个对方法增强的类,对他增强,如果出现失败就中断这个方法的调用,返回失败。

数据监控

Hystrix Dashboard (断路器:hystrix 仪表盘)

Hystrix Dashboard 是一款针对 Hystrix 进行实时监控的工具。

通过 Hystrix Dashboard 我们可以在直观地看到各 HystrixCommandHystrixObservableCommand 实例的实时数据,比如请求响应时间、请求成功率等等。帮助我们快速发现系统中存在的问题。

Spring Boot Admin

Spring Boot Admin是一个开源社区项目,用于管理和监控SpringBoot应用程序。 应用程序作为Spring Boot Admin Client向为Spring Boot Admin Server注册(通过HTTP)或使用SpringCloud注册中心(例如Eureka,Consul)发现。 UI是AngularJs应用程序,展示Spring Boot Admin Client的Actuator端点上的一些监控。 Spring Boot Admin 为已注册的应用程序提供以下功能:

  • 显示运行状况
  • 显示详细信息,例如
    • JVM 和内存指标
    • micrometer.io 指标
    • 数据源指标
    • 缓存指标
  • 显示内部版本信息编号
  • 关注并下载日志文件
  • 查看 jvm 系统和环境属性
  • 查看弹簧启动配置属性
  • 支持Spring Cloud的可发布/env- &/refresh-endpoint
  • 轻松的日志级管理
  • 与 JMX-bean 交互
  • 查看线程转储
  • 查看 http-traces
  • 查看审计事件
  • 查看 http-endpoints
  • 查看计划任务
  • 查看和删除活动会话(使用春季会话)
  • 查看 Flyway / Liquibase 数据库迁移
  • 下载堆转储
  • 状态更改通知(通过电子邮件、Slack、Hipchat 等)
  • 状态更改的事件日志(非持久性)

Spring Cloud Alibaba

官方介绍:Spring Cloud Alibaba为分布式应用开发提供一站式解决方案。它包含开发分布式应用程序所需的所有组件,使您可以轻松地使用Spring Cloud开发应用程序。

Spring Cloud Alibaba是对Spring Cloud中部分停止维护的组件进行扩展的替换,目前由于Eureka、Zuul、Hystrix已不再开源,导致Spring开源基金会无法免费获取其授权,从而停止更新和维护,阿里分别推出nacos、gateway、Sentinel来替代,并加入了Alibaba Cloud SchedulerX、Seata、Alibaba Cloud SMS等组件,功能更丰富。

核心组件 Spring Cloud Spring Cloud Alibaba Dubbo
服务注册中心 Eureka nacos zookeeper/nacos
调用方式 Rest API Rest API RPC
服务网关 Zuul gateway
断路器 Hystrix Sentinel 不完善
分布式配置 Spring Cloud Config naco
分布式追踪系统 Sleuth Sleuth
消息总线 Bus Bus RocketMQ
数据流 Stream Stream
批量任务 Task Task
消息中间件 RecketMQ
分布式事务解决方案 Seata Seata
分布式调度服务 Alibaba Cloud SchedulerX
短信平台 Alibaba Cloud SMS
Built with Hugo     主题 StackJimmy 设计