AICon 上海站|90%日程已就绪,解锁Al未来! 了解详情
写点什么

为什么 Segment 会从微服务退回单体架构?

  • 2018-07-18
  • 本文字数:3098 字

    阅读完需:约 10 分钟

近年来,我们发布了很多文章介绍企业向微服务迁移的成败经验。最近, Segment 的 Alexandra Noonan 写了一篇文章,讲述了他们从单体架构迁移到微服务,之后又退回单体应用的经历。文中 Alexandra 具体介绍了他们从原来的简单架构迁移到微服务的过程:

我们原来有个 API 负责拦截事件并将它们转发到一个分布式的消息队列中。这里的一个事件指的是由网页或移动应用生成的,包含用户与用户动作信息的 JSON 对象。当队列中的事件被消费后,系统会检查用户设置来决定接收事件的目标。(……)之后事件被逐个发送到每个目标的 API。这样的流程很合理,因为开发者只需要将事件发送到 Segment 的 API 这一个目标即可,无需创建几十个集成。

如果事件交付失败,就会被系统重新加入队列,也就是说有时工作者进程要一边发送新的事件,一边尝试重新发送之前失败的事件。这样会导致所有目标都出现延迟,Alexandra 解释说:

为解决最紧迫的阻塞问题,团队为每个目标各创建了一个独立的服务和队列。这一新架构包括一个新的路由进程,它会接收入站事件并向每个选定的目标分发一份该事件的拷贝。现在如果某个目标出现问题,只有它自己的队列会回溯,不会影响其它目标。这一微服务化的架构将各个目标独立开来,这样当某个目标又出现常遇到的问题时就会非常有用。

文章之后写到,Segment 的开发团队一开始将所有代码存放在一起,但这引发了许多问题:

最大的麻烦在于,只要一个测试崩溃,那么所有目标的测试都会失败。当我们试图部署一项改动时,我们必须先费劲修复崩溃的测试,就算改动与一开始的变动毫无关联也得这样做。为了解决这个问题,我们决定将代码拆分到每个目标各自的存储库里。

这样一来开发团队的灵活性的确改善了许多。然而随着目标数量的增加,存储库的数量也在同步增长。为了让开发者免受维护这么多代码库的麻烦,Segment 团队创建了许多共享库,存放所有目标通用的变换和功能。这组共享库大大减轻了他们维护工作的压力。但这个措施也有不太容易发现的负面影响:向共享库更新并测试改动会花费大量时间,还会增加破坏无关目标的风险。最后这些库开始分裂为不同的版本,各自不统一,引发了之前没有想到的一个问题:每个目标的代码库都会依赖不同版本的共享库。Alexandra 承认,他们当时可以开发工具来自动将改动更新到这些库中,但那时他们又遇到了这个微服务架构产生的一些新问题。

新出现的问题是,每个服务都有自己的负载模式。有些服务一天处理几个事件,有的服务每秒就能处理几千个。如果目标只处理很少的事件,工作者线程就得在出现负载问题时手动扩展服务以满足需求。

他们的系统集成了自动扩展能力,但因为每个服务都需要指定 CPU 和内存资源分配,调整自动扩展的设置“更像玄学而非科学”。如前所述,每次存储库的数量增长时他们都要增加目标,最后团队平均每月要增加三个目标,当然还要加上更多的队列和服务。

2017 年初, Segment 的一个产品的核心部分使我们达到了峰值负载。当时的情况下我们好像在从微服务的大树上摔下来,一路撞上了所有的树枝。我们这个小团队非但没有提升效率,反而陷入了愈加复杂的泥潭。这个架构的核心优势都成了负担。我们的速度暴降,故障率却在暴增。(……)于是,我们决定回退一步,重新考虑整个流程。

文章最后 Noonan 回顾了他们如何摆脱这个微服务架构,其中他们还开发了 Centrifuge 来替换所有独立的队列,将所有事件都发送到一个单体服务上。他们还将所有目标的代码都迁移到一个存储库里,不过这一次新增了一些代码管理的规则:所有目标都要使用同一个版本,每次更新时同步更替到新版本。他们再也不用操心各个独立版本之间的差异了,因为所有的目标都在使用一个版本,以后也是如此。对于开发者来说,管理越来越多的目标所花费的时间减少了,风险也降低了。

Noonan 的文章还写了很多内容,都是关于他们退回单体服务的经历。感兴趣的读者应该去仔细读一下,文章里面有很多架构细节、关于存储库架构的思考和建立弹性测试集的方法。最后,团队将回退的好处总结如下:

2016 年时我们还在使用微服务架构,我们为共享库带来了 32 项改进。而仅仅今年到现在我们就做出了 46 项改进。过去半年来我们为库带来的改进比 2016 年全年都多。因为所有的目标都处于同一服务内,我们可以很好地搭配 CPU 密集型服务和内存密集型服务,所以扩展服务以满足性能需求变得非常容易。更大的工作者池能负载更多内容,所以我们不再需要将处理少量负载的目标挂起到页面了。

不过这个架构回退过程也有一些负面影响,包括:隔离错误变得更困难(一个目标的错误导致目标崩溃,结果会传染到所有目标);升级一个目标的版本可能会破坏其它一些目标,于是后者也需要升级。Noonan 在文章最后写下了诚恳的总结:

在微服务和单体架构之间做选择时,要注意它们各自都有自己需要考虑的因素。我们的架构中有些部分是微服务表现更出色,但服务端的目标迁移到微服务后的一系列麻烦是一个很好的教训,证明这一流行趋势在某些情况下能对生产力和性能有多大负面影响。结果对于我们来说,单体架构才是最终解决方案。

其实他们关于微服务的某些看法是很眼熟的。今年早些时候我们报道说,ThoughtWorks 根据观察认为微服务尚未进入普及周期。当时的报道写到:“主要原因之一是很多组织并没有为微服务做好准备,他们缺少一些关于运营和自动化的基础实践”。此外, Jan 在另一篇文章中总结了多年来微服务迁移的失败案例。Berico 科技的首席软件工程师 Richard Clayton 提到了他们当时遇到的一个问题:

在不同服务之间共享通用功能代码,以消灭各个服务中的重复功能的努力却带来了巨大的负面影响,最终导致了大规模回退。

回到原文,有很多关于这个话题的讨论,比如 Hacker News Reddit 上的这些;有些讨论者认为与微服务无关的一些因素可能导致了这些问题。比如,有些评论指出 Noonan 的文章并没有引用 CI,只有 CD,起码这是一个奇怪的组合。还有评论认为不止微服务会引发这些问题,所有的分布式系统都是一个样。关于这一点我们之前也提到过,有人使用 SOA 时有过类似的经验:

我曾在一个类似的代码库中工作过,那时他们管它叫 SOA,云还没开始流行。对服务的每次调用都会启动一个完整的服务实例。我想我们应该强制将网络延迟规定为架构设计的要素之一。

有趣的是很多讨论串谈到了微服务中数据上下文的问题。这个话题我们探讨过很多次,这也是微服务反对者的主要论据之一。HackerNews 的一条评论举例说:

比这还糟呢。据我观察多数微服务架构根本就没考虑一致性(“我们才不要乱七八糟的事务!”),盲目地随大流还乐在其中。我搞不懂为啥子人们会觉得,把软件模块拆分开来然后用缓慢不可靠的网络和弱爆的手动连接 REST 处理串起来,就能神奇地让架构面目一新哩?我觉得人们产生这种生产力幻觉的原因是:”我把这些都搞定啦,现在我也有一套’管它是什么即服务‘的先进玩意儿喽!看看那酷毙的数据面板上闪烁的小绿灯吧,我们可是为了它干了好几个月呢!“

另外,为微服务定义域是多年来我们一直强调的微服务部署关键环节。有一篇 PPT 介绍了如何使用 DDD 解构单体应用,Reddit 的一个讨论串也谈到了这一点:

建立一个出色的微服务架构是很难的。我现在觉得关键在于恰当地分隔你的域,当系统进化时持续关注这一层面。微服务并不像它的名字那样,它不必非得那么小,但是要搭配适合这个架构的元素。很多人的失败正是因为忽视了这一点。

其他人怎么看?比如说,Segment 的微服务架构出现的问题能否用其它方式解决,无需退回单体应用?或者一开始的单体架构是否有办法进化得更好,解决原来的问题,而无需切换到微服务?

查看英文原文: Why Segment Returned to a Monolith from Microservices

感谢冬雨对本文的审校。

2018-07-18 06:295989

评论

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

从零学习SDK(3)如何安装和配置SDK

MobTech袤博科技

“信创”滚滚而来,私有化或将迎来第二春

BeeWorks

TiCDC 源码阅读(五)TiCDC 对 DDL 的处理和 Filter 解析

TiDB 社区干货传送门

文盘Rust -- 用Tokio实现简易任务池

TiDB 社区干货传送门

开发语言

企业数字化升级迫在眉睫,瓴羊Quick BI工具应运而生

夏日星河

堡垒机厂商都是大企业吗?你比较推荐哪家?

行云管家

网络安全 等级保护

Stable Diffusion:一种新型的深度学习AIGC模型

GPU算力

Flink MongoDB CDC 在 XTransfer 的生产实践|Flink CDC 专题

Apache Flink

大数据 flink 实时计算

NFT交易平台商城系统开发技术

薇電13242772558

NFT

5 大手段,打造单一可信源代码托管平台|极狐GitLab DevSecOps 助力 SLSA 落地之源代码篇

极狐GitLab

DevOps DevSecOps 源代码 安全审计 SLSA

四种常见服务限流算法解析

做梦都在改BUG

值得一看!阿里内部“M9”级别全彩版分布式实战笔记

做梦都在改BUG

Java 架构 分布式 分布式事务 微服务

瓴羊Quick BI国产数字化智能工具口碑怎么样?30天免费试用

小偏执o

知行合一!AI大模型与算法二三事

深数

深度学习 科普 数字化 NLP 大模型 LLM

一文彻底搞懂Raft算法,看这篇就够了!!!

做梦都在改BUG

高频面试:如何解决MySQL主从复制延时问题

做梦都在改BUG

Java MySQL 面试 主从复制

GitHub已开源—在国内外都被称为分布式理论+实践的巅峰之作

做梦都在改BUG

Java 数据库 分布式 系统设计 设计数据密集型应用

开源即时通讯IM框架MobileIMSDK的微信小程序端开发快速入门

JackJiang

TiCDC 源码阅读(六)TiCDC Puller 模块介绍

TiDB 社区干货传送门

快手基于 Apache Flink 的实时数仓建设实践

Apache Flink

大数据 flink 实时计算

APP频繁改版惹人烦?火山引擎VeDI来帮忙

字节跳动数据平台

数字化 企业数字化 企业号 4 月 PK 榜 APP改版

MySQL架构与SQL执行流程

做梦都在改BUG

Java MySQL 数据库 SQL执行流程

TiDB损坏多副本之有损恢复处理方法

TiDB 社区干货传送门

集群管理 6.x 实践 TiKV 底层架构

TiCDC 源码阅读(七) TiCDC Sorter 模块揭秘

TiDB 社区干货传送门

堡垒机主流品牌有哪些?如何选择?

行云管家

堡垒机 IT运维

tiup cluster display 执行流程代码详解

TiDB 社区干货传送门

实践案例 集群管理 故障排查/诊断 安装 & 部署

瓴羊Quick BI连续入选魔力象限ABI报告,实至名归

流量猫猫头

阿里大佬倾情力荐:Java全线成长宝典,从P5到P8一应俱全

三十而立

Java java面试

ByteBase是什么,他怎么和tidb结合提高工作效率的

TiDB 社区干货传送门

实践案例

为什么Segment会从微服务退回单体架构?_DevOps & 平台工程_Mark Little_InfoQ精选文章