微服务运行环境概览(一): SpringCloud 体系

个人学习,描述有误请指正。微服务架构可能给你带来实际的好处,也可能只是带来更多的烦恼,本篇博客是微服务架构运行环境的概述,来观察下可管理的微服务应用具备什么样的特征,第一篇会抛出问题,并使用SpringCloudAlibaba做解,第二篇中描述用K8s时的情况。这是两篇会迭代的文章,从大的方面入手,在迭代中修正问题或者添加一些细节。

这是一个常用的微服务架构的案例,我在其中标注了一些问题,并会尝试解答:
在这里插入图片描述完成用户的购物请求时,需要减库存、生成订单,并在生成订单时减余额,以上过程具有事务性。

问题解答

Q1:服务之间怎样调用

服务在独立的进程中运行,协作时通过TCP/IP网络通信,这也就意味着不论是HTTP还是RPC,A调用B就必须知道B的IP地址,这个问题会在后面提到。如果使用RPC作为应用层协议,业务代码不会包含网络调用方面的细节,能做到职责分离,如果使用HTTP,也可以引入spring-cloud-openfeign来简化HTTP的调用,获得像RPC一样的编码体验。否则业务代码中会包含这样的代码段:

// 使用WebClient
return webClientBuilder.build().get()
        .uri("http://x.x.x.x:x/?name=" + name)
        .retrieve()
        .bodyToMono(People.class)
        .block();

OpenFeign不仅仅是以这个示例的方式简化了代码,由于它对于开发者来说是远程调用的最上层,因此有意愿集成与远程调用相关的能力,比如在日志中打印远程调用的请求参数、超时判定、重试、执行降级逻辑(借助hystrix实现,但是已经被springcloud从组件库中移除)等,可以说是一个轻量级的流量治理方案。完整的特性参见feign项目主页。OpenFeign作为依赖库被引入应用程序中,不需要启动额外的进程。

可见,微服务中的远程调用可能不仅仅是选择一种协议,是性能、工程效率、反脆弱,甚至包含开源社区情况的多方面考量。

目前我们的微服务是这样的:
在这里插入图片描述

Q2:购物服务怎样找到库存服务的IP?

微服务架构的一个优势是具备天然的弹性边界,以示例场景来说,就是库存服务集群的规模是不固定的,此时购物服务要么通过名字找到库存服务,要么将请求发往反向代理提供的固定IP,后一种方式至少会增加一个进程,况且IP总归是更加容易发生变化的资源,前一种方式普遍来说更加合理,DNS就是一种根据名字找到IP的系统,但它不是为微服务架构中的动态服务发现而设计的,有专门适用于这个场景的服务发现组件,例如Nacos,每个应用实例中引入Nacos客户端,客户端向服务端注册服务,并且根据名字从服务端获得IP:PORT列表,大体上看功能并不复杂,但是这里还有很多考量的方面,例如:

  • 服务端的高可用,如何支持CP和AP
  • 对企业IT架构的支持,企业IT架构存在来自环境、业务、机房、权限等带来的管理差异或隔离需求
  • 可扩展性,能够充分描述一个服务,使得其他组件能够根据描述进行流量控制
  • 性能与容量
  • 易用性

以上考量的细节都能在Nacos架构与原理这本官方的免费电子书里找到,感兴趣可以阅读。

目前我们的微服务是这样的:
在这里插入图片描述

Q3:购物服务将请求发送到库存服务集群的哪个实例?

在Q2中,已经说明了购物服务的每个实例都能获取到一份完整的库存服务实例列表,那么应该将请求发往哪个实例呢?很显然这里需要一个客户端负载均衡,也就是说由购物服务的实例根据负载均衡策略选择一个库存服务的实例并发送请求,毫无疑问,需要在应用中再增加一个依赖,然后在此基础上选择或者自定义负载均衡策略。以购物服务实例获取库存服务实例列表为场景,举两个例子:

  • 库存服务实例包含权重标签,那么可以根据此标签做加权负载均衡
  • 购物请求的header中包含实例特征标签,将此类请求发往能够匹配到标签的实例

目前我们的微服务是这样的:
在这里插入图片描述

Q4:进程数量膨胀太快,怎么管理配置?

微服务架构中的应用进程很多,从单体到微服务,再到弹性集群,配置管理对象的数量相对来说增加了很多,何况还有出于各种目的的动态配置管理需求(比如功能开关、业务规则),这样的背景下,使用人工或者自动化工具修改配置然后重启服务显得捉襟见肘,服务必须知道自己需要从哪里获取配置,并主动响应配置变更,否则还是需要回到一些老问题上,比如修改哪些机器上的哪些应用的哪些配置之类的,不光复杂还很危险。集中的配置管理还能带来额外的好处,比如多环境管理、结构化配置、变更审计。Nacos除服务发现的能力外,还具备配置管理能力,幸运的是至此我们不用再启动新的进程来完成这项必须完成的工作。同样,细节可以参考Nacos架构与原理这本电子书。

目前我们的微服务是这样的:
在这里插入图片描述

Q5:一个交易由多个服务完成,怎样了解调用过程并查看日志?

如果是单体应用,仅靠日志就能了解一个交易的完整过程,一个交易不会有那么多必须关注的网络调用,并且只要找对主机就能看到完整的日志记录。对单体应用的观测也会有日志、方法追踪的需求,但是很难说会上升到基础设施的层面,而对于微服务架构,为日志和调用链建立专门的观测系统几乎是必须的,否则很快就没有人知道大量的服务之间到底是什么关系,很难排查问题,也不知道如何优化,另外一个观测的主题是指标,它决定了何时启动弹性动作。将可观测性的三大支柱(日志、指标、追踪)统一到一个时间线上或者说一个系统中几乎是运维微服务架构应用的本能,业界的标准是OpenTelemetry(可以阅读OpenTelemetry可观测性的未来这本小册子),它描述的架构中,通过应用中嵌入的SDK,将数据暴露给本地的收集器,收集器做一些数据丰富、缓存、容错的处理,最后将数据发送到服务端,分别进入满足数据特性的分析型存储,最终从一个统一的界面上显示出来:
在这里插入图片描述
这是一个美好的未来,在SpringCloud项目中,追踪使用轻量的Sleuth+ZipKin方案,日志更加灵活,推荐使用本地的采集器进程,指标方面SpringBoot项目可以暴露与Prometheus集成的端点,还要考虑基础设施、中间件之类的指标,可观测会给系统增加很多进程。

目前我们的微服务是这样的:
在这里插入图片描述

Q6:每个服务都暴露了API,怎样才能管理它们?

微服务架构中的每个应用都应该等同于一个产品,它们对外提供了API,需要考虑兼容性等各种作为产品需要面对的问题,这也意味着这些API在漫长的生命周期中能够被各方调用,如何管理这些API就成了很大的问题,比如提供统一的入口,并在入口处进行准入控制、限流、熔断、重写等。市面上有很多功能强大的API网关产品,SpringCloud中使用Gateway组件实现这一功能,它是一个使用SpringBoot构建的应用,不能代替Nginx,需要一些开发量来实现相对复杂的功能,动态配置也需要借助配置中心完成,相对来说是一个轻量级的组件。Gateway承载了微服务的入口控制功能,如果有较多或者较专业的外部调用,也有必要增加出口网关。

目前我们的微服务是这样的:
在这里插入图片描述

Q7:如果账户服务超时,故障随着依赖路径传递怎么办?

微服务架构复杂性的一个核心是大量的网络调用,发生在网络上的行为可能因为各种原因产生异常,比如网络自身或者下游服务异常,它的可怕之处在于局部的问题会很快放大到全部,从而导致全部服务不可用,也就是微服务的雪崩,这让微服务的弹性在故障来临时失去了意义,在前面介绍OpenFeign时提到它可以判定超时、重试以及执行降级逻辑,这些行为能够阻止微服务雪崩的原因在于快速失败或者返回一个能接受的结果,让请求不再堆积,看起来似乎不错,但实际的环境更加复杂,比如在QPS或并发线程数等维度:

  • 在异常或者超时时降级,执行降级逻辑,在逻辑中重试、恢复异常或者返回一个可接受的结果
  • 如果一段时间内满足总请求数量的异常比例超过阈值,就执行熔断,对所有请求降级,熔断结束后探测下游可用性,决定是否恢复熔断
  • 如果访问访问流量超过阈值,对流量进行限流或者将请求排队,按速率放行
  • 在指定的时间内逐步提高放行流量的比例,进行预热
  • 关联资源的流量到达阈值时,限制当前资源的流量
  • 指定链路(API)的流量到达阈值时,限制当前资源的流量
  • 对来自指定调用源的流量进行限流
  • 对热点流量进行特别处理
  • 对发往集群的流量进行限制,控制整个集群的调用总量
  • 对进入网关的流量进行限制,比如针对客户端IP、Header、URL参数进行控制
  • 系统自适应保护,让系统尽可能跑在最大吞吐量的同时保持稳定性

想要实现以上功能就必须引入一个尽可能强大和灵活的方案,SpringCloud生态中阿里开源的Sentinel就可以做到,需要在应用中引入客户端实现流控,同时还需要一个编辑和保存流控规则的管理进程,Sentinel开源的管理进程非常简陋,甚至不能持久化规则,如果需要做持久化集成,可以这样改造:Sentinel客户端从Nacos中加载规则,而Dashboard将Nacos作为持久化存储。Sentinel和OpenFeign提供的功能并不冲突,后者可以提供兜底。

目前我们的微服务是这样的:
在这里插入图片描述

Q8:怎样防止交易被发邮件之类的步骤阻塞

防止交易被长耗时的步骤阻塞,一定是采用异步解耦的方式,这里需要引入具备特定功能的消息队列进行支持,比如延时消息、死信队列等,在事务场景下可能还需要事务型消息的支持,另外的关键场景包含消息广播和削峰填谷。异步是变性能需求为规模需求的关键,生产者和消费者的模型也是一种非常好的扩展方式,因此消息队列是微服务架构里的关键中间件。因为他是一个业务组件,这里不将它体现在图形中。

Q9:用户购物具有事务性,怎样实现?

示例业务是有事务性的,必须保证多个数据源操作的一致性,此时可以引入分布式事务解决方案,比如Seata,它是阿里开源的方案,将一个大的全局事务分解成了多个小的分支事务,通过中心化的TC记录和维护全局和分支事务的状态,由全局事务发起方扮演TM角色,管理全局事务,由分支事务参与方扮演RM角色,管理分支事务、在业务表中生成undo_log(嵌入应用的Seata客户端对数据源做了代理)。全局事务的实现方式分为自动化的AT模式和支持用户更多介入的TCC模式和Saga模式(面向长事务),更加详细的方案参考官方博客Seata极简入门。尽管AT模式对于开发者非常友好,对于SpringBoot应用仅仅是几个注解就能开启分布式事务,但Seata仍然是一个重量级的解决方案,需要一个中心化的TC、每次事务都要涉及多个角色之间的交互,需要在适当的时候引入,否则将增加系统的复杂性。如果对事务有疑问,可以参考博客为什么需要事务呢?进行了解。

目前我们的微服务是这样的:
在这里插入图片描述

Q10:怎样部署微服务

现在我们可以看到一个非常复杂的环境,应用的开发、维护具备非常多的内外部依赖,如果说内部依赖让我们不得不面对大量的抽象,那外部依赖和众多的应用进程管理起来就非常困难了,如果没有良好的运行环境支持,堪称噩梦,实际中存在这样的情况:

  • 发布时手动传包到几十个机器,挨个手动操作,运维搞不定就盯着开发搞,基本顶着人力的上限运行
  • 使用容器部署,基本解决了应用打包的问题,但是一台主机上会跑经过人工编排的多个容器,也是运维压力山大

何况还有异构基础设施的问题,在这样的压力下,必然会寻求解法,比如采用自动发布、K8s之类的,但也会面临一系列的细节问题,比如哪些行为由外部的自动化系统来做、哪些行为需要应用架构优化、如何屏蔽K8s的复杂性等等,这些问题似乎都能扩展到研发效能,毕竟架构与工具是能够统一到业务目标的,这是一个非常大的话题。

总结

以上看似描述了一个比较完善的微服务框架,好像万事俱备只欠东风,但是真正跑起来会发现很多开源组件都存在最后一公里的问题,比如Nacos、Sentinel、Zipkin等,即使它们的核心逻辑经得起考验,但对你来说可能是一堆割裂的、不够安全的、功能缺失的组件,看看它们的控制台你就有修理一番的冲动,SpringCloudAlibaba更好用的版本在阿里云上,不多讨论开源本身的问题了。

可以看到SpringCloud体系降低了构建微服务的难度,但是并没有云原生体系的高度,在云原生体系下,微服务是云原生的技术特征之一而不是全部,我们需要看看云原生话语体系下的微服务架构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值