许多现代应用程序需要在企业规模上构建,有时甚至需要在互联网规模上构建。每个应用程序都需要满足可伸缩性、可用性、安全性、可靠性和弹性要求。在本文中,我将讨论一些可以帮助你轻松实现上述功能的设计模式。我将讨论每种模式,如何在云原生环境中使用该模式,以及何时使用何时不使用。其中一些模式并不新鲜,但在当前互联网规模的云计算世界中非常有用。
本文最初发布于 BetterProgramming,经原作者授权由 InfoQ 中文站翻译并分享。
图片来自:https://undraw.co/
以下是本文将要讨论的模式:
断路器
命令和查询职责分离(CQRS)
事件源
挎斗
BFF(Backend-for-Frontend)
Strangler
让我们开始吧。
断路器
分布式系统的设计应该考虑故障。如今,世界已经接纳了微服务,而这些服务大多依赖于其他远程服务。由于网络、应用程序负载等各种原因,这些远程服务可能无法及时响应。在大多数情况下,实现重试应该就能够解决问题。
但有时候,可能会出现诸如服务降级或服务本身完全失败等重大问题。在这种情况下,不断地重试是没有意义的。这就用到断路器模式了。
断路器,图片由作者提供。
上图展示了断路器模式的实现,其中,当服务 1 识别出服务 2 被调用时存在连续故障/超时时,服务 1 将自动断开服务 2 的调用并返回回退响应,而不是重试。
有一些流行的开源库,比如Netflix的Hystrix,可以用来非常轻松地实现这种模式。
如果你正在使用 API 网关或像 Envoy 这样的挎斗代理,那么这可以在代理层本身实现。
注意:非常重要的一点是,在断开时,要实现足够的日志记录和告警,以便跟踪在此期间收到的请求,并让运营团队知道。
你还可以实现一个半开断路器,继续使用降级服务为客户端提供服务。
什么时候使用这种模式
当一个服务依赖于另一个远程服务,而该服务在某些情况下可能会失败时;
当服务具有非常高的依赖性时(例如,主数据服务)。
什么时候不使用这种模式
当处理本地依赖时——断路器会带来开销。
命令和查询职责分离(CQRS)
对于涉及数据存储的现代应用程序来说,CQRS 是一种非常有用的模式,其基本原则是将数据存储中的读(查询)和写/更新(命令)操作分开。
假设你正在构建一个应用程序,它需要你将数据存储在 MySQL/PostgreSQL 等数据库中。众所周知,在将数据写入数据存储时,一个操作需要几个步骤——比如验证、建模和持久化——因此,典型的写/更新操作要比简单的读操作花费更长的时间。
当你使用单个数据存储同时执行大规模的读取和写入操作时,可能会开始遇到性能问题。
在这种情况下,CQRS 模式可能很有用。CQRS 模式建议对读和写操作使用不同的数据模型。该模式的一些变体还建议为这些模型使用单独的数据存储。
CQRS,图片由作者提供
注意:目前大多数 PaaS 数据库都提供了创建数据存储读副本(Google Cloud SQL、Azure SQL DB、Amazon RDS等)的能力,这让数据复制更容易实现。
如果你正在使用本地数据库,那么许多企业级数据库也提供了这种功能。
注意:现在有些人也喜欢将读副本实现为速度快和性能高的 NoSQL 数据库,像 MongoDB 和 Elasticsearch。
什么时候使用这种模式
当你考虑扩展一个需要大量读写操作的应用程序时;
当你希望分别对读和写操作进行性能调优时;
当你的读操作可以接受近实时或最终一致时。
什么时候不使用这种模式
当你构建一个常规的 CRUD 应用程序,而它不需要同时进行大量的读写操作时。
事件源
事件源是一种有趣的设计模式,它将一系列域事件存储为日志,日志的聚合视图提供应用程序的当前状态。
这种模式通常用于无法提供数据存储锁并且需要维护事件的审计和历史记录的系统——例如,酒店/会议/座位预订之类的应用程序。
事件源,图片由作者提供。
考虑用户预订或取消预订的酒店房间预订系统。在这里,你需要将预订和取消存储为一系列事件。在每次预订之前,聚合视图通过查看事件日志显示可用房间。
注意:大多数云服务提供商支持像谷歌 Pub/Sub、Azure 服务总线、AWS SQS 这样的消息传递服务。这些服务,结合强一致性数据存储,可实现此模式。
什么时候使用这种模式
当常规的 CRUD 操作不足以满足需求时;
通常适用于座位预订系统——如公交、火车、会议、电影院等——或包含购物车操作、付款等事件的电子商务系统;
当需要通过强审计和事件回放以创建应用程的当前和历史状态时。
什么时候不使用这种模式
当常规的 CRUD 操作足够满足用户的需求时。
挎斗
挎斗模式随着微服务的兴起而流行开来。在此模式中,应用程序的组件被部署到单独的流程或容器中。这有助于实现抽象和封装。
Envoy Proxy是最常用的挎斗代理之一,应用非常广泛。它有助于保持应用程序核心功能的独立性,使用挎斗来分离网络、可观察性和安全性等常见特性。
挎斗,图片由作者提供。
这种挎斗可以帮助抽象 L4/L7 层通信。像 Envoy Proxies 这样的挎斗甚至通过实现 Mutual TLS 来帮助实现更高的安全性。
你可以将其与服务网格结合使用,在各种微服务之间实现更好的通信和安全性。要想了解更多内容,可以阅读我之前的文章。
什么时候使用这种模式
当你在产品范围内面对多个异构微服务时;
当你处理遗留应用程序时,这些应用程序通常无法应对新时代的通信和安全挑战。
什么时候不使用这种模式
当你处理数量有限但需要相互通信的服务时;
小型应用程序,在这种情况下,挎斗部署可能不经济或不便于运维。
BFF(Backend-for-Frontend)
在传统的产品开发周期中,后端工程师负责创建与数据存储交互的服务,前端工程师负责构建用户界面。现在,应用程序在构建时需要同时考虑到移动端和桌面端的使用。
尽管在硬件方面移动设备和桌面设备的差距越来越小,但对于移动设备而言,连接和使用仍然是其面临的挑战。
在这种情况下,BFF 模式变得非常方便。在这种模式下,你需要为特定的前端构建/定制后端服务。
Backend-for-Frontend,图片由作者提供。
为了优化移动客户端的性能,你可能需要构建一个单独的后端服务,它使用轻量级的分页响应进行应答。
你可能还希望将此模式用于各种服务的聚合,以减少通信量。
注意:如果你现在使用了 API 网关,那么 BFF 模式可以很容易地在网关中实现,你不需要维护单独的服务。
什么时候使用这种模式
当你想为不同的客户端(比如桌面和移动客户端)提供产品/服务时;
当你想为特定类型的客户端优化响应时;
当你想减少移动客户端和各种服务之间的通信时。
什么时候不使用这种模式
当应用程序用户希望使用单个用户界面时;
当移动和桌面应用程序需要展示相似的信息并提供相似的功能。
Strangler
如果你所在的组织正在走向应用程序现代化,则必须使用 Strangler 设计模式。Strangler 设计模式主张在遗留应用程序和新应用程序之上创建一个 Facade,为用户提供一个抽象的视图。
Strangler,图片由作者提供。
此模式将用户与迁移活动解耦。
注意:在传统的 IT 组织中,如果要从一个 ERP 迁移到另一个 ERP,这种模式会非常有用。如果你使用的是 API 网关,那么在网关代理中实现它就更容易了。
你需要决定是在迁移结束时保留 Facade 还是删除它。
什么时候使用这种模式
当你迁移或更新一个复杂的、依赖度高的应用程序(如 ERP 迁移)时。
什么时候不使用这种模式
如果迁移很简单,那么直接替换是更好的选择。
英文原文链接:Modern-Day Architecture Design Patterns for Software Professionals
评论