我构建的每个服务都会死
Source: Dev.to
这正是关键所在。我是 Ontime Payments 的高级软件工程师,这是一家让员工直接从工资中支付账单的金融科技创业公司。我们有意构建了一个模块化、事件驱动的无服务器架构,且其中的每个服务最终都预计会被替换。虽然有些服务不会被替换,但我们仍然按会被替换的前提来构建,这影响了所有的设计。
无服务器架构
无服务器拥有众所周知的优势:无需管理服务器、无需打补丁、计算资源会自动弹性伸缩。真正的转变不仅在于托管基础设施本身;更在于当你将小而专注的函数、事件驱动的通信以及“任何组件在需要时都可以被终止并替换”的理念结合在一起时,会产生的效果。
如果你对基础概念不熟悉:用户访问 API Gateway,触发一个 Lambda 函数。该函数完成自己的任务(例如处理支付),向用户返回响应,并向 EventBridge 发送一个事件。
EventBridge 位于中间,根据你定义的规则路由事件。支付函数并不知道仓库操作或电子邮件收据的任何细节。它只会宣布自己完成了什么,其他服务则监听并相应地执行操作。生产者并不知道有多少消费者在监听,也不知道它们是谁。每个函数只做一件事。这种小组件与松耦合的组合正是让其他一切成为可能的关键。
替换服务
我们有一个监控服务,最初很简单,但随着系统扩展,逐渐变成了一堆条件逻辑的混乱。每增加一个新功能,就会出现更多的边缘情况、更多的设置需求、以及更脆弱的代码。因此我们从头构建了一个 v2。
这违背了常见的建议(“永远不要重写,始终迭代”)。因为原始服务体积小且专注,重新开始实际上比不断打补丁要省事。范围也在可控范围内。
两个版本并行运行,类似于在从单体应用迁移时使用的 strangler fig 模式。1 它们从 EventBridge 读取相同的事件。触发这些事件的服务无需做任何修改;它们根本不知道有一个消费者还是两个(甚至十个)在监听。我们验证 v2 正常工作后,就关闭了 v1。系统的其余部分没有感知到任何变化。
这并不是一个特殊的案例。我们曾合并模块、拆分模块、替换整套服务。早期的邮件发送服务被并入一个更广泛的通知模块,统一处理 Slack、Webhook 和邮件。旧的服务直接关闭。这是我们日常的工作方式,而不是某种英雄式的迁移努力。收益并不是某个瞬间的突变,而是所有事情、始终都变得更容易。
心态与灵活性
很多开发者试图通过预测来实现灵活性,从第一天起就为每一种可能的未来需求进行构建。这并不是灵活性;这只是把你的僵硬范围进一步扩大。
我们所发现的灵活性并不是来自提前规划,而是来自架构本身。Lambda 鼓励小而专注的组件。事件驱动的设计让它们彼此隔离。每个部件都足够小,易于理解;足够专注,便于替换;足够隔离,以至于替换它时不会产生连锁反应。
在架构层面严肃对待 keep‑it‑simple‑stupid 哲学2,意味着我们只为当下的需求构建,而不是为所有可能的未来构建。这释放了思考能量,提高了部署速度,也避免了为可能永远不会出现的情景而过度复杂化。当某个服务不再符合需求时,我们会将其淘汰,并用符合需求的东西替代。由于我们的构建方式,这种替换比起其他情况下要容易得多。
结论
每个服务都会终止。这正是系统得以运行的原因。
人工撰写,AI 辅助。
想了解更多关于使用 AWS Lambda 和 EventBridge 的事件驱动无服务器架构,请参阅 AWS 关于事件驱动架构的文档。