云架构中的API网关、微服务与无服务器设计
1. API网关与应用负载均衡器
API网关位于服务前端,能够决定可利用的服务能力,并控制请求的验证。同时,它支持模拟集成,这是一种具有固定响应的虚假集成,常用于在后端仍在开发时进行测试和模拟。API可以提供一个固定响应,反映后端准备好时的实际响应,这样前端开发人员可以与后端开发人员并行工作,而无需等待后端完成开发。
应用负载均衡器(ALB)虽然乍一看与API网关有相似的作用,但它缺乏一些有用的功能,如处理HTTP头以及请求和响应转换。若需要这些功能,就必须在微服务代码中进行开发,这会增加不必要的复杂性。不过,ALB可以与Cognito集成,用于用户认证和实施访问控制。
ALB采用基于负载均衡器容量单位(LCU)的按小时计费模式。LCU定义了每秒支持的新连接数、每分钟的活动连接数以及每小时可处理的字节数。每个LCU每秒最多可评估1000条规则,若要提高限制,需增加ALB中配置的LCU数量。
请求大小是影响成本的关键参数。API网关对0到512KB之间的任何请求收取相同费用,而ALB的成本受请求大小影响较大,因为它按LCU收费,每个LCU每小时支持400MB。对比可知,如果应用程序预计会有大请求,运行API网关的成本将比ALB低得多;但如果请求较小,ALB则是更便宜的选择。在每秒100个请求的示例中,收支平衡点的请求大小约为210KB。对于API网关HTTP API,结果类似,但HTTP API成本更低,此计算的收支平衡请求大小降至约62KB。
| 对比项 | API网关 | 应用负载均衡器(ALB) |
|---|---|---|
| 功能特性 | 支持请求验证、模拟集成,处理HTTP头和请求响应转换功能强 | 缺乏处理HTTP头和请求响应转换功能,需在微服务代码中开发 |
| 计费模式 | 0 - 512KB请求收费相同 | 基于LCU按小时计费,每个LCU每小时支持400MB |
| 成本优势 | 大请求时成本低,月成本易预测 | 小请求时成本低,成本随请求大小和数量波动大 |
| 收支平衡请求大小(每秒100请求) | HTTP API约62KB,普通约210KB | - |
2. 无服务器设计模式
无服务器并非现代云应用的万能架构,大型复杂解决方案很少能100%采用无服务器架构。具有复杂或遗留数据模型的应用往往离不开关系数据库,因此应用,尤其是迁移后的应用,往往是混合架构,包含无服务器、完全托管以及容器或服务器。有时,对于特定应用或团队,单体架构可能更有意义。优秀的架构师不应强行将不适合的解决方案采用无服务器架构。
常见的无服务器项目类型如下:
1. 简单的独立函数,如对上传到S3的新图像做出反应并创建缩略图的触发函数,或对特定DynamoDB数据库具有独占访问权的微服务,以增加安全性和审计功能。
2. 管道,其中Lambda微服务是服务之间的粘合剂,如视频处理(面部和对象的视频分析 + 提取音频并转录 + 文本分析)。Step Functions通常是管理管道的合适服务。
3. IoT和类似的边缘计算场景,有一系列完全托管和无服务器服务对此类用例提供强大支持。
4. 具有基本交互的简单单页网站,如处理联系或注册表单。
复杂解决方案通常是混合架构,将无服务器和其他架构混合使用。可以将项目分解为多个部分,为每个部分单独评估最佳方法。例如,处理关系数据库中数据的微服务集合可以采用更偏向单体的架构,使用Lambda层减少重复代码;而执行特定任务并使用NoSQL数据库的单个微服务可以采用独立微服务架构。每个部分可视为一个独立项目,拥有自己的基础设施即代码(IaC)、仓库和文档,参数可以通过堆栈之间共享或使用Parameter Store等服务进行共享。
以下是不同的部分设计方案:
a. 完全无服务器:每个Lambda微服务或Fargate容器独立运行,仅使用无服务器服务,如DynamoDB。虽然成本效益高,但难以实现,若不符合项目最佳利益,不应强行采用。
b. 单体无服务器:仍然使用Lambda微服务,但大多数功能集中在单个Lambda或共享层中。在存在多个非常相似的微服务(如API CRUD)的情况下,这可能是减少代码重复的好方法。
c. 基于容器或服务器:在某些情况下,如机器学习和其他依赖GPU的任务,Lambda微服务或Fargate容器无法解决问题,此时需要使用容器、服务器或基于服务器的服务。在可能的情况下,应由微服务启动,完成任务后终止,以最小化风险和计费空闲时间。
3. 何时不使用严格的微服务架构
对于不会随时间增长的简单API服务,为每个API资源使用一个微服务来执行创建/检索/更新/删除操作,可能比将每个资源拆分为四个不同的微服务更有意义。当不同组件之间存在大量代码相似性时,需要考虑微服务是否是正确的选择,因为最终会得到许多几乎相同的微服务,这在简单API后端中很常见,每个API路径都执行非常相似的CRUD活动。如果对剩余数据的操作都相同,那么一个能够处理不同数据模式的单个微服务可能是更好的方法。
如果低延迟是关键因素,将请求分散到多个微服务可能不是正确的做法,因为每个步骤都会增加请求的延迟。无服务器微服务是事件驱动的,不适合长连接,如果请求无法转换为事件驱动设计,容器会更合适。
4. 微服务示例架构
4.1 基本CRUD API
CRUD微服务能为用户提供快速响应,但与解耦微服务相比,其弹性有所降低。管理WebSocket连接、请求和断开事件的微服务也属于此类。
graph LR
A[客户端] --> B[CRUD微服务]
B --> C[数据库]
4.2 触发或解耦微服务
触发或解耦微服务在后台运行,对云环境中的事件做出反应。它们可以由另一个服务或微服务直接触发,也可以通过任务队列触发。解耦微服务通常是异步的,即它在后台运行,前端应继续执行而无需等待响应。
graph LR
A[事件源] --> B[任务队列]
B --> C[解耦微服务]
C --> D[后续服务]
4.3 守门人微服务
任何想要对特定数据进行操作的微服务、应用程序或用户都必须通过守门人微服务。它提供了一个单一的位置来验证、格式化和记录请求,确保进出数据库的数据一致性,并为与该数据相关的所有操作提供审计跟踪。守门人微服务对于保护敏感数据(如个人身份信息、医疗、金融或安全数据)特别有用。
创建守门人微服务时,需为其分配一个具有访问特定DynamoDB表、S3存储桶或其他相关服务权限的角色,并确保其他微服务没有相同的访问权限。其他微服务若要对该数据执行任何活动,必须从守门人微服务获取或传递数据。在某些情况下,目标服务支持传入访问策略,可以添加仅允许守门人访问的策略;或者利用KMS密钥进行加密,为守门人微服务提供独占访问权限。同时,应启用所有可用的日志记录和监控功能,并将代码中的每个操作记录到CloudWatch中,附带用户ID以进行审计。
graph LR
A[其他微服务/用户] --> B[守门人微服务]
B --> C[数据库/S3等]
4.4 CRON或定时微服务
此类微服务用于处理定期或一次性的定时事件。
graph LR
A[定时触发器] --> B[CRON微服务]
B --> C[执行任务]
4.5 边缘计算
在合适的情况下,可以利用用户的处理能力。如果前端(如Web或移动应用)能够执行应用程序所需的某些操作,且这些操作不涉及敏感或专有信息,可将其移至前端范围。这样可以降低云运营成本和应用程序延迟,提升用户体验。
graph LR
A[客户端设备] --> B[执行部分操作]
B --> C[云服务]
5. 无状态架构
在典型的应用程序或网站中,后端会记录与用户当前会话相关的数据,这些会话数据也称为状态,包含认证状态、历史记录、个人资料信息和当前活动等。在传统的单体应用中,信息存储在应用服务器本地,这被称为有状态应用。有状态应用是常见模式,因为服务器提供了易于访问的持久存储,状态信息可以快速存储和检索,应用的任何部分都可以轻松访问。
传统应用服务器的会话流程如下:
1. 客户端登录并发送必要的凭证。
2. 应用程序从数据库中检索用户信息并验证凭证。
3. 验证通过后,创建会话令牌,客户端可使用该令牌进行后续请求而无需再次登录。
4. 会话令牌存储在服务器上,并返回给客户端,对于网站,通常存储在cookie中。
5. 对于后续的后端服务请求,客户端将会话令牌发送到服务器(浏览器通常会使用cookie自动完成),应用程序验证令牌并检索请求所需的状态。
然而,将有状态的遗留应用迁移到云环境时会面临一些挑战。有状态设计适用于单服务器应用,但在云中,应用需要具备可扩展性,应在服务器集群(EC2实例)上运行。当有状态的遗留应用迁移到云时,必须确保特定用户的请求始终发送到创建其会话的同一服务器,否则用户每次都需重新登录。在扩展集群并添加更多服务器时,现有用户仍会被发送到旧服务器,这使得负载分配更加困难,用户体验也会受到影响。若服务器发生故障,该服务器上的会话数据将丢失,集群会将用户重定向到正常工作的服务器,用户必须再次登录以创建新会话。
相比之下,无状态设计更适合现代云应用。无状态并不意味着没有会话,而是指会话数据的存储位置。在无状态设计中,会话存储在外部存储解决方案(如数据库)中。在自动扩展基础设施中的多个服务器都可以访问相同的会话,扩展时负载可以均匀分布。同样,服务器故障对用户来说应该是无感知的,因为另一个服务器会接管。集中式会话也更便于管理会话和进行访客分析,但缺点是会增加延迟,因为每个传入请求都需要额外的数据库查询,有时如果需要将会话数据添加到会话中,则需要进行两次查询。
容器同样可以支持有状态和无状态设计,但为了实现架构的可扩展性和冗余性,需要采用无状态设计。例如,创建发票的微服务不需要会话,它只需由事件触发,将数据注入发票模板,然后保存为PDF,供后续流程处理。
graph LR
A[事件] --> B[发票微服务]
B --> C[生成PDF]
C --> D[后续处理]
6. 微服务解耦
耦合是指应用程序中两个组件之间的关系,定义了它们协同工作的紧密程度和相互依赖程度。解耦则是在不影响组件输出或质量的前提下,减少这种依赖关系。微服务天生独立且自包含,非常适合进行解耦。
解耦的原因是提高容错能力,使每个组件能够独立于工作流中其他组件的性能执行各自的任务。通过监控每个组件并对故障等事件做出响应,可以在解耦的工作流中设计自愈和自动错误报告功能。
解耦最初是从服务器开始的,早期的系统需要确保消息代理能够按需扩展、可靠运行并保持可用。
解耦带来的好处包括:
- 提高微服务的独立性,使微服务的更新更容易,因为触发、输入和输出都是标准化的。
- 解耦的微服务更容易独立于其他组件进行扩展。
- 便于多个应用程序使用单个共享微服务,也便于多个开发人员并行处理不同的微服务。
- 工作流更加灵活,更容易开发具有动态序列的决策树,并在工作流中添加或删除步骤。
- 由于输入和输出已标准化,微服务内部的编程语言、结构和方法对工作流没有影响,可以选择最适合任务的解决方案,但仍应遵循最佳实践和组织标准。
解耦在可扩展性方面也有帮助:
- 作业队列每秒可以处理大量请求,通常比数据库或自动扩展容器等服务处理能力更强。
- 队列可以帮助管理请求的突然激增,让服务有时间按需扩展,并在不拒绝或丢失请求的情况下赶上积压的任务。
然而,解耦也存在一些挑战:
- 解耦始终是一个异步过程,会增加总请求时间的延迟,因此不适用于某些用例,需要有一种方法在请求完成后将更新推送给客户端。
- 存在额外的成本,作业队列服务对每个作业和交互都收费,虽然单个费用较低,但在大规模使用时会累积起来。
- 架构复杂性增加,分布式、异步和并行模式带来了自身的挑战,通常需要陡峭的学习曲线。在处理数据的应用中,需要考虑最终一致性而非保证一致性。可能会出现重复事件,组件需要识别并适当处理。扇出式解耦模式意味着事件消息会有多个接收者,这也会带来新的挑战。
在耦合的微服务流程中,当发生错误时,只能向用户返回错误,尽管至少已经完成了部分处理,请求和任何文件数据也会丢失,用户需要在问题解决后重新提交。而在解耦的微服务流程中,每个微服务将其输出发送到作业队列,队列再触发工作流的下一步。当微服务成功完成任务后,将其从队列中移除并将输出传递给下一步。如果微服务失败,任务不会从队列中移除,并在短时间后再次激活,队列会尝试再次触发微服务以自动从临时问题中恢复。如果仍然失败,可以通知应用程序团队手动解决问题。问题解决后,任务可以重新发送到队列,工作流可以继续,请求和文件数据不会丢失,用户无需重新提交。
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
subgraph 耦合流程
style 耦合流程 fill:#ffffff,stroke:#000000,stroke-width:2px;
A1(客户端):::process --> B1(微服务1):::process
B1 --> C1(微服务2):::process
C1 --> D1(结果返回):::process
end
subgraph 解耦流程
style 解耦流程 fill:#ffffff,stroke:#000000,stroke-width:2px;
A2(客户端):::process --> B2(微服务1):::process
B2 --> E2(作业队列):::process
E2 --> C2(微服务2):::process
C2 --> F2(移除任务):::process
F2 --> D2(结果返回):::process
end
综上所述,在云架构设计中,需要综合考虑API网关与ALB的特点、无服务器设计模式的适用场景、微服务架构的选择以及状态管理和解耦等因素,以构建高效、可靠且成本合理的应用程序。
云架构中的API网关、微服务与无服务器设计
7. 不同架构的对比总结
为了更清晰地了解API网关、应用负载均衡器、不同无服务器设计模式、微服务架构以及有状态和无状态架构的特点,我们对其进行了对比总结,如下表所示:
| 架构类型 | 优点 | 缺点 | 适用场景 |
| ---- | ---- | ---- | ---- |
| API网关 | 支持请求验证、模拟集成,大请求成本低,月成本易预测 | - | 应用程序有大请求,需要处理HTTP头和请求响应转换 |
| 应用负载均衡器(ALB) | 可与Cognito集成用于认证和访问控制,小请求成本低 | 缺乏部分功能,需在微服务代码开发,成本波动大 | 应用程序请求较小 |
| 完全无服务器 | 成本效益高 | 难以实现 | 简单独立功能、特定场景微服务 |
| 单体无服务器 | 减少代码重复 | - | 存在大量相似微服务的场景 |
| 基于容器或服务器 | 可处理特定复杂任务 | 有风险和计费空闲时间 | 机器学习等依赖GPU的任务 |
| 基本CRUD API | 响应快速 | 弹性降低 | 简单的增删改查操作 |
| 触发或解耦微服务 | 异步处理,灵活度高 | 增加延迟,有额外成本和架构复杂度 | 对实时性要求不高的任务 |
| 守门人微服务 | 保证数据一致性和安全性,提供审计跟踪 | - | 保护敏感数据 |
| CRON或定时微服务 | 处理定时任务 | - | 定期或一次性定时事件 |
| 边缘计算 | 降低成本和延迟,提升用户体验 | - | 前端可处理非敏感操作的场景 |
| 有状态架构 | 状态信息存储和检索快,应用各部分易访问 | 迁移到云有挑战,扩展和容错性差 | 单服务器应用 |
| 无状态架构 | 可扩展性和冗余性好,便于管理和分析 | 增加延迟 | 现代云应用 |
8. 架构选择的决策流程
在进行云架构设计时,我们可以按照以下决策流程来选择合适的架构:
graph TD
A[明确应用需求] --> B{请求大小}
B -- 大请求 --> C[考虑API网关]
B -- 小请求 --> D[考虑应用负载均衡器]
A --> E{应用复杂度}
E -- 简单 --> F[考虑无服务器设计(简单独立功能)]
E -- 复杂 --> G{是否有特定任务}
G -- 是(如GPU依赖) --> H[考虑基于容器或服务器架构]
G -- 否 --> I{数据类型和操作}
I -- 敏感数据 --> J[考虑守门人微服务]
I -- 非敏感数据 --> K{实时性要求}
K -- 高 --> L[考虑基本CRUD API或有状态架构]
K -- 低 --> M[考虑触发或解耦微服务或无状态架构]
9. 架构实施的注意事项
在实施上述架构时,还需要注意以下几点:
-
API网关和ALB
:
- 对于API网关,合理配置模拟集成,确保前端和后端开发的并行性。同时,根据应用的请求大小和流量情况,准确评估成本。
- 对于ALB,要根据业务需求合理设置LCU数量,以平衡成本和性能。
-
无服务器设计
:
- 对于完全无服务器架构,要确保服务之间的独立性和兼容性,避免过度依赖导致的问题。
- 采用单体无服务器架构时,要注意代码的模块化和可维护性。
- 基于容器或服务器架构,要做好资源管理,减少计费空闲时间。
-
微服务架构
:
- 对于基本CRUD API,要考虑数据的一致性和弹性问题,可以结合缓存等技术提高性能。
- 触发或解耦微服务,要处理好异步通信和延迟问题,确保作业队列的可靠性。
- 守门人微服务,要严格控制访问权限,启用全面的日志记录和监控。
- CRON或定时微服务,要确保定时任务的准确性和稳定性。
- 边缘计算,要保证前端处理的安全性和数据完整性。
-
状态管理
:
- 有状态架构迁移到云时,要做好会话管理和负载均衡,避免用户体验下降。
- 无状态架构,要优化数据库查询,减少延迟对性能的影响。
10. 未来云架构的发展趋势
随着云计算技术的不断发展,云架构也呈现出一些未来的发展趋势:
-
混合架构的普及
:由于不同架构各有优缺点,未来更多的应用会采用混合架构,将无服务器、容器、服务器等多种架构结合使用,以满足复杂业务的需求。
-
智能化和自动化
:云架构将越来越智能化和自动化,例如自动调整资源配置、自动处理故障等,减少人工干预,提高效率。
-
安全和隐私的加强
:随着数据安全和隐私问题的日益重要,云架构将更加注重安全设计,如采用更高级的加密技术、更严格的访问控制等。
-
边缘计算的发展
:边缘计算将得到更广泛的应用,将计算和数据存储靠近数据源,减少延迟,提高用户体验。
11. 总结
在云架构的设计和实施过程中,我们需要综合考虑多个因素,包括请求大小、应用复杂度、数据类型、实时性要求等,选择合适的API网关、应用负载均衡器、无服务器设计模式、微服务架构以及状态管理方式。同时,要注意架构实施的注意事项,关注未来云架构的发展趋势,以构建高效、可靠、安全且成本合理的云应用。通过合理运用这些架构和技术,我们可以更好地满足业务需求,提升用户体验,推动云计算技术的不断发展。
希望以上内容能为你在云架构设计和实践中提供有益的参考和指导。在实际应用中,要根据具体情况进行灵活调整和优化,以达到最佳的效果。
超级会员免费看
1539

被折叠的 条评论
为什么被折叠?



