NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

简单软件架构的一些好处

  • 2022-03-29
  • 本文字数:3806 字

    阅读完需:约 12 分钟

简单软件架构的一些好处

本文最初发表于 Wave 官网,经原作者 Dan Luu 授权,InfoQ 中文站翻译并分享。

 

Wave 是一家价值 17 亿美元的公司,拥有 70 名工程师,该公司的产品是一款加减数字的 CRUD 应用程序。为了与此保持一致,我们的架构是一种标准的 CRUD 应用架构,基于 Postgres 的 Python 单体架构。先从一个简单的架构入手,然后尽量用最简单的方式来解决问题,这使得我们的业务范围能够扩大到这种规模,而工程师们大多专注于为用户提供价值的工作。

 

Stackoverflow 扩大了单体的规模,取得了良好的效果(2013 年的架构/2016 年的架构),最后以 18 亿美元的价格被收购。如果我们关注的是流量而非市场市值,那么 Stackoverflow 就是互联网上流量最高的前 100 个网站之一(关于其他许多建立在单体之上的有价值的公司的案例,请参考这条 Twitter 主题的回复。我们没有很多网络流量,因为我们是一个移动应用,但 Alexa 还是将我们的网站列在了前 75000 名,尽管我们的网站基本上只是人们查找 APP 的一种途径,而大部分人并没有从我们的网站中获得这些 APP)。

 

有些应用的要求,使得在一个枯燥的数据库中构建出一个简单的单体应用是不可能的,但对大部分应用来说,即便是在前 100 个网站的流量水平上,计算机的运行速度也足以满足使用简单的架构来提供服务,通常创建简单的架构比复杂的架构更便宜、更容易。

 

尽管简单的架构具有不合理的有效性,但是大部分的新闻报道都是围绕着复杂的架构展开的。举例来说,在最新的通用技术会议上,就有六场演讲讨论了怎样构建或处理基于微服务的复杂结构的负面影响,却没有一场演讲讨论如何构建简单的单体。甚至关于量子计算的演讲也有一场。更大规模的会议也一样;最近旧金山的一次以企业为导向的会议上,关于处理复杂架构的演讲,场次就高达两位数;却没有一场关于如何构建简单的单体的演讲。我上次去的那次会议给我留下了很深的印象,就是许多公司的员工,他们的应用程序规模很小,本来可以用简单的架构就能完成,但是他们使用的都是会议圈子和网络上流行的最新、最复杂的技术。

 

我们的架构是如此简单,以至于我都懒得去做一个架构图。我会讨论我们所做的使一切乏味的事。

 

我们目前使用的是乏味的、同步的 Python,这意味着,当我们的服务器进程在等待 I/O 时被阻塞,比如网络请求。我们之前尝试过 Eventlet,这是一种理论上能使我们从 Python 中获得更高效率的异步框架,但是我们碰到了大量的 Bug,我们觉得,等待事件的 CPU 和延迟成本,都不值得我们为处理 Eventlent 问题而承担操作上的痛苦。其他知名的 Python 框架也有类似的情况,但是大规模使用它们的用户往往也会报告大规模使用这些框架带来的严重后果。使用同步的 Python 代价很高,因为我们需要支付 CPU 的费用,而在网络请求期间,CPU 除了等待之外什么都不做,但是,现在,我们每个月只能处理几十亿个请求,因此,即便是使用 Python 这种缓慢的语言,也要支付公共云的零售费用,这样的成本也很低。我们工程团队的成本完全决定了我们所运营的系统的成本。

 

我们将长时间运行的任务(我们不想让响应阻塞)分配到一个队列中,而不是承担使我们的单体异步的复杂性。

 

我们不能像我们想的那样无聊的地方,就是我们的内部数据中心。当我们只在塞内加尔和科特迪瓦运营时,我们完全是在云端中运营,但是,随着我们的业务范围扩大到乌干达(以及未来更多的国家/地区),我们不得不拆分后端,部署到当地的内部数据中心,以遵守当地的数据存储法律和法规。这并非一项简单的操作,但正如那些在面向服务的复杂架构中做过相同工作的人所知道的那样,这种操作要比使用复杂的服务导向的架构要简单得多。

 

另外一个方面是我们必须研发的软件,而非购买。刚起步时,我们强烈地倾向于购买软件,而非研发软件,因为一个由少数工程师组成的团队无法承担研发软件的时间成本。虽然“购买”这一选项,通常会给你提供一些无效的工具,但这在那个时候是正确的选择。如果我们不能说服供应商修复 Showstopper 错误,而这个错误对我们至关重要,那么在这种情况下,构建更多的自己的工具,并且在更多的方面保留内部的专业知识,这的确是很有意义的,但这与公司应只选择“构建”其核心能力的标准建议相悖。这种复杂性的大部分都是我们不愿意承担的,但是对于某些类别的产品,即便是进行了相当广泛的研究,我们仍然找不到供应商能够提供适合我们的产品。公平地说,我们的供应商需要解决的问题比我们需要解决的问题复杂得多,因为我们的供应商承担着为每个客户解决问题的复杂性,而我们只需要为一个客户解决问题,那就是我们自己。

 

译注:Showtopper 错误是导致执行停止并基本上变得无用的硬件或软件错误。必须修复此严重错误,以使开发过程进一步进行。

 

我们在运营的头几个月里,就犯了一个错误,就是没有仔细地界定数据库事务的边界,这在今天已经付出了一定的代价。在 Wave 的代码库中,SQLAlchemy 数据库会话是一个请求全局变量;在任何时候访问 DB 对象的属性时,它都隐含地开始一个新的数据库事务,并且 Wave 代码库中的任何函数都可以在会话上调用 commit,使其提交所有挂起、的更新。这使得我们很难控制数据库更新发生的时间,从而增加了出现微妙的数据完整性错误的概率,并且很难依靠数据库来构建类似于幂等键(idempotency key)或事务性暂存的作业流失。这样做还会增加我们意外地持有打开的长时间运行的数据库事务的风险,这可能使模式迁移操作变得困难

 

一些我们不确定的选择(因为我们在考虑更改,或建议其他从零起步的团队考虑另一种方式)有:使用 RabbitMQ(就我们的目的而言,Redis 可能同样适用于任务队列,只需要 Redis 就可以减轻操作负担);使用 Celery(这对于我们的用例来说过于复杂,并且已经出现了好几次故障,比如在版本升级过程中出现了向后兼容性问题);使用 SQLAlchemy(它使开发人员难以理解自己的代码将会产生怎样的数据库查询,从而导致各种难以调试的情况,同时也带来了不必要的操作痛苦,尤其是与上面提到的数据库事务边界的观点有关);以及使用 Python(由于我们的创始 CTO 的技术背景,这是最初的正确选择,但其并发支持、性能和广泛的动态性使我们质疑它是否是大规模后端代码库的正确选择)。以上所有这些都不是主要的错误,而且对于一些(例如 Python) 来说,缺陷已经很少了,因此,与投资到理论上更好的迁移相比,我们将花费更少的费用去进行更多的维护,但如果我们现在就从头编写一套类似的代码库,那么我们就会认真考虑,它们是否正确的选择。

 

在某些方面,我们很满意能做出这样的选择,虽然这些听上去并不像是最简单可行的解决方案,比如我们的 API,我们使用 GraphQL;我们的传输协议,我们有一段时间使用自定义协议;还有我们的主机管理,我们使用 Kubernetes。对于我们的传输协议,我们曾经使用了一种基于 UDP 的自定义协议,并带有 SMS 和 USSD 后备功能,这也是这场讲座所提到的性能理由。在 HTTP/3 发布后,我们已经能够用 HTTP/3 来替代我们的自定义协议,通常我们只需要 USSD 就可以解决像最近在马里发生的互联网关闭这样的事件)。

 

对于 GraphQL 的使用,我们相信其优点多于缺点:

 

优点:

 

  • 精确返回类型的自文档化;

  • 精确返回类型的代码生成使得客户端更加安全;

  • GraphiQL 交互式探索器是生产力的一个胜利;

  • 我们的各种应用(用户应用、支持应用、Wave agent 应用等)大多可以共享一个 API,从而减少复杂性。

  • 可组合的查询语言允许客户端在一次数据包往返中准确获取它们需要的数据,而无需建立大量的特殊用途的端点;

  • 避免了对什么算作 RESTful API 的无意义争论。

 

缺点:

 

  • 当我们采用 GraphQL 时,GraphQL 库并不是很好(基本的 Python 库是从 JavaScript 库中移植过来的,因此不是 Python 化的,Graphene 需要大量的模板,Apollo-Android 生成的优化代码非常烂)。

  • 默认的 GQL 编码是冗余的,而且由于很多客户端的带宽较低,所以我们非常关心限制大小。

 

对于 Kubernetes,我们之所以选择 Kubernetes,是因为我们清楚,如果业务成功(确实如此),而且我们不断扩张,我们最终会扩张到那些要求我们在该国内运营服务的国家。各国之间的具体规定各不相同,但是我们在非洲的主要市场上拓展了业务,这就要求我们在该国运营我们的 “主要数据中心”,还有其他一些规定,例如,要求我们能够将故障转移到该国的数据中心。

 

电信集成是我们无法回避的复杂性的一个方面。从理论上讲,我们将使用 SaaS SMS 提供商来完成这一切,但是,非洲各大 SaaS SMS 提供商的业务并没有遍及整个非洲,因此在那里使用这些服务的费用都让人望而却步。如果我们利用 SaaS SMS 提供商来解决我们所有的短信需求,那么以前的那些说工程师的薪酬成本如何主导我们系统成本的说法是站不住脚的;提供电信集成服务的团队为此付出了数倍的代价。

 

通过将应用架构尽量简化,我们就可以将复杂性(以及人力)预算用于有利于业务发展的领域。如果没有足够的理由去提高复杂性,那么我们就可以基于尽可能简单地做事的这一想法,用少量的工程师,创建一个规模不小的业务,虽然我们所经营的非洲金融业务通常被视为难以涉足的业务,我们会在以后的文章中谈到(我们的早期和最有帮助的咨询顾问之一,他给我们提出的建议,对于 Wave 的成功非常关键,起初提出 Wave 是一个糟糕的商业点子,而创始人应该选择另一个,因为他预见到了许多潜在的困难)。

 

原文链接:

https://www.wave.com/en/blog/simple-architecture/index.html

公众号推荐:

跳进 AI 的奇妙世界,一起探索未来工作的新风貌!想要深入了解 AI 如何成为产业创新的新引擎?好奇哪些城市正成为 AI 人才的新磁场?《中国生成式 AI 开发者洞察 2024》由 InfoQ 研究中心精心打造,为你深度解锁生成式 AI 领域的最新开发者动态。无论你是资深研发者,还是对生成式 AI 充满好奇的新手,这份报告都是你不可错过的知识宝典。欢迎大家扫码关注「AI前线」公众号,回复「开发者洞察」领取。

2022-03-29 14:504177

评论 2 条评论

发布
用户头像
机翻的吧,一点都读不通顺
2022-03-30 11:43
回复
用户头像

微服务架构趋势下如何处理存量系统
https://xie.infoq.cn/article/3f9e2ea9e02ef60a90f7dac3d
2022-03-30 08:46
回复
没有更多了
发现更多内容

利用Excel导入数据到SAP C4C

Jerry Wang

Excel SAP C4C Cloud for Customer

Hybris开发环境的license计算实现

Jerry Wang

Java SAP Hybris Commerce Cloud

中国与世界共享数字经济机遇

CECBC

数字经济

防火墙

escray

学习 极客时间 安全 5月日更 安全攻防技能30讲

【Flutter 专题】121 图解简易 Slider 滑动条

阿策小和尚

5月日更 Flutter 小菜 0 基础学习 Flutter Android 小菜鸟

Dubbo 路由规则之条件路由

青年IT男

dubbo

CRM WebClient UI和Hybris里工作中心跳转的url生成逻辑

Jerry Wang

CRM abap WebClient UI

Java 基础(一)——Java 入门

空城机

Java 5月日更

为什么很多程序员,成为不了技术大牛?

实力程序员

SAP Netweaver和Hybris的数据库层

Jerry Wang

abap Hybris

人生算法:掌控大脑的两种模式

石云升

读书笔记 思维模型 5月日更

《觉醒年代》观后感

xiezhr

觉醒年代 五四运动 南陈北李

Github Action 自动构建 Flutter Android Apk

Leetao

flutter Github Actions

架构实战营模块4作业

阿体

微服务架构设计之解耦合

Damon

微服务 5月日更

SAP CRM WebClient UI和Hybris backoffice UI开发的相同点

Jerry Wang

CRM SAP abap WebClient UI Hybris

小走神

Nydia

学习

谈一谈Java的前生今世

孙叫兽

Java jdk 发展史

☕【JVM 技术之旅】深入挖掘Java对象的内存结构

洛神灬殇

JVM java对象分析 java对象 5月日更 内存对象结构

教你用 3 行代码发邮件

小匚

Python 学习 自动化

Java基础(一)——Java入门和IntelliJ IDEA使用

空城机

Java IDEA 5月日更

着力区块链技术等方向,上海这所高校成立研究院

CECBC

前端开发:node.js的node包管理器npm安装以及使用

三掌柜

5月日更

Rust从0到1-泛型-定义

rust 泛型 generic

UI5 Source code map机制的细节介绍

Jerry Wang

JavaScript SAP SAP UI5

WLS2搭建Django部署环境

IT蜗壳-Tango

5月日更

ABAP Netweaver和Hybris里获得内存使用统计数据

Jerry Wang

Java CRM abap C4C Hybris

CRM WebUI and Hybris的Product页面标题实现

Jerry Wang

CRM SAP WebClient UI Hybris

多元线性回归模型 - DAY14

Qien Z.

5月日更 多元线性回归

PlatONE联盟链如何实现大规模生产级应用?

CECBC

阿里巴巴P8自爆:Java八大核心思维导图知识梳理

Java架构师迁哥

简单软件架构的一些好处_大数据_Dan Luu_InfoQ精选文章