开发者生态
morning
硬停止规则:从 3 个 HCM 单体应用到 120 个领域微服务
摘要
为什么资金问题其实并不是真正的资金问题 2021 年 5 月,我和我在 Paycor(一家人力资本管理平台,现已被 Paychex 收购)的团队做了一个决定,那个决定最终塑造了我们平台未来五年的发展方向。我们停止了对单体架构的改动。 当时共有三个单体应用:规模庞大、支持多租户,并且与我们负责的人力资本管理(HCM)产品的业务边界深度交织。我们早就想把它们拆分了。我们研究过 扼杀者模式 ",也起草过...
Azure
APIM
Redis
Service
API
为什么资金问题其实并不是真正的资金问题
2021
我和我在
Paycor
一家人力资本管理平台
2026-08-01
1 阅读
约10分钟阅读
作者:Prashanth Pasham
字号:
为什么资金问题其实并不是真正的资金问题 2021 年 5 月,我和我在 Paycor(一家人力资本管理平台,现已被 Paychex 收购)的团队做了一个决定,那个决定最终塑造了我们平台未来五年的发展方向。我们停止了对单体架构的改动。 当时共有三个单体应用:规模庞大、支持多租户,并且与我们负责的人力资本管理(HCM)产品的业务边界深度交织。我们早就想把它们拆分了。我们研究过 扼杀者模式 ",也起草过一份为期多年的迁移计划。 但这些计划始终未能获得资金支持。每个季度,迁移提案都要与能带来收入的功能需求竞争,结果总是败下阵来。 于是我们尝试了另一种做法。不再单独做项目,而是制定了一条简单的规则:每个新功能、每个 Bug 修复、每次功能增强——任何原本会涉及单体应用的改动,现在都要拆分出来,创建一个新的领域服务。 这种迁移将作为常规路线图工作的副产品自然发生,所需经费与其他所有工作共用同一预算。这是一种基于拉动机制的迁移。 成本是切实存在的。在单体架构中原本只需要四个小时的变更,现在需要六个小时。我们将这部分成本分摊到数百个用户故事中,而不是试图将其打包成一项极有可能无法获批的资本支出申请。 目前,我们在 Azure 上运行着 120 多个领域微服务,整个迁移过程实现了零停机。那三个单体应用仍然在运行,仅承载着无人需要改动的极小一部分功能,其余所有业务都已经完成迁移。 本文将详细介绍该方法的实际运转情况:支撑这一过程的平台投资、我们被迫做出的架构选择、确保成本可控的成本优化措施,以及如果今天重新开始,我会采取哪些不同的做法。 解锁三大平台,让基于拉动的迁移成为可能 基于拉动的迁移——即每次产品驱动的代码变更都会独立拆分出一个服务,而不是让某个独立的程序按照自己的时间表进行迁移——从原理上讲似乎很简单。但在实践中,这取决于三项平台投资。因为我们刚开始时并不具备这三项条件,所以在最初大约一个季度的时间里,迁移过程相当艰难。一旦这三项条件都到位,迁移工作便变得顺理成章。 Azure 上的按域订阅 首次投资是结构性的。我们采用了“每个产品领域一个订阅”的模式。考勤系统有一个独立的订阅,薪资系统有一个独立的订阅,报表、排班、集成等功能也各自拥有独立的订阅。 这在纸面上听起来有些繁琐。但在实际应用中,它为我们带来了三项超出预期的关键收益。 首先是成本归属。考勤订阅的账单每月都会精确地显示该领域在云资源上的具体支出。我们不会将共享云成本在不同的领域之间进行分摊。每个团队都能看到自己的账单,并对此负责。 这种架构还实现了影响范围隔离。无论是配置错误、脚本失控,还是过于严格的 IAM 新策略,所有问题都局限在该域的订阅范围内。在过去的五年中,我们从未发生过因配置变更导致的多域服务中断事件。 此外,还有第三个较为隐性的效果:团队责任感。当工程师能够看到自己的资源消耗和平台占用情况时,他们在代码审查中会做出不同的决策。虽然这是一个隐性的结果,但已经在数据中体现出来了。 是部署模板让订阅模式真正变得可用。当 DevOps 团队部署新服务时,该模板包含 Azure Kubernetes Service(AKS) 命名空间、数据库、Service Bus 和 Event Hub 配置、Key Vault、可观测性钩子以及网络配置。过去需要通过工单进行处理的、耗时两到四周的部署工作,如今已缩短为几分钟的自助服务。 这是此次迁移带来的最大的行为变化。如果搭建新服务需要三周时间,工程师们就绝不会为此支付 50% 的前期成本;但如果新服务只需十分钟就能上线,他们就会愿意支付这笔钱。 APIM 作为路由衔接层 第二项投资是运维层面的。我们在预计要迁移的每个端点前都部署了 API 管理(APIM)。 单体架构的端点和新的域服务都可以通过同一路径向 APIM 注册。流量分流由部署配置决定,而非客户端变更。我们可以先将 1% 的流量导向新服务,观察一天,然后再逐步增加比例。 客户端完全不知道正在进行的切换。移动应用毫不知情,合作伙伴的公共 API 调用者也毫不知情。APIM 负责管理接口规范,新服务则实现了该规范。流量在我们指定的时间点顺利完成了切换。 通过 Azure 应用配置实现功能开关,并使用 Redis 缓存封装器 第三项投资属于战术性投资。我们需要一个生产环境可以信赖的功能开关层。 Azure App Configuration " 具备满足此需求的语义机制。但在我们的流量规模下,每次请求都调用该功能会带来高昂的成本。因此,我们构建了一个轻量级封装层,将值缓存到 Redis 中,并设置了比较短的 TTL 以及显式的失效触发机制。从应用程序的角度来看,功能开关检查等同于一次 Redis 查询,这几乎不产生任何成本。 该封装层主要承担两项任务。第一项是渐进式发布:先为 1% 的租户开启某个功能开关,观察指标,再逐步扩展。第二项是近乎瞬时的回滚。如果某个版本出现异常,在 App Configuration 中切换该功能开关,几秒内即可传播到每个节点。 渐进式发布是大多数工程师关注的部分。而近乎瞬时的回滚,则曾不止一次地拯救了我们。 图 1:解锁三大平台,使基于拉动的迁移成为可能(图片由作者制作) HCM 服务水平目标(SLO)与考勤系统数据采集路径 在人力资源管理(HCM)领域,有两个服务水平目标(SLO)几乎影响着我们做出的每一项架构决策。 第一个是针对考勤系统的。当按小时计薪的员工打卡上下班时,我们绝不能丢失该条记录。对于本就入不敷出的员工来说,一次打卡记录的丢失就意味着一笔工资的损失。这方面绝不容许有任何误差。 第二个是关于薪资系统的。一旦到了薪资处理时间,系统就必须正常运行。在薪资处理窗口期内发生系统停机,绝非单纯的不便,而是涉及合规报告的重大事件。 这两项 SLO 推动我们做出了一系列具体的架构承诺。 十个摄入来源,一份持久记录 该考勤系统必须支持从大量设备和渠道接收打卡数据。目前,我们从以下十个来源采集数据: 员工自助服务门户工作现场的实体考勤机休息室的自助终端面向零售和餐饮服务客户的销售点系统现场运营中的 iPad 应用程序iOS 和 Android 平台上的移动应用集成所使用的合作伙伴公共 API基于电话的系统管理员在管理界面中手动录入的考勤记录针对特定垂直领域的边缘设备 每个数据源都有其独特之处。远程站点的物理时钟连接不稳定。合作伙伴 API 设有我们无法控制的速率限制。POS 系统会在业务淡季批量提交数据。移动应用会在离线时将数据放入队列,并在恢复连接后进行重放。 无论通过何种渠道,每个数据源的首要任务都是将打卡数据写入 Service Bus 队列。随后,该打卡数据会从队列写入表存储,成为持久化记录。只有在持久化写入成功后,我们才会向数据源发出确认。 这一流程(进入队列、写入持久化记录、确认)是 SLO 的核心。一旦数据拥有了持久化记录,我们就能从任何下游故障中恢复。在拥有持久化记录之前,我们无法确认该数据已经被接收。 Event Hub 扇出 根据持久化记录, Azure Event Hub " 会向四个下游消费者广播数据: 打卡处理:应用策略并计算工资事件。记录数据库:作为打卡数据的权威来源。报表:用于分析和
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱