欢迎关注微信公众号:Coding我不配
获取更多干货,一起每天进步一点点
单体应用程序就是所有的功能全部堆积在一起。在这个唯快不破的互联网时代,能否快速发布新功能、支持高并发和大数据,很大程度上决定了一个产品的生死。
随着业务快速发展,微服务架构应运而生。
微服务是一种结构风格,服务之间使用遵循 HTTP 的 API 进行资源访问与操作。每个小型服务可以独立部署,可以采用不同的语言进行开发,可以使用不同的数据库进行数据存储。
第一个优点是服务独立,每个服务都有独立的代码仓库、独立的数据库、独立进行部署的能力。
第二点是开发体验好,开发体验好的关键点在于启动速度快,克隆代码速度快,编译部署速度快,技术选型更自由。
第三点是职责专一性,服务只负责本身的业务,不关心无关业务。这样有利于实现不同的团队维护不同的服务。
第四点是按需扩容,也就是说某个服务特别耗内存,可以单独部署在内存比较大的机器上;如果特别耗 CPU , 那可以部署到 CPU 比较好的机器上。且只需要部署这个服务,不需要像单体应用那样部署整个应用。
微服务在解决问题的同时也引入了新的问题。
第一个缺点是分布式带来的复杂性,服务拆分后,本地调用变成了远程调用,服务实例有多个,如何负载均衡;被调用的服务出问题的话,如何调用容错;服务之间的依赖关系如何等问题。
第二个缺点是运维的复杂性,拆分后的服务数量多,部署后的服务节点多,需要有日志的统一管理,才方便通过日志排查问题。服务需要有统一监控,才能在发生问题时及时告警。
第三个缺点是服务拆分的复杂性,如何拆分出对应的服务很关键,需要结合自身的业务领域进行合理的拆分。拆分后每个服务都有自己的数据库,当一个业务操作涉及多个服务时,如何保证数据一致性等。
国外大多使用 Spring Cloud,而国内也有不少公司是基于阿里开源的 Dubbo 框架来构建微服务。
不过从 2017 年开始,Spring Cloud 在国内的普及度逐渐变高,越来越多的企业也开始使用 Spring Cloud。2019 年 8 月,Spring Cloud Alibaba 的发布也助力了 Spring Cloud 的高速发展。
Dubbo 专注于服务治理这块,性能比较高。而 Spring Cloud 的优势在于社区活跃,发布新功能的频率高,组件非常齐全,整合起来简单。
了解 Spring Cloud,需要对其中框架进行一定的掌握。 Spring Cloud 框架中的核心组件构成包括:
Eureka 主要用于服务治理;
Ribbon 用于负载均衡;
Hystrix 用于服务之间远程调用时的容错保护;
Feign 可以让通过定义接口的方式直接调用其他服务的 API;
Zuul 是 API 网关,是客户端请求的入口,负责鉴权,路由等功能;
Gateway 是新推出的基于 Spring 5 的响应式网关;
Config 用于统一的配置管理;
Sleuth 用于请求链路跟踪;
Stream 用来为微服务应用构建消息驱动能力。
Eureka 是 Spring Cloud 中负责服务注册与服务发现的组件,专注于服务注册与服务发现。
Spring Cloud Eureka 是 Spring Cloud Netflix 微服务套件的一部分,基于 Netflix Eureka 进行了二次封装,主要负责完成微服务架构中的服务治理功能。
Spring Cloud Eureka 是一个基于 REST 的服务,并提供了基于 Java 的客户端组件,能够非常方便的将服务注册到 Spring Cloud Eureka 中进行统一管理。
什么是注册中心?为了方便理解,可以将注册中心拆解成两个部分,分别是注册和中心。注册很好理解,比如用户注册,就是将自己的信息注册在某个平台上。再来看中心,可以理解成一个统一管理信息的平台。两个部分连起来就是注册中心,也就是统一管理所有注册信息的平台。
服务注册指的是服务在启动时将自身的信息注册到注册中心中,方便信息进行统一管理。服务注册是客户端向注册中心提交信息的动作。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GHTgYLQP-1594891179379)(https://imgkr.cn-bj.ufileos.com/3c332b17-20b1-434c-8095-614d055d2878.png)]
如上图所示,上面的部分是注册中心,下面的客户端是应用程序,服务注册就是应用程序在启动之后将自身的信息向注册中心进行注册的过程,服务注册后注册中心就有了所有应用程序的信息。
服务发现指的是从注册中心获取对应服务的信息。服务发现是客户端向注册中心获取信息的动作。
如上图所示是服务发现的过程。每个客户端都会从注册中心拉取自己关注的信息到本地。
服务调用,简单的说是一个应用程序调用另一个应用程序。调用的前提是服务注册与服务发现协作完好。
注册中心,用来集中存储管理服务信息。
服务提供者,通过 API 供其他方调用服务。
服务消费者,需要调用其他方的 API 获取服务。
无论是服务提供者还是服务消费者,都会将信息注册到注册中心中进行统一管理。
服务消费者需要知道服务提供者的信息,比如 IP、 端口等信息,才能发起远程调用,所以需要通过拉取的动作从注册中心拉取对应服务的信息,然后发起调用。
当服务提供者出现故障后,这时是无法提供服务的,如果此时服务提供者留在注册中心的状态还是正常就会导致服务消费者调用服务失败。
那么注册中心如何知道其他服务是否健康呢,这时就需要有一个心跳的动作,心跳就是健康汇报,定时跟注册中心汇报服务健康状态。
当一定时间内无心跳产生,则证明服务可能出现故障,无法汇报健康状态,注册中心就会剔除无效的服务信息。
Eureka 的架构主要分为 Eureka Server 和 Eureka Client 两部分,Eureka Client 又分为 Applicaton Service 和 Application Client,Applicaton Service 就是服务提供者,Application Client 就是服务消费者。
首先会在应用程序中依赖 Eureka Client,项目启动后 Eureka Client 会向 Eureka Server 发送请求,进行注册,并将自己的一些信息发送给 Eureka Server。
注册成功后,每隔一定的时间,Eureka Client 会向 Eureka Server 发送心跳来续约服务,也就是汇报健康状态。 如果客户端长时间没有续约,那么 Eureka Server 大约将在 90 秒内从服务器注册表中删除客户端的信息。
Eureka Client 还会定期从 Eureka Server 拉取注册表信息,然后根据负载均衡算法得到一个目标,并发起远程调用。
应用停止时也会通知 Eureka Server 移除相关信息,信息成功移除后,对应的客户端会更新服务的信息,这样就不会调用已经下线的服务了,当然这个会有延迟,有可能会调用到已经失效的服务,所以在客户端会开启失败重试功能来避免这个问题。
随着应用的访问量增加,单台服务器已经远不能满足高并发的业务需求,这时就需要多台服务器组成集群来应对高并发带来的业务压力,同时也需要负均衡器来对流量进行合理分配。
负载均衡是一种基础的网络服务,它的核心原理是按照指定的负载均衡算法,将请求分配到后端服务集群上,从而为系统提供并行处理和高可用的能力。
负载均衡的方式有很多种,在 Spring Cloud 体系中,Ribbon 就是负载均衡的组件,所有的请求都是通过 Ribbon 来选取对应的服务信息的。
主流的负载方案分为两种:
集中式负载均衡,在消费者和服务提供方中间使用独立的代理方式进行负载,如 Nginx。
客户端负载均衡,客户端根据自己的请求情况做负载,Ribbon 就属于客户端侧做负载的框架。
集中式负载均衡,如下图所示,就是集中式负载均衡的工作原理,负载均衡器负责维护需要负载的服务实例信息,如:192.168.1.1:8080 和 192.168.1.2:8080 这两个实例。
客户端不直接请求 192.168.1.1:8080 和 192.168.1.2:8080 这两个实例,而是通过负载均衡器来进行转发,客户端的请求到了负载均衡器这里,负载均衡器会根据配置的算法在 192.168.1.1:8080 和 192.168.1.2:8080 这两个实例中选取一个实例,转发到具体的实例上。
这样的好处是客户端不需要关心对应服务实例的信息,只需要跟负载均衡器进行交互,服务实例扩容或缩容,客户端不需要修改任何代码。
如下图所示,为客户端负载均衡,客户端负载均衡需要自己维护服务实例的信息,然后通过某些负载均衡算法,从实例中选取一个实例,直接进行访问。
集中式负载均衡和客户端负载均衡的区别:对服务实例信息的维护。
集中式负载均衡的信息是集中进行维护的,比如 Nginx,都会在配置文件中进行指定。客户端负载均衡的信息是在客户端本地进行维护的,可以手动配置,最常见的是从注册中心进行定时拉取。
Ribbon 是由 Netflix 发布的负载均衡器,它有助于控制 HTTP 和 TCP 的客户端的行为。Ribbon 属于客户端负载均衡。
为 Ribbon 配置服务提供者地址后,Ribbon 就可基于某种负载均衡算法,自动的帮助服务消费者进行请求。同时 Ribbon 默认提供了很多负载均衡算法,如轮询、随机算法等。
Ribbon 主要用于负载均衡场景,实现一个通用的负载均衡框架,则需要很多组件支持,Ribbon 中就提供了这些组件,有了这些组件,整个框架的扩展性便会更好,更灵活。 主要组件如下表:
组件 | 作用 |
---|---|
ILoadBalancer | 定义一系列的操作接口,比如选择服务实例 |
IRule | 算法策略,内置算法策略来为服务实例的选择提供服务 |
ServerList | 负责服务实例信息的获取,可以获取配置文件中的,也可以从注册中心获取。 |
ServerListFilter | 过滤掉某些不想要的服务实例信息 |
ServerListUpdater | 更新本地缓存的服务实例信息 |
IPing | 对已有的服务实例进行可用性检查,保证选择的服务都是可用的 |
Ribbon 的使用方式主要有以下三种
原生 API,Ribbon 是 Netflix 开源的,若项目中没有使用 Spring Cloud,可以在项目中单独使用 Ribbon,在这种场景下就需要使用 Ribbon 的原生 API。
Ribbon + RestTemplate,当项目整合了 Spring Cloud 时,就可以用 Ribbon 为 RestTemplate 提供负载均衡的服务。
Ribbon + Feign,通过结合 Feign 调用方式来进行负载均衡。
Hystrix 是由 Netflix 发布的针对微服务分布式系统的熔断保护中间件,相当于电路中的保险丝,它的关注度也非常高,在 GitHub 上已经有超过 18000 颗星,也经过了 Netflix 线上大规模流量的验证,性能非常稳定。
微服务架构下,会存在服务之间相互依赖调用的情况,当某个服务不可用时,很容易因为服务之间的依赖关系使故障扩大,甚至造成整个系统不可用的情况,这种现象称为服务雪崩效应。
如上图所示,为服务雪崩效应发生的过程,首先是服务正常状态,当客户端对服务 A 发起请求,服务 A 依赖了服务 B,服务 B 又依赖了服务 C,当所有服务都处于正常状态时,整个请求链路是通畅的,结果会很快返回给客户端。
如果这时服务 C 发生故障或出现性能问题,就会出现延迟,刚开始时延迟较小,随着时间的推移,延迟会越来越大,服务 B 对服务 C 的调用就会堵塞,服务 C 此时已经疲惫不堪。
由于请求都堵在服务 C 上,服务 B 作为调用方,却迟迟等不到服务 C 的结果,服务 A 对服务 B 的请求又源源不断的发送过来,最终导致服务 B 的资源耗尽,从正常状态变成不正常状态,再也无法及时响应服务 A 的请求结果。
依此类推,最终服务 A 也会被拖垮,导致整个系统不可用,这个过程就是服务雪崩效应。如果能从最开始的小问题进行预防,就不会出现后面的级联效果,本课时的主要内容就是讲解如何通过服务的容错降级来保证系统的可用性。
起因是服务提供者出了问题才导致后面的雪崩问题。
服务提供者应用程序常见问题:比如由于某些代码问题导致 CPU 飙升,将资源耗尽;服务器出现问题,磁盘出问题,导致数据读写特别慢,一下就拉高了响应时间;慢查询 SQL 超出了系统本身的承受能力等。
服务消费者主要表现在同步调用等待结果导致资源耗尽,还有就是自己即是服务消费者,同时也是服务提供者。
服务提供者方面,对于这种请求量超出承受能力的问题,可以进行扩容来支持高并发或者进行限流,自己能处理多少请求就处理多少,处理不了的请求直接拒绝,这样才不会将自己拖垮。
对于代码的 Bug 问题,可以通过测试来避免,对于慢 SQL 这种问题,需要去做数据库性能优化。对于服务器硬件故障问题,可以加大运维粒度,通过监控等手段来提前预防。
服务消费者方面,需要做的就是资源隔离,快速失败,这也是最有效的方式,当发现被调用方迟迟不响应出现问题的时候,就不要再继续发起调用请求了,此时应该停止,等待被调用方恢复后再发起调用。使用 Hystrix 就能轻松搞定这种场景。
在微服务架构下,很多服务都相互依赖,如果不能对依赖的服务进行隔离,那么服务本身也有可能发生故障,Hystrix 通过 HystrixCommand 对调用进行隔离,这样可以阻止故障的连锁反应,能够快速失败并迅速恢复服务或者进行回退并优雅降级。
Spring Cloud 将原生 Hystrix 整合进来,提供了最简洁的使用方式,并且跟 Feign、Zuul 等组件做了集成,极大的降低了使用的难度。
Hystrix 的 5 条设计原则:
避免线程耗尽,由于被调用方出现问题,调用方无法及时获取响应结果,而一直在发送请求,最终会耗尽所有线程的资源。
快速失败指的是当被调用方出现问题后,调用方发起的请求可以快速失败并返回,这样就不用一直阻塞住,同时也释放了线程资源。
支持回退指的是在失败后,可以让用户有回退的逻辑,比如获取备用数据,从缓存中获取数据,记录日志等操作。
资源隔离是设计原则里最重要的,当你的服务依赖了 A、B、C 三个服务,当只有 C 服务出问题的时候,如果没做隔离,最终也会发生雪崩效应,导致整个服务不可用,如果进行了资源隔离,A、B、C 三个服务都是相互隔离的,即使 C 服务出问题了,那也不影响 A 和 B。
近实时监控也非常重要,它能帮助了解整个系统目前的状态,有哪些服务有问题,当前流量有多大,出问题后及时告警等。
Hystrix 的使用主要有三种方式
注解方式操作步骤:首先需要在 pom 中增加 spring-cloud-starter-netflix-hystrix 的依赖,然后在启动类上增加 @EnableHystrix 注解,HystrixCommand 注解作用于方法上,哪个方法想要使用 Hystrix 来进行保护,就在这个方法上增加 HystrixCommand 注解。
Feign 是一个声明式的 REST 客户端,它的目的就是让 REST 调用更加简单。Feign 提供了 HTTP 请求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地址等信息。
常用的 API 调用方式主要有以下方式:
以上四种是最常见的 API 调用方式,在调用 API 之前,首先需要知道 API 的地址,其次是 API 对应的参数,然后发起调用,本质上调用 API 的过程就是一个 HTTP 请求过程。
Feign 会完全代理 HTTP 请求,只需要像调用方法一样调用它就可以完成服务请求及相关处理。
Feign 有如此强大的功能,离不开内部众多组件的支持,这些组件同时也为 Feign 提供了非常灵活的扩展机制。
重要组件如下图:
Contract 契约组件:Contract 允许用户自定义契约去解析注解信息。
Encoder 编码组件:通过该组件可以将请求信息采用指定的编码方式进行编码后传输。
Decoder 解码组件:Decoder 将相应数据解码成对象。
ErrorDecoder 异常解码器:支持可以直接用自定义异常。
Logger 日志记录:可以指定 Logger 的级别以及自定义日志的输出。
Client 请求执行组件:Client 是负责 HTTP 请求执行的组件。
Retryer 重试组件:当 HTTP 请求出现 IO 异常时,Feign 会限定一个最大重试次数来进行重试操作。
InvocationHandlerFactory 代理:采用 JDK 的动态代理方式生成代理对象。
RequestInterceptor 请求拦截器:添加多个拦截器,在请求执行前设置一些扩展的参数信息。
QueryMapEncoder 参数查询:可以基于 QueryMapEncoder 将实体类生成对应的查询参数。
在 Spring Cloud 中使用 Feign 主要有三步:
需要在启动类加 @EnableFeignClients 启用 Feign;
定义 Feign 的调用客户端,需要在接口上增加 @FeignClient 注解;
直接通过客户端访问接口。
当然 Feign 可以整合 Hystrix 一起使用。
在使用 Feign 的过程中,一些比较实用的技巧,主要有下面几点:
继承特性:可以简化重复的代码
拦截器:支持自定义拦截器
GET 请求多参数传递:使用 @SpringQueryMap 注解支持多个参数
日志配置:可以设置 FeignClient 的日志级别
异常解码器:支持自定义异常解码器
Zuul 是一个基于 JVM 路由和服务端的负载均衡器。提供了路由、监控、弹性、安全等服务。Zuul 能够与 Eureka、Ribbon、Hystrix 等组件配合使用。
网关是所有请求的入口,承载了所有的流量,始终战斗在最前线,高并发、高可用都是网关需要面对的难题。使用网关的情况,主要有动态路由、请求监控、认证鉴权、压力测试、灰度发布。
动态路由是动态的将客户端的请求路由到后端不同的服务上,如果没有网关去做统一的路由,那么客户端就需要关注后端 N 个服务。
左边的图没有使用网关,客户端调用服务时就需要访问服务各自的接口,如客户端调用 A 服务的接口就需要请求 a.com,而对需要访问服务的客户端来说访问流程越简单越好,现在需要关注多个 API 提供方,无疑提高了访问的复杂度。
右边的图使用了网关,使用网关后,客户端只需要关注网关的地址,也就是 gateway.com。不再需要关注多个 API 提供方,由网关统一路由到后端的具体服务中,这其实跟我之前讲的集中式负载均衡的概念类似,这样的好处是对客户端来说访问服务的流程简单了,关注的点少了。
请求监控可以对整个系统的请求进行监控,详细地记录请求响应日志,可以实时统计当前系统的访问量及监控状态。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zQyOaNwq-1594891179395)(https://imgkr.cn-bj.ufileos.com/f8d0b401-05c1-4b8b-ad3e-ee9f2685071d.png)]
如果没有使用网关的话,记录请求信息需要在各个服务中去做。当网关出现在架构中后,所有客户端的请求都会经过网关来做路由分发,入口统一了,很多事情也就好处理了,只需要在网关中统一进行请求信息的记录,就可以基于这些记录做实时的数据分析,比如并发调用量,根据数据分析决定是否要动态限流,分析是否有爬虫请求等多维数据结果。给业务方提供正确实时的决策信息,是非常有价值的。
认证鉴权可以对每一个访问请求做认证,拒绝非法请求,保护后端的服务。微服务架构下,如果没有使用网关,那么客户端需要直接跟多个服务进行交互,当请求到达对应的服务时,就必须验证当前的请求有没有登录,有没有权限访问。访问 A 服务需要验证一次,访问 B 服务也需要验证一次,每个服务都要做重复的工作。
当使用网关后,就可以在网关中做统一的验证逻辑了,唯一要做的工作就是在网关验证完成后,需要将用户信息传递给后端服务,后端服务默认相信当前的请求已经在网关中通过验证,它不会再去做验证的逻辑,但是当前请求对应的用户信息要告诉后端服务,可以将用户信息通过 HTTP 请求头传递给路由的后端服务。
压力测试是一项很重要的工作,像一些电商公司需要模拟更多真实的用户并发量来保证大促时系统的稳定,通过 Zuul 可以动态地将测试请求转发到后端服务的集群中,还可以识别测试流量和真实流量,用来做一些特殊处理。
灰度发布可以保障整体系统的稳定性,在初始灰度的时候就可以及时发现、调整问题,以降低影响范围。
当需要发布新版本的时候,不会立即将老的服务停止,去发布新的服务。而是先发布新版本的服务,比如之前的版本是 1.0,那么现在发布的版本就是 1.1,发布后,需要通过测试请求对 1.1 版本的服务进行测试,如果没发现什么问题,就可以将正常的请求转发过来了。如果测试中发现问题,可以直接停掉 1.1 版本的服务,就算不停掉也没关系,不会影响到正常用户的使用。
Zuul 于 2012 年开源,目前在 GitHub 上有超过 8000 多颗星的关注,经过 Netflix 在生产环境中长期的使用和改进,Zuul 的稳定性非常好。
过滤器可以对请求或响应结果进行处理,Zuul 还支持动态加载、编译、运行这些过滤器。Zuul 中的过滤器总共有 4 种类型,每种类型都有对应的使用场景。
pre 过滤器:可以在请求被路由之前调用。适用于身份认证的场景,认证通过后再继续执行下面的流程。
route 过滤器:在路由请求时被调用。适用于灰度发布的场景,在将要路由的时候可以做一些自定义的逻辑。
post 过滤器:在 route 和 error 过滤器之后被调用。这种过滤器将请求路由到达具体的服务之后执行。适用于添加响应头,记录响应日志等应用场景。
error 过滤器:处理请求发生错误时被调用。在执行过程中发送错误时会进入 error 过滤器,可以用来统一记录错误信息。
对于 Zuul 的路由方式主要有四种方式:
第一种路由方式是 URL 路由,不具备负载均衡。
第二种路由方式是配置多个 URL 负载均衡,本质上还是使用了 Ribbon 来进行负载均衡,所以需要通过配置 Ribbon 的 servers 来做负载。
第三种路由方式是为所有请求加前缀,这种方式适合需要对 API 有一个统一的前缀的场景,比如想统一的前缀为 openapi,那么就需要增加 zuul.prefix=/openapi。
第四种方式是基于 Eureka 代理服务,使用网关,90% 的需求都是转发内部服务,这些服务都会注册到 Eureka 中,虽然可以手动配置 Ribbon 的 servers 列表,但这种方式需要人为干预。所以需要在 Zuul 中集成 Eureka,在路由转发时可以转发到 Eureka 中注册的服务上,这样就很方便了,不需要去关心服务的上下线。
Zuul 的使用,首先在 pom 中增加 spring-cloud-starter-netflix-zuul 的依赖,加完依赖之后,在启动类上增加 @EnableZuulProxy 注解。然后打开配置文件,配置一个固定的路由 Zuul,启动项目访问地址即可。
Apollo 是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
配置中心是用来统一管理配置信息的产品,配置中心可以在微服务等场景下极大地减轻配置管理的工作量,增强配置管理的服务能力。
目前主流的配置中心有 Apollo、Spring Cloud Config、Nacos 等开源产品,每款配置中心都能满足统一管理配置的需求,不同的点在于是否能够快速让用户使用,部署难度,功能细节,扩展方法做的是否足够友好。
在没有使用配置中管理配置的时候,配置文件都是跟着项目走的,也就是存放在项目中的目录下,一个项目中可能有多个配置文件。
当项目发布的时候,会先编译打包,同时配置文件也会被打包进去,也就是配置文件会跟着项目一起发布。这样存在的问题是当需求修改配置的时候,需要重新在本地修改,然后重新发布才可以让新的配置生效,当请求压力越来越大,你的项目也会从 1 个节点变成多个节点,这个时候如果配置需要发生变化,对应的修改操作也是相同的,只需要在项目中修改一次即可,但对于发布操作工作量就比之前大了很多,因为要发布多个节点。
修改这些配置,发布的工作降低了整体的工作效率,为了能够提升工作效率,配置中心应运而生了,可以将配置统一存放在配置中心来进行管理。
使用配置中心管理配置后,可以将配置信息从项目中转移到配置中心,一般一个项目会有一个唯一的标识 ID, 也就是身份信息,通过这个 ID 从配置中心获取对应的配置内容。
主要的流程分为两个步骤,一个是拉取,一个是推送。拉取是在项目启动的时候通过配置中心拉取配置信息,推送则是配置中心必须要有的功能,如果没有推送功能,配置中心就没那么重要了。
之所以说推送是必须要有的功能,是因为在配置中心修改配置之后,可以将配置实时地推送给客户端进行更新,这样项目不用重启,修改配置实时生效,延迟较低。如果没有推送功能,手动将数据存在数据库中,写个定时任务去拉取配置,也同样可以做到配置统一管理,当然这是最简单的方式。
配置中心可以解决工作中的很多痛点,主要有:
统一管理不同环境、不同集群的配置:可以对配置进行环境的隔离,不同环境下的配置是不一样的
配置修改实时生效,即热发布功能
版本发布管理:在 Apollo 中修改任何配置都会生成对应的操作版本,当配置出现问题后,可以选择指定的版本进行回退。
灰度发布
权限管理、发布审核、操作审计
提供 Java 和 .Net 原生客户端。轻松集成,操作简单。
提供开放平台 API
部署简单
这点非常重要,很多框架在部署层面非常复杂,依赖各种环境和组件。Apollo 在这方面做的非常好,提供了部署安装包和脚本,部署简单,对外部的依赖也少,目前只需要依赖 MySQL 即可,用于存储配置数据。
Spring Cloud 体系中自带的配置中心是 Spring Cloud Config,两者区别:
Spring Cloud Sleuth 是一种分布式的服务链路跟踪解决方案,通过使用 Spring Cloud Sleuth 可以让快速定位某个服务的问题,以及厘清服务间的依赖关系。
微服务使系统变得越来越复杂,原本单体的系统被拆成很多个服务,每个服务之间通过轻量级的 HTTP 协议进行交互。
单体架构时,一个请求的调用链路非常清晰,一般由负载均衡器,比如 Nginx。将调用方的请求转发到后端服务,后端服务进行业务处理后返回给调用方。而当架构变成微服务架构时,可能带来以下几个问题:
一个请求往往需要调用多个服务,而当接口响应比较慢时,无法知道是哪个服务出现了问题,在什么地方比较耗时,只有通过链路跟踪,将整个请求的链路信息收集起来,才可以知道请求在哪个环节耗时较长,从而快速发现接口响应慢的问题,并及时解决。
服务之间都存在相互调用的情况,如果不做梳理工作,随着时间的推移,整个调用关系将会变成一张蜘蛛网,梳理调用关系可以在前期将服务之间的关系整理清楚,当需要对一个服务做改动时,可以明确的知道影响的范围。链路跟踪会将请求的链路信息记录起来,通过这些信息可以分析出服务之间的依赖关系,并且可以绘制出可视化的依赖关系图。
记录详细的日志能够方便排查问题,在微服务架构下,一个请求经过了 N 个服务,输出 N 条日志,需要将日志统一收集起来,而存在的问题是日志是在各个服务节点中输出的,当服务器时间不一致时,是无法获得正确的日志顺序的,最严重的是不知道这些日志间的关系,不知道某个请求对应的日志有哪些。链路跟踪会产生 tradeId,tradeId 会贯穿整个请求,将所有日志串联起来。
Sleuth 可以添加链路信息到日志中,这样的好处是可以统一将日志进行收集展示,并且可以根据链路的信息将日志进行串联。
Sleuth 中的链路数据可直接上报给 Zipkin,在 Zipkin 中就可以直接查看调用关系和每个服务的耗时情况。
Sleuth 中内置了很多框架的埋点,比如:Zuul、Feign、Hystrix、RestTemplate 等。正因为有了这些框架的埋点,链路信息才能一直往下传递。
Zipkin 是 Twitter 的一个开源项目,是一个致力于收集所有服务监控数据的分布式跟踪系统,它提供了收集数据和查询数据两大接口服务。有了 Zipkin 就可以很直观地查看调用链,并且可能很方便看出服务之间的调用关系,以及调用耗费的时间。
Zipkin 有四个组件:Collector,Storage,Search,Web UI。
Spring Cloud Alibaba 是由一些阿里巴巴的开源组件和云产品组成的。
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,你只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
Spring Cloud Alibaba 主要包含 Sentinel、Nacos、RocketMQ、Dubbo、Seata 等组件。
服务限流降级
Spring Cloud Alibaba 默认支持 WebServlet、WebFlux、OpenFeign、RestTemplate、Spring Cloud Gateway、Zuul、Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
服务注册与发现
Spring Cloud Alibaba 适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
分布式配置管理
Spring Cloud Alibaba 支持分布式系统中的外部化配置,配置更改时自动刷新。
消息驱动能力
Spring Cloud Alibaba 基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
分布式事务
Spring Cloud Alibaba 使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。
随着技术的不断发展,Spirng Cloud 在选择组件时更加关注易用性、性能方面。二代架构主要变化如下:
主要是 Eureka 替换成了 Nacos,二代架构引入了 Spring Cloud Alibaba,Nacos 就是其中比较重要的一个组件。Eureka 之前官方也宣布了暂停了 2.X 版本的开发,1.X 的版本还会维护。其实对于一般的服务规模,目前的 Eureka 完全够用了。而 Nacos 作为后起之秀,目前更新频率很高,社区也更活跃,使用 Nacos 是一个正确的选择。
Apollo 也替换成了 Nacos,Nacos 是既可以做注册中心,又可以做配置中心,替换的原因在于既然都用 Nacos 做注册中心了,顺便就用它的配置功能,这样就可以少维护一个组件。
网关从 Zuul 替换成 Spring Cloud Gateway,在 Spring Cloud Gateway 出现之前,网关都是用 Zuul 构建的,虽然 Netflix 开源了 Zuul2,由于各种原因,官方并没有打算将 Zuul2 集成到 Spring Cloud 体系中。
而是自己研发了一个全新的网关 Spring Cloud Gateway,由于 Zuul1 基于 Servlet 构建,使用的是阻塞的 IO,性能并不是很理想。Spring Cloud Gateway 则基于 Spring 5、Spring boot 2 和 Reactor 构建,使用 Netty 作为运行时环境,比较完美的支持异步非阻塞编程。
官方提供的压测报告显示 Spring Cloud Gateway 的性能是 Zuul 的 1.5 倍,Spring Cloud Gateway 刚出不久,稳定性有待验证,主要是缺乏大规模流量的验证,而 Zuul 开源的时间较长,同时在 Netflix 内部经过了大规模流量的验证,比较稳定。长期发展来说,Spring Cloud Gateway 的优势比较大,毕竟官方主推。
Hystrix 替换成了 Sentinel,Hystrix 也停止了开发,这个时候 Spring Cloud Alibaba 中的 Sentinel 的优势就很明显了,Sentinel 支持多样化的流量控制,熔断降级等功能,完全可以替代 Hystrix。
Spring Cloud Alibaba 的出现,对于社区,对于开发者都是福音,意味着在 Spring Cloud 体系中又多了一种选择,可以选择一开始的 Netflix 中的组件,也可以选择 Alibaba 中的组件。
在微服务脚手架构建微服务治理过程中,有很多组件可以选择,这里总结推荐使用 Spring Cloud 来构建微服务架构时使用的框架:
服务注册与发现:Nacos
服务熔断限流:Sentinel
服务通信调用:Feign
配置中心:Nacos
服务网关:Spring Cloud Gateway
分布式事务:Seata
消息队列:RocketMQ
调用链监控:Sleuth+Zipkin
欢迎关注微信公众号:Coding我不配
获取更多干货,一起每天进步一点点