type
status
date
slug
summary
tags
category
icon
password
本文是Manning的《微服务架构设计模式》一书的整理笔记,并加入了一些自己的想法,给尚未读过这本书的人探探路。这本书的代码部分是基于Java编写的,我个人希望脱离Java体系的捆绑,所以文中不会照搬书中的Java内容,只整理架构性、思路性的东西。
本文是笔记的第二部分,描述承载微服务架构所需要的Infra,具体涉及到API Gateway、服务的可配置性、可观测性以及容器化/Serverless部署等,与AWS DVA考试内容有很大的重叠。
第8章:外部API模式
每个微服务都有无数自己的API,而每种客户端(比如Web、移动端、其他应用)一面需要调用多个API满足需求,一面可能要求API为客户端做某些定制化,这就会陷入很多问题,比如,请求数量多性能差用户体验不佳、缺乏封装导致的客户端和微服务在业务逻辑上紧耦合、防火墙内外进程间通信不支持某些协议等种种制约等,此外客户端和服务器的任何一方发生变化或升级都会导致另一边跟着动,管理困难。
为此引入API Gateway模式,它相当于做一个单独的服务,来充当所有微服务的Facade层,除了网页静态资源请求外,其他的API请求都走这个层,这个曾负责把请求转发给后端每个微服务。在这一层里,做的事情是把外部来的一个请求拆分成对多个微服务的多个同步或异步请求,并且可以把HTTP低速通信为内网的gRPC高速通信。
使用API Gateway需要解决的问题是弄清楚谁来负责这样一个巨大的耦合点,在权衡如何划分指责和服务部署流程后,根据对灵活性的取舍,可以让所有微服务的开发团队共同管理,也可以让Web、移动端、其他应用等各个端都维护自己独立的API Gateway。
API Gateway可以解决很多边缘性问题,比如身份验证、访问授权、限流、缓存、指标收集、日志收集等,在AWS中提供了API Gateway的服务,可以通过配置解决上述边缘问题。笔者补充,虽说ALB也能当弱化版API Gateway用,但不推荐反过来把API Gateway当ALB用,因为流量分发不是API Gateway的职责范围,推荐让API Gateway的后面接一个ALB。另外,书中提到AWS的API Gateway不支持组合API是个弊端,我反而认为组合API是个不好的实践,业务逻辑面条代码应该推到后续的Lambda函数或者后端程序里,而不是让API Gateway抗业务逻辑。
API Gateway面对的一个典型场景就是不同客户端会对多个微服务发起数据库查询然后组合它们的结果,这会导致查询层代码极不灵活需要随需求不断扩展方法,一个解决途径是使用GraphQL模式(在AWS中的服务是AppSync),它相当于用一种DSL包装了查询,通过URL参数传递给API Gateway,再由解析逻辑映射为对不同微服务的API调用。笔者补充:这东西相当于对工具产生了强依赖,GraphQL的引入一旦深入体系,迁出成本会显著上升。
第11章:开发面向生产环境的微服务应用
这一章提到了几个边缘性问题话题,首先是服务的安全性,也就是给服务添加认证,整体来讲有两种策略,第一种是给每个API都赋予一个鉴权逻辑,可以通过编程切面实现,但是这让鉴权逻辑混入了业务代码中,更推荐的方式是把这件事做在API Gateway上以摆脱鉴权和业务逻辑的耦合,当然需要付出的代价就是要运维这个Infra。书中详细阐述了如何使用Java实现,但是个人作为一个AWS用户更倾向于使用AWS原生的工具,让请求的第一次去找一个/token的路由,可以在这个路由的背后通过OAuth2或者Lambda等方法返回一个token,以后针对所有API的Header里都带着这个token即可,AWS的API Gateway提供了一套特定的写法来支持HTTP和REST API不同格式如何获取token,并且在其内部实现了会话缓存,不需要重新造轮子。
第二个话题是服务的可配置性,主要提到了一些外部服务比如数据库的连接字符串等位置信息应该如何管理,一种方案是写到程序的运行时里,比如走环境变量,但一旦位置发生了修改就不得不导致服务的重启,另一种方式是从配置中心比如AWS的Parameter Store拉取,这样虽然多了一个infra,但是当配置变更时提供了更大的灵活性,前提是你要为infra付费。
第三个话题提及了微服务的可观测性,即如何在系统复杂度提高后仍能监控其运行状态、性能与故障。这些手段共同形成从可用性 → 可追踪性 → 可诊断性的闭环,使团队能在出现异常时快速定位问题。结合AWS和一些SaaS服务来讲有以下几条
- 暴露一个/health接口返回200检测服务是否健康(可以让CloudWatch Synthetics Canary主动探测)
- 把所有服务的日志发送到统一日志流水线,比如CloudWatch Logs
- 追踪分布式服务之间的延迟,比如使用X-Ray
- 使用统一服务收集硬件以及业务层面的指标,比如使用CloudWatch
- 统一管理每个服务的异常信息,比如使用Sentry.io
第12章:部署微服务应用
本章讨论的部署方式不仅适用于微服务,也概括了现代应用在不同封装层次下的典型部署模型,总共提及了四种服务的部署方式。
第一种是直接部署在物理机上,比如部署Java Web程序,就需要在物理机上安装JDK、安装Tomcat,然后通过流水线部署程序,这种方式部署速度快,能让服务吃足了资源,但是对技术栈的封装差,难以约束服务对资源的消耗,同时同一台机器上的服务缺乏隔离,需要手动维护管理每个服务的位置。
第二种方式是部署到虚拟机上,也就是通过EC2+ASG的方式,虚拟机封装了技术栈也隔离了服务实例,但缺陷是机器开得过大可能造成资源浪费,维护云平台还有额外的开销。
第三种方式是打包进Docker容器,它做到了很好的隔离性和对资源的控制,但容器镜像的管理工作是大头,且需要学习成熟的托管解决方案和治理平台,比如ECS和K8S。最后书中给出了用K8S部署一个Java服务的例子,这里不赘述。
第四种方法是Serverless部署加API Gateway访问,也就是Lambda函数,它不需要运维硬件,但限制颇多,需要对Lambda工具本身足够熟悉,且难以支持长连接。书中给出了让Lambda函数适配Spring Boot的例子,个人压根不推荐把Java用作Lambda函数的开发语言。最后书中推荐了Serverless Framework,但我觉得该方案在职责划分上较为模糊,不利于长期治理,推荐Terrafrom管理Lambda函数和API Gateway基础设施,Github Action管理代码和部署。
四种部署方式逐步体现了“封装性增强、资源利用率下降、运维责任转移”的演进规律。