BuzzFeed如何从Perl单体应用迁移到Go和Python微服务

2018 年 6 月 30 日

本文要点

  • BuzzFeed 近日从一个单体 Perl 应用程序迁移到了大约 500 个使用 Python 和 Go 编写的微服务。
  • 起初,他们的路由逻辑是在 CDN 中实现的,但事实证明,这很难测试和维护。他们后来改成使用 NGINX 路由。
  • 网站路由服务被设计成在 BuzzFeed 自己的 Rig 平台上运行,这便于他们部署到他们运行的每一个 Amazon 弹性容器服务环境(ECS)(测试、过渡、生产)中的每个服务上。
  • BuzzFeed 构建了一个抽象层,让他们可以使用 YAML 配置路由服务。

2016 年,BuzzFeed 启动了一个重构项目,把使用 Perl 编写的一个单体应用程序转换成一组微服务。他们之所以这样做,主要是因为 Perl 应用程序被证明很难扩展,使 buzzfeed.com 独自服务于每月大约 70 亿次页面访问,而且,组织还要向大约 30 个不同的社交平台发布内容,包括不同的语言版本。

除了扩展问题外,BuzzFeed 发现,寻找懂 Perl 并且希望使用它开发的工程师越来越难。最后,他们希望自己能够在有了新产品想法时可以更快速地迭代。

从一个很高的层面上来说,新架构包含一个 CDN,指向一个路由服务,该服务位于 AWS 上,使用了 ECS 容器化服务

新的微服务是以Python 作为主要语言开发的,对于性能比较敏感的组件则使用了Go。BuzzFeed 的工程团队发现,这两种语言可以很好地互补,对于开发人员而言,根据需要从一种切换到另一种也相对简单。

在本文写作时,他们在AWS 上的过渡环境和生产环境中已经有大约500 个微服务。他们在分解服务时使用了听上去和 SCS 类似的东西;buzzfeed.com 的首页是一个服务,新页面是单独的服务,作者页面也是,诸如此类。

团队面临的一项挑战是把请求路由到正确的后台应用程序。他们的 CDN 提供商 Fastly 具有在边缘通过编程定义行为逻辑的能力,使用的是一种基于 C 的编程语言 VCL,工程团队最初就是直接使用 VCL 编写他们所有的路由逻辑。

不过,他们发现,随着配置越来越复杂,修改变得越来越困难,充分测试这些配置的能力愈发重要。BuzzFeed 资深软件工程师 Mark McDonnell 告诉 InfoQ:

我们在 CDN 中有大量的逻辑,只有少数几名工程师真正了解它是如何工作的。另外,CDN 还被有意锁定,因为缓存层对我们而言特别重要,我们需要防止工程师意外修改,那可能会对我们的缓存策略产生不利影响,或者会导致进入的请求被路由到错误的源服务器。

此外,Fastly 还有自己的 Varnish HTTP 加速器实现。BuzzFeed 发现,这让工程师很难启用一个本地开发环境,并通过它运行他们的 VCL 逻辑,因此,VCL 代码测试就成了问题。为此,工程团队决定实现一个新的路由服务来代替 VCL 路由,把大部分路由逻辑从 CDN 提取到一个单独的路由器微服务中。

网站路由服务被设计成在 BuzzFeed 自己的 Rig 平台上运行,这便于他们部署到他们运行的每一个 Amazon 弹性容器服务环境(ECS)(测试、过渡、生产)中的每个服务上。

对于反向代理,他们考虑了包括 HAProxy 在内的多个选项,但最终决定使用 NGINX。McDonnell 说,“我们选择 NGINX ,因为我们平台基础设施团队中的大部分人都有使用经验,所以,我们得到了 SRE 的支持,我们其中的一个卖点是,它很容易提升速度”。如你所想,向系统添加 NGINX 确实会给单个请求带来额外的延迟,但按照 McDonnell 的说法,这可以“忽略不计”。

虽然把简单易用和熟悉度作为选择 NGINX 的其中两个原因,但 BuzzFeed 还是构建了一个配置该服务的抽象层。该服务是用 Python 编写的,它会从 YAML 动态生成所需的 nginx.conf 文件。它广泛使用了 YAML 特有的特性,如“锚和别名(Anchors and Aliases)”和“合并键(Merge Key)”,据 BuzzFeed 技术博客介绍,“这让我们可以跨环境块重用配置,而且很容覆盖特定的键,不需要重复大量的配置工作。我们主要把这种方法用于‘上游’和‘超时’区域,因为我们通常会希望覆盖那些特定于环境的值。”

起初,路由服务是使用 NGINX 的开源版本构建的,但后来转到了商业版本 NGINX Plus 。按照 McDonnell 的说法,可以获得付费支持是一个原因,但团队也需要只有付费版本中才有的某些特性,尤其是 DNS 监控;BuzzFeed 的服务器区域相当复杂,那样,当 AWS 负载均衡改变 IP 地址时,NGINX Plus 能够保证 DNS 条目也更新。 BuzzFeed 技术博客上有一篇博文是这样解释的:

在 NGINX 启动的时候,它会为我们在配置文件中定义的下游解析 DNS。也就是说,它会把主机名转换成 IP(或者一组 IP,和使用 AWS Elastic 负载均衡器一样)。然后,NGINX 会缓存这些 IP,我们的问题在这里开始出现了。

你可能不熟悉负载均衡器,它们会检查多个服务器,看看它们是否健康,如果不健康,服务器会被关闭,并有一个新实例启动。我们发现的问题是,每个服务器实例的 IP 都在不断变化。如前所述,NGINX 在启动时会缓存 IP,而因为 ELB[Elastic 负载均衡器] 的原因,新进来的请求会被代理到不再有效的缓存 IP。

一种解决方案是热重载 NGINX 配置。那是个手动过程,我们不知道什么时候该那样做,因为我们无法知道服务器实例何时会停止服务。

NGINX 文档中有几个设法变通解决这个问题的选项;不过,除了一个选项外,其他所有选项都意味着我们需要重新设计我们的整个架构,因为它们不支持 NGINX 的 upstream 指令(作为配置抽象的一部分,我们对它的依赖度很高)。

允许我们利用接口设计的那个解决方案只有 NGINX Plus 提供。采用商业版本的成本是合理的:我们不需要从头重写我们的整个服务,后续我们也可以利用额外的特性(其中有一部分我们已经考虑过)。一旦切换,该解决方案只需要增加一行 resolver 指令,为缓存的 DNS 解析结果定义一个 TTL。

VCL 逻辑用于帮助 BuzzFeed 在他们推出新服务时根据用户的地理位置分类用户,那样,他们就可以从一个类似新西兰这样的小国家开始。McDonnell 解释说:

对于任何 geoip.country_code 是 NZ 的用户,他们会设置一个 X-BF-SiteRouter 头。然后,在 VCL 代码中,如果 X-BF-SiteRouter 头已经设置(取决于请求哪个路由),我们会把后端切换到 Site Router。

一旦我们满意,我们就会把服务区域扩展到 AU、GB、OC、EU、SA(南美),最终,我们会把所有东西都指向 Site Router(实际上,北美是最后一个区域)。

我们还使用了 Vary 头保证来自不同区域、还没准备好访问 Site Router 的用户不会意外从中获得缓存的响应。

迁移到新架构已经在团队生产率方面为我们带来了益处,McDonnell 告诉我们:

工程师可以根据自己的意愿自由启动服务,我们每天部署很多次。周遭有各种流行的术语,如持续集成、持续交付和持续部署,它们只有稍微的不同。最终,我们有了一个非常棒的交付管道,但是,我们特有的平台实现无法自动把变更推送到生产环境,目前我们还得手动选择,那对于我们的应用场景而言是合理的(例如,并不是我们构建的所有东西都必须自动存在于生产环境中)。

BuzzFeed 有一个富 A/B 系统,用于测试单个的“特性”,规模较大的基于 A/B 测试的上线在他们的方法中反而变得比较简单(综合运用 VCL 逻辑和 Site Router 特有的“override”配置来处理请求路由)。

新基础设施监控(以及日志聚合和分析)是使用DataDog 实现的。他们还在评估 Honeycomb.io

关于作者

Charles Humble 于 2014 年 3 月成为 InfoQ.com 编辑团队负责人,指导我们的内容创作,包括新闻、文章、著作、视频演讲和采访。在承担 InfoQ 的这个全职角色之前,Charles 负责我们的 Java 报道,并且是薪酬研究公司 PRPi Consulting 的 CTO,该公司 2012 年 7 月被 PwC 收购。他已经从事企业级软件工作将近 20 年,做过开发,当过架构师和开发经理。在业余时间,他从事音乐创作,是伦敦氛围科技舞曲团 Twofish 的三名成员之一。

查看英文原文: How BuzzFeed Migrated from a Perl Monolith to Go and Python Microservices

2018 年 6 月 30 日 14:55924
用户头像

发布了 1008 篇内容, 共 307.1 次阅读, 收获喜欢 272 次。

关注

评论

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

区块链交易所系统开发,OTC场外交易所

135深圳3055源中瑞8032

硬核系列 | 深入剖析字节码增强

高翔龙

JVM 字节码插桩 bytecode JVM虚拟机原理 字节码增强

阿里P8架构师“墙裂”推荐:Java程序员必读的架构进阶热门书籍,值得学习!

Java架构之路

Java 程序员 架构 编程语言 推荐书籍

Flink中CoProcessFunction6-7

小知识点

scala 大数据 flink

架构师训练营第 1 期第 5 周作业

业哥

详解GaussDB(DWS) explain分布式执行计划

华为云开发者社区

数据库 计划 数据

蘑菇街大牛熬夜整理的Spring MVC知识点总结(思维导图+源码笔记),免费分享文档资料

Java架构之路

Java 程序员 架构 面试 编程语言

(转)程序员的写作课

Leo

学习 前端进阶训练营 技术博客

一个优秀的程序员,不仅要会编写程序,更要会编写高质量的程序

Java架构之路

Java 程序员 架构 性能优化 编程语言

晦涩难懂的CAP,是否完全正确?

架构师修行之路

老公熬夜都要看的:从基础到进阶的Java面试题,助你2021年金三银四拿下大厂offer。

996小迁

Java 编程 架构 面试 计算机

必须收藏:20个开发技巧教你开发高性能计算代码

华为云开发者社区

性能 并发

技术实践丨手把手教你使用MQTT方式对接华为IoT平台 华为云开发者社区

华为云开发者社区

技术 物联网 mqtt

架构师训练营第五周作业

邓昀垚

极客大学架构师训练营

发挥区块链技术优势 确保食品安全

CECBC区块链专委会

区块链技术 信任机制

简约而不简单的分布式通信基石

架构师修行之路

TCP 分布式 微服务 udp

区块链钱包系统定制开发,去中心化钱包平台搭建

135深圳3055源中瑞8032

开始真正的学习吧 -- 2020-10-20

BlueVitamin

做好提醒巧防范 守好钱包防诈骗——南京移动防通讯信息诈骗志愿者服务进社区

Geek_459987

亚马逊向世界各地逾1000家慈善组织捐赠数百万件物资

爱极客侠

PLSQL 过程语言-结构化查询语言

Flychen

用Python加载数据的5种不同方式

计算机与AI

Python 数据处理

从资金荒、恒大事件看区块链技术在供应链金融上的应用价值

CECBC区块链专委会

区块链 供应链物流

央视多方视频连线演播厅系统

dwqcmo

音视频会议 集成架构 解决方案 智能硬件

架构师训练营第五周学习总结

邓昀垚

极客大学架构师训练营

合约跟单APP开发,智能合约跟单软件

135深圳3055源中瑞8032

播客有没有未来?

善宝橘

播客

法定数字货币对银行存在潜在冲击,可能是第六版的人民币

CECBC区块链专委会

数字货币 金融

USDT承兑商支付系统开发,USDT跨境支付

135深圳3055源中瑞8032

「2020年字节秋招超万人」那么程序员跳槽时,如何选择公司

Java架构师迁哥

程序员

MapReduce简介及过程详解

犟马骝

hadoop mapreduce

BuzzFeed如何从Perl单体应用迁移到Go和Python微服务-InfoQ