写点什么

我们为什么停用微服务?

  • 2020-05-29
  • 本文字数:3937 字

    阅读完需:约 13 分钟

我们为什么停用微服务?


在 Botify,我们工程团队的核心价值观之一是 ownership。我们赋予工程和产品团队自主权以及灵活性,让它们拥有自己的项目并完成这些项目。然而,随着我们在更大的技术栈上工作,团队规模也越来越大,我们开始遇到一些关于如何共享工作成果的问题。


2016 年年底,我们想赋予工程师和产品经理更多的 local ownership,从而能快速轻松地将他们的产品和技术栈投入使用。为此,我们决定将 Django 应用程序拆分为微服务。


这个故事阐述了我们是怎样失败,以及如今我们为何又将这些服务迁回到单体应用。同时,我们还会花些时间来分享我们的经验教训。


在深入讨论前,我想强调下:本文的目的并非指责微服务。在 Botify,我们的理念是“使用最合适的工具”——我们认为,微服务并非此刻解决我们问题的适当工具。

开启微服务之旅

首先,简单介绍下 Botify 的历史。Botify 于 2012 年在 Python/Django 技术栈上创建。到 2016 年初,整个 Botify 平台都是通过我们 Django 应用程序的负载均衡集群提供服务。当时,我们有一个大约 15 人的产品和工程团队。

为什么选择微服务?

以下两个目标促使我们评估在技术栈中使用微服务的可能性:


  1. 提高开发速度:我们希望减少前端和后端之间的依赖关系,并增加 local ownership,从而将开发主体限定为一个小团队;

  2. 统一技术:我们在巴黎招聘 Python/Django 工程师越来越多困难,所以我们就想,前后端都统一使用 JavaScript 会让招聘工作更容易,因为我们在转向“全栈”JavaScript 这样一个单一的角色。

梦想要大,但要从小事做起

我们决定从身份验证和授权栈入手实现第一个微服务。我们认为,应该从小处着手,将 Django 应用程序当前的一部分功能转移到微服务中。我们创建了一个小型的 JavaScript 团队,负责实现 NodeJS 后端,用于处理用户及其帐户和权限。我们称之为 Customer Success。



使用微服务的 Botify API 架构概要

痛点

组织

当你像我们一样,在人为因素的驱动下做出技术决策时,你很快就会遇到问题。新团队的组织和流程很难与现有的团队并行不悖。由于特性是独立开发的,很快就出现了知识分化。微服务内部的东西没法共享,而跨栈代码审查的缺失让我们觉得失去了 ownership。

隔离

你可能已经注意到,在上面的架构中,微服务 Customer Success 并非完全隔离。从单体到微服务存在后端到后端的通信,反之亦然。这并不完全是坏事(似乎还很常见),但这还是会降低性能,并在两个服务之间创建依赖关系。从长远来看,这还意味着更复杂的机制,如 circuit breakers 和优雅的服务降级(为保证正常运行时间和可用性)。


我们还看到,在该模式下,我们主要的关系数据库是共享的。在数据库内部,一些表被映射到 Django 和 Express/Sequelize 的模型。换句话说,修改共享表的模式需要对微服务和单体进行同步修改。这是由糟糕的领域隔离所导致的。

工具

随着时间的推移,我们学会了如何健壮地构建和部署我们的 Django 应用程序,但是,对于每个新的技术栈,我们必须重新掌握这个过程。虽然在微服务环境中,独立部署是一个核心优势,但与部署微服务相比,我们还是对部署单体更有信心。不过,我们花了比较少的时间就为我们的微服务实现了健壮、流畅的自动化部署。


在日常工作中,我们遇到的问题越来越多,为了让架构更有效,我们需要不断地修改解决方案。期间,我们针对 Django 技术栈做了一些工作,改进代码、覆盖率、可测试性、依赖关系和性能。


我们颠覆了最初驱使我们采用微服务的模式


微服务技术栈是从当前流行的框架和开发团队最熟悉的框架中选取的。然而,在 Botify,我们坚信,要为合适的工作选择合适的工具:合适的工具不一定是最著名的工具,也不一定是我们已经知道的工具。


我们确定,是时候认真地(重新)考虑我们的微服务架构和 Customer Success 后端了。

去而复返,重回单体

鉴于每天都要在 JavaScript 身份验证后端和 Django 模块之间频繁地来回切换,我们把工程师们召集在一起,权衡该架构的优缺点以及潜在的迁移成本。


我们做出大胆选择,将身份验证后端重新加入到 Django 单体中,并重新生成了我们在 2016 年从 Django 转换到 Node 的 API 端点。为什么要重新采用以前的做法?下面是其中一些原因。

为恰当的问题选择恰当的方案

重要的是要记住我们的用例以及 Botify 为谁服务。我们的平台是一个企业级 B2B 服务,帮助 Web 上最大的网站改善他们的 SEO。我们的主要挑战在于对客户数据的分析,而不是我们的流量:我们每个月要处理 PB 级的数据,在一些长期运行的任务上,比如爬取或处理数据。


不过,我们不需要巨大的面向用户的流量,因为在撰写本文时,我们的用户主要是 Web 上大型站点的 SEO 经理。处理用户相关数据的微服务架构旨在服务于高流量的 B2C 平台,而 Botify 的挑战在于动态地聚合数以 GB 的 SEO 数据,让其在几秒钟内可用。对大约一万名客户的元数据以毫秒为单位进行响应,这项任务无需高度可伸缩的微服务架构。恰恰相反,我们的后端到后端通信减慢了这些简单的检索过程,花费了更多时间。

共享资源意味着同步部署

举个例子,最近的一个项目是删除一个无人维护的依赖项,该依赖项会将 JSON 数据库列作为文本处理,以便利用 PostgreSQL 中内置的列类型 jsonb。


然而,这些文本列是在两个代码库之间共享的,逐步迁移非常麻烦。同步部署多个后端很容易出错,尤其是在规模大并存在负载均衡的情况下,这与微服务最初的好处背道而驰。在 Botify,我们总是喜欢用这个警示性的故事来说明我们不喜欢同步部署。这是个有趣的故事,如果你有时间的话,可以一读。

分离的代码库淡化了知识、ownership 和联系

微服务最初由少数人实现,是为了保护新来者不受无人维护的代码库的影响,同样的人处理了所有的演进。这种现象违背了我们的代码评审理念:任何人都能够评审并理解正在发生的事情。在 Botify,我们喜欢开放式的工作方法,这样,团队中的任何人都可以查看所有代码并发表评论或提出建议。使用单独的技术栈、团队和语言,这让我们失去了团队合作和严格评审给开发团队带来的许多好处。


以上这些促使我们停用身份验证微服务并将其端点迁回 Django 单体的主要原因。

停用微服务

停用微服务非常简单,有许多方法可供选择。


我们希望在终止 Customer Success 后端时,所作的更改尽可能少,这意味着要模拟微服务的行为,在单体中逐个重写 API 端点并切换路由。这样,更改只会影响 API,而不影响前端,从而避免可怕的同步部署或 API 版本控制。


以下是我们停用微服务所采取的步骤:


  • 识别路由:列出微服务提供的所有 API 路由,确定它们的用途和目标。先处理简单的情况:有些路由可能没用,或者没有必要。

  • 在目标后端创建路由:最麻烦的工作是在目标代码库中编写相同的逻辑。相同的输入,相同的输出,还要最小化切换风险。

  • Y 分支(Y-branch)调用,比较结果:设置一个简单的分支系统,使用两个后端并比较响应,以发现不一致的地方。

  • 根据 QA 反馈,进行修复:QA 大量而广泛地审查逻辑,以发现任何遗留的 Bug。

  • 逐步扩大 Y 分支范围,以使用新迁移的逻辑。

  • 待所有逻辑都迁移到单体后,删除微服务,并完成清理工作。移除正在运行的实例和计算机。


我们可以很自豪地说,我们在 2 月 4 日 10:34 成功地停用了 NodeJS 身份验证后端 Customer Success,没有任何同步部署或 API 版本控制。



停止时间:10:34

痛点

如前所述,停用后端非常简单,使用这套方法,我们没有遇到大的麻烦。


实际上,我们遇到的最令人沮丧的问题是我们自己找出的:在构建 Customer Success 后端时,我们选择的策略是,不管 REST 调用的结果是什么,总是返回 200 响应,并使用布尔型的 success 和响应关键字 statusCode 提供更具体的错误信息:


{  "errors": [    {      "message": "Organization was not found",      "code": 404,      "name": "NotFoundError"    },  ],  "success": false,  "statusCode": 404}
复制代码


虽然这是一种常见的 REST 实践,但它不适用于 Django REST 框架。在不更改契约的情况下,将这些端点从 Express 迁移到 Django,需要大量重写 Django REST 框架的行为,才能匹配我们的 Express 实现。我们没有利用 HTTP 状态码来处理错误,而是对其进行了修改,这样,我们就可以用相同的响应关键字返回 200 状态码。令人失望,但也不是太糟糕。这种差异让人心里发痒,如果我们认为有必要,就会把它作为技术债务的一部分加以修正。好的一面是,我们的微服务定义了一种智能的跨源资源共享策略,这个必须要复制到我们的单体系统中。虽然一开始做正确的事情很麻烦,但它使我们能更好地保护应用程序免受恶意攻击。

小结

本文不是要批评微服务,也不是要对 Django 和 Express REST 后端评短论长。每一种技术都自有其用途,但我们相信,要在正确的时间选择正确的解决方案来构建我们的产品。如今,我们不必来回切换,也不用维护两个后端,显然,我们已经从中获益。


顺便提一下,当我们构建微服务后端时,我们实际上还同时构建了另一个后端,这个后端直到今天都还用着。它的功能与用户以及我们的单体应用联系比较少,所以它运行地很好,依赖和痛点也都更少。如果我们必须再次实现一个类似的特性,我们可能会在单体应用中实现,但是现在,既然它还没出问题,我们就先不修复了。


对于某些用例和情况,我们仍然相信微服务。我们并不排除未来创建新的微服务的可能性。不管怎样,我们已经从错误中吸取了教训。


我们的团队在组织结构上也有了变化: 现在实行小组制,有单独的小组负责产品特性以及前端和后端工程师面临的技术挑战,还有一名产品经理和一名 QA 工程师。我们吸取教训,每个小组都几乎是独立地设计和实现其特性,但代码库在小组间是共享的,代码审查则是由 Botify 的所有工程师负责。这让我们可以共享 ownership、知识和技术栈维护,并达到我们作为一个团队希望达到的卓越技术水平。


英文原文:


To Kill a Microservice


2020-05-29 07:0020376
用户头像

发布了 713 篇内容, 共 442.8 次阅读, 收获喜欢 1529 次。

关注

评论 9 条评论

发布
用户头像
全文看下来,只能说你们技术难以支撑你们推进微服务
2020-06-27 21:53
回复
用户头像
他們缺乏一位有能力的軟體架構師,感覺是個 newbie 在帶 team. 微服務不是只有 DDD 做完就上,數據也得拆分, 通過一些手段像 CQRS 去做橫向數據、timer 等元件的擴展,這還只是基礎,看起來他們對其下的 Infra 結構也沒什麼著墨,多半是只會套framework的 junior engineer, 分散不了就把People/Process/Technology 拿出來數落一遍,再扯個 Culture 就下課了。

他們真的只能走 monolithic program.
2020-06-07 05:04
回复
用户头像
“不管 REST 调用的结果是什么,总是返回 200 响应”,失败也返回200,为什么你们会有这种奇妙的操作……
2020-06-07 00:16
回复
用户头像
技术太烂!微服务应该是分离数据库的
2020-06-06 20:27
回复
用户头像
我觉得更想是没有选对合适的NodeJS微服务框架,建议作者看一下moleculer
2020-06-06 19:29
回复
用户头像
拆分的微服务技术栈不同、而且共享数据库影响到了部署上线,这种场景确实不适合
2020-06-04 10:27
回复
用户头像
没怎么看懂啊, 他为啥不用微服务啊?
2020-06-01 11:01
回复
他沒說的:
就是沒有做數據拆分,不懂使用 CQRS, 沒有搞清楚 Data ownership, 讓每個人都當 owner,結果就是在數據庫打架。
2020-06-07 05:23
回复
因为设计和技术能力太差
2020-06-08 09:03
回复
没有更多了
发现更多内容

mcgs笔记 用户 登录登出查看用户信息

万里无云万里天

自动化 HMI mcgs

Splunk Enterprise for Mac可视化数据分析收集软件

Mac相关知识分享

mcgs笔记 查看 辅助提示

万里无云万里天

自动化 HMI mcgs

Go 必知必会:Interface灵活而强大的类型系统

王中阳Go

接口 interface 数据类型 GO语言编程

金融安全架构设计中的反思

I

安全架构 金融服务安全 安全架构设计

活动预告:“大模型时代下AI中台”主题沙龙

中国信通院AI Infra工作组

为工程项目选择管理工具?这篇测评帮你决定

易成管理学

工程项目管理

如何从Docker镜像中提取恶意文件

百度搜索:蓝易云

基于京东API返回值的商家商品管理策略优化

代码忍者

API 接口 API 测试 pinduoduo API

mcgs笔记 权限 按钮的操作权限设置

万里无云万里天

自动化 HMI mcgs

语音识别与语音控制的原理介绍

芯动大师

语音控制

MySQL四种备份表的方式

百度搜索:蓝易云

excel表格Excel 2021 for Mac

Mac相关知识分享

Amazon Bedrock 模型微调实践(二):数据准备篇

亚马逊云科技 (Amazon Web Services)

人工智能

LED厂家告诉您LED玻璃幕墙如何设计

Dylan

设计 艺术 LED LED display LED显示屏

mcgs笔记 用户 查看用户与用户组

万里无云万里天

自动化 HMI mcgs

SSH 配置文件管理工具SSH Config Editor Pro for Mac

Mac相关知识分享

可信AI评估|中国信通院可信AI“大模型一体机”第二批评估正式启动

中国信通院AI Infra工作组

区块链DApp开发:选择正确公链的重要性

区块链软件开发推广运营

交易所开发 dapp开发 NFT开发 公链开发 代币开发

CENTOS7安装redis在/home/pms/software路径下,并且将redis加入到systemctl中

百度搜索:蓝易云

ubuntu扩展内存挂载

百度搜索:蓝易云

mac苹果电脑系统优化工具:CleanMyMac X for mac 中文激活版

你的猪会飞吗

mac破解软件下载 CleanMyMac X破解版 CleanMyMac X中文

全能视频处理软件VideoProc Converter for mac

Mac相关知识分享

开放原子开源生态大会OpenHarmony生态主题演讲报名开启

OpenHarmony开发者

OpenHarmony

帮助优化工程项目的管理软件:8款实用工具

易成管理学

项目进度管理 工程项目管理

虚拟币交易平台开发指南:打造安全高效的虚拟货币交易系统

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 NFT开发 代币开发

一文说清楚ETL与Kafka如何实现集成

RestCloud

kafka 数据处理 分析 ETL 数据集成

虚拟人,如何用好这个“外挂”?一定要看看这本书!

博文视点Broadview

mcgs笔记 动画按钮 根据值分段显示内容

万里无云万里天

自动化 HMI mcgs

建筑项目管理工具推荐:如何实现高效施工管理

易成管理学

建筑施工项目管理

故障测试入门指南

FunTester

我们为什么停用微服务?_架构_David Wobrock_InfoQ精选文章