写点什么

Agoda 的非常规客户端优先迁移:从 GraphQL 单体架构到微服务架构

作者:Eran Stiller

  • 2024-12-19
    北京
  • 本文字数:3184 字

    阅读完需:约 10 分钟

Agoda 的非常规客户端优先迁移:从 GraphQL 单体架构到微服务架构

Agoda 最近描述了它们从单体 GraphQL API 转向微服务架构的非常规方法。与侧重于优先拆解服务器端组件的传统方法不同,Agoda 采用了客户端优先的策略,使用一个内部智能编排器库来使其客户端应用程序准备好并行处理单体和微服务。


在服务器迁移之前,Agoda 优先考虑让客户端准备好处理单体和微服务,从而降低风险和所需的协调工作。Agoda 的助理开发经理 Numan Hanif 告诉 InfoQ:“这种方法最大限度地减少了中断,使我们的团队能够更好地控制整个堆栈,并使架构更好地与敏捷和现代开发原则保持一致。”


打破单体架构,拆分 GraphQL 单体架构 (来源)


内部智能编排器(Smart Orchestrator)是 Agoda 客户端优先迁移策略的关键组成部分,旨在在迁移期间将客户端应用程序与后端连接起来。它充当动态路由层,根据配置将请求定向到单体 GraphQL API 或新部署的 微服务。Agoda 的工程师更喜欢使用这种方法,而不是使用 Apollo Federation,后者与奈飞(Netflix)处理这种情况的方式相似。


发布与单体架构相同的接口允许客户端应用程序无需任何修改即可运行,从而减少了迁移过程中进行大量更改的需要。这种设置确保了客户端应用程序可以处理混合后端环境,为并行微服务开发奠定了基础。


智能编排器(Smart Orchestrator)根据配置路由客户端查询(来源)


除了路由之外,智能编排器(Smart Orchestrator)还自动管理模式更新和映射,支持迁移的增量特性。最初,所有模式都指向单体,但随着域的拆分,编排器更新了映射,将查询路由到正确的微服务上。


Agoda 以增量方式执行向微服务的迁移。每个新创建的微服务都经过了严格的单体测试,以验证数据的正确性,确保在转换客户端流量之前,两个系统的响应相匹配。此外,Agoda 还实施了一个准确性测试系统,在增量部署期间不断比较单体和微服务的输出,以进一步验证迁移。


Agoda 采用了一种自动化的数据驱动方法,在其 100 个应用程序 Git 存储库中分析和准备 GraphQL 查询,以确保在迁移过程中客户端准备就绪。使用生产数据,Agoda 根据域之间相互依赖的程度将查询分为简单、中等和复杂类型。


“拆解”跨域查询是 Agoda 迁移的关键一步。简单的查询不需要更改,而 Agoda 工程师将中等查询拆分为每个域单独的独立请求,并在客户端上合并结果。涉及紧密耦合嵌套域的复杂查询,当一个查询依赖于另一个查询的结果时,通常需要顺序执行,因此需要更广泛的重组。


“拆解”复杂查询(来源)


在拆分单体架构的同时,Agoda 专注于将现有代码原封不动地迁移到新的微服务中,从而导致了旧的技术问题转移到了新的微服务中。例如,Hanif 告诉 InfoQ,“Agoda 遇到了诸如缺少客户端速率限制等问题,这经常影响我们的运营。”他说,事后看来,“为了更好地实现这种平衡,我们应在迁移过程中实施重构实践,确保迁移后的架构更清洁、更高效。”


InfoQ 在采访 Hanif 的过程中,谈到了 Agoda 的微服务迁移、使用的方法以及吸取到的教训。

InfoQ:你能详细介绍一下你们决定从单体架构迁移到微服务架构的原因吗?哪些特定的增长指标或痛点是启动这一迁移的转折点?


Numan Hanif:供应商管理系统由一个由 7 人组成的专业工程团队管理,监督 70 多个通过 GraphQL、gRPC 和 REST 等多个接口交互的客户端服务。这个单体系统在处理重要流程方面至关重要,包括通过该单体系统进行预订确认。


在这个单体系统中,我们的平均变更交付周期(Agoda 使用的开发人员体验指标)环比增长了 12%,平均每月创建了 40 个合并请求(MR)。我们广泛的测试环境包括 9200 个单元和集成测试,这些测试大约需要一个小时才能运行完,并在计划运行中实现约 73% 的稳定性。


单体架构的设置还严重依赖于各种基础设施组件,并且难以管理不相关的域,从而导致了架构的复杂性。由于每季度积压 210 张操作票据和高昂的运维开销,以及知识孤岛和庞大的代码库,学习曲线很陡峭。


这些问题凸显了可扩展性解决方案的必要性,使得微服务成为增强该系统开发过程中的可管理性、可扩展性和敏捷性的理想选择。

InfoQ:你们是否遵循了任何特定的方法或框架来定义每个微服务的边界,比如领域驱动设计(DDD)或类似的实践?


Hanif:我们没有采用领域驱动设计(Domain-Driven Design,DDD)作为我们微服务边界的默认框架,而是根据我们的具体需求和 GraphQL API 的独特方面开发了一种定制方法。我们从自低而上的方法开始,分析数据库模式,并通过标记将表分类到特定的域中。这提供了一个与我们的数据管理模式相一致的基础结构,确保了识别服务边界的一致基础。


标记了表之后,我们将每个 GraphQL 端点与相应的表域对齐,以保持跨数据和服务边界的一致性。虽然 75% 的 GraphQL 端点域标记起来很简单,但剩下的 25% 却带来了挑战,因为它们涉及存储过程从多个域访问表的复杂模式。这种复杂性需要进一步的改进,以确保内聚的服务结构与我们的架构目标相一致。


我们的流程与 DDD 共享元素,例如将服务与业务功能对齐,但不同之处在于它是基于数据驱动、自底而上的方法。与自顶而下、领域专家主导的 DDD 方法不同,我们专注于现有的数据结构,并使用领域标记来解决 GraphQL 的独特挑战。这使我们能够创建连贯且功能一致的微服务,同时解决基础设施的操作复杂性。

InfoQ:是什么促使你们采用“客户端优先”的迁移方法?这一策略是否是基于以往的经验、理论优势或从以往项目中吸取的教训?Agoda 现有的架构或团队结构中是否存在任何特定的挑战,使这种方法特别适用?


Hanif:采用“客户端优先”的方法迁移到微服务的决定受到了理论和实践经验的影响。最初,我们考虑使用单体作为客户端通信的路由器,但这与我们实现真正的垂直(客户端数据库)所有权的目标相冲突。路由器最终将成为一个软单体,使长期架构变更变得复杂,并保持集中控制。这一见解强调了需要采取更分布式的策略。


过去采用服务器优先迁移方法的经验凸显了几个挑战,包括由于客户端迁移延迟而导致的迁移时间过长。这些瓶颈阻碍了我们完全停用单体架构的能力,并暂时推迟了微服务架构带来的好处。这些经验教训强调了首先让客户端做好准备的重要性,确保它们能够处理后端更改并促进无缝迁移的重要性。


客户端优先策略旨在通过允许后端开发与客户端准备活动同时进行来减少与外部团队的协调工作。这种方法最大限度地减少了中断,使我们的团队能够更好地控制整个堆栈,并使架构更好地与敏捷和现代开发原则保持一致。它还解决了诸如主动拼接查询、实现并行开发和减少依赖性之类的挑战,考虑到现有体系结构的复杂性,这一点尤其有益。

InfoQ:智能编排器(Smart Orchestrator)客户端库是内部构建的,还是你们根据需要调整了现有的工具?在创建和维护它的过程中,有哪些主要的挑战?对于处理 GraphQL 模式和路由的复杂性,你们是否发现了一些必要的特定特性?


Hanif:智能编排器(Smart Orchestrator)客户端库是内部开发的,用于解决现有解决方案无法满足的特定需求。这一决定允许使用定制工具,在不改变客户端接口的情况下,有效地管理跨微服务的模式更新和请求路由。自动模式映射更新等关键功能对于处理 GraphQL 的复杂性至关重要,可确保与现有客户端应用程序的无缝集成,同时可以避免嵌入式业务逻辑。


开发智能编排器(Smart Orchestrator)带来了挑战,每当迁移过程中出现问题时,都要用新的库版本更新多个存储库,这需要仔细的协调和测试。此外,在生产环境中启用 GraphQL 自检查询是至关重要的,但通常会由于安全和性能问题而受到限制。通过应对这些挑战,我们确保库始终是轻量级的,同时有效地支持跨域查询并适应我们的架构需求。

作者介绍


Eran Stiller 是澳大利亚墨尔本的首席软件架构师。作为一名经验丰富的软件架构师和首席技术官,Eran 设计、实施和审查了跨多个业务领域的各种软件解决方案。Eran 在软件开发领域拥有多年的经验,并有着丰富的公开演讲和社区贡献记录。


查看原文链接:

https://www.infoq.com/news/2024/11/agoda-graphql-microservices/

2024-12-19 08:0021236

评论

发布
暂无评论
发现更多内容

Nacos源码分析(一)之线程池的巧妙设计,可以薅到自己的项目里

刘祥

SpringCloud Alibaba

终端常用快捷键

刁架构

终端 快捷键 iterm2

如何在 Python 中反转字符串?

Ethereal

融云 IM +RTC 重磅优惠上线!15 天免费体验,1 年服务买一赠一

融云 RongCloud

千字带你了解什么是 RPC 协议

踏雪痕

RPC 3月程序媛福利 3月月更

iuap助力澳洋集团打造主数据管理平台

用友BIP

用友 用友iuap

云原生网络利器--Cilium 之 eBPF 篇

Daocloud 道客

云原生 ebpf cilium

阿里云神龙AI加速引擎帮助vivo将训练性能提升30%-70%

阿里云弹性计算

AI gpu 神龙架构 加速引擎

持续集成容器篇:Docker与自动化打包

Docker 架构 持续集成 jenkins 持续交付

智能家居市场白热化,小程序助力生态合作新模式

Speedoooo

小程序生态 智慧小区 小程序容器 智慧家居 智慧物业

CVE-2022-22947 远程代码执行漏洞复现分析

网络安全学海

黑客 网络安全 信息安全 渗透测试 WEB安全

网络协议之:socket协议详解之Unix domain Socket

程序那些事

socket Netty 程序那些事 3月月更

智能问答机器人

DS小龙哥

智能问答机器人 3月月更 智能对话机器人

手绘流程图,教你WSL2与Docker容器无缝互相迁移

华为云开发者联盟

Docker 容器 WSL2 迁移

实用机器学习笔记二十八:迁移学习

打工人!

学习笔记 迁移学习 机器学习算法 3月月更

如何设计良好的技术项目文档结构

老张

项目管理 交付质量

创建 Node.js 视频流应用之后端

devpoint

node.js Video Express 3月月更

融云获 CSDN 技术影响力之星评选「年度技术品牌奖」

融云 RongCloud

使用基于 WebRTC 的 JavaScript API 在浏览器环境里调用本机摄像头

汪子熙

JavaScript 前端 WebRTC 摄像头 3月月更

Python 递归函数返回值为 None 的解决办法

AlwaysBeta

Python 递归

在线MySQL,SQL Server建表语句生成JSON测试数据工具

入门小站

工具

如何捕获和分析 JavaScript Error

喀拉峻

前端

WMS系统与ERP仓储管理的差异

源字节1号

开源 后端 前端开发 WMS系统 ERP系统

欧拉的奇异之旅·共赴开源时代

白洞计划

聊聊 Pulsar:编译 Pulsar 源码并搭建源码环境

老周聊架构

云原生 Apache Pulsar 3月月更

兴业+民生上岸面试经验分享

暖蓝笔记

3月程序媛福利 3月月更

图解|从根儿上理解MySQL的索引

蝉沐风

MySQL 索引 B+树

Java基础重要面试题(二)

逆锋起笔

java面试 java基础 3月月更

无影云电脑支持企业快速实现居家办公

阿里云弹性计算

远程办公 数据安全 无影云电脑

确保数据中心物理安全的五种方法

Ethereal

对微博系统中“微博评论”的高性能高可用计算架构的一点思考

晨亮

「架构实战营」

Agoda 的非常规客户端优先迁移:从 GraphQL 单体架构到微服务架构_微服务_InfoQ精选文章