<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一家價值 17 億美元的公司, 70 名工程師,簡單軟件架構(gòu)的一些好處

          共 4304字,需瀏覽 9分鐘

           ·

          2022-06-01 02:51

          作者 | Dan Luu
          譯者 | Sambodhi

          策劃 | Tina??

          譯文 from infoQ

          Wave 是一家價值 17 億美元的公司,擁有 70 名工程師,該公司的產(chǎn)品是一款加減數(shù)字的 CRUD 應(yīng)用程序。為了與此保持一致,我們的架構(gòu)是一種標準的 CRUD 應(yīng)用架構(gòu),基于 Postgres 的 Python 單體架構(gòu)。先從一個簡單的架構(gòu)入手,然后盡量用最簡單的方式來解決問題,這使得我們的業(yè)務(wù)范圍能夠擴大到這種規(guī)模,而工程師們大多專注于為用戶提供價值的工作。

          Stackoverflow 擴大了單體的規(guī)模,取得了良好的效果(2013 年的架構(gòu) /2016 年的架構(gòu)),最后以 18 億美元的價格被收購。如果我們關(guān)注的是流量而非市場市值,那么 Stackoverflow 就是互聯(lián)網(wǎng)上流量最高的前 100 個網(wǎng)站之一(關(guān)于其他許多建立在單體之上的有價值的公司的案例,請參考這條 Twitter 主題的回復(https://twitter.com/danluu/status/1462607028585525249)。我們沒有很多網(wǎng)絡(luò)流量,因為我們是一個移動應(yīng)用,但 Alexa 還是將我們的網(wǎng)站列在了前 75000 名,盡管我們的網(wǎng)站基本上只是人們查找 APP 的一種途徑,而大部分人并沒有從我們的網(wǎng)站中獲得這些 APP)。

          有些應(yīng)用的要求,使得在一個枯燥的數(shù)據(jù)庫中構(gòu)建出一個簡單的單體應(yīng)用是不可能的,但對大部分應(yīng)用來說,即便是在前 100 個網(wǎng)站的流量水平上,計算機的運行速度也足以滿足使用簡單的架構(gòu)來提供服務(wù),通常創(chuàng)建簡單的架構(gòu)比復雜的架構(gòu)更便宜、更容易。

          盡管簡單的架構(gòu)具有不合理的有效性,但是大部分的新聞報道都是圍繞著復雜的架構(gòu)展開的。舉例來說,在最新的通用技術(shù)會議上,就有六場演講討論了怎樣構(gòu)建或處理基于微服務(wù)的復雜結(jié)構(gòu)的負面影響,卻沒有一場演講討論如何構(gòu)建簡單的單體。甚至關(guān)于量子計算的演講也有一場。更大規(guī)模的會議也一樣;最近舊金山的一次以企業(yè)為導向的會議上,關(guān)于處理復雜架構(gòu)的演講,場次就高達兩位數(shù);卻沒有一場關(guān)于如何構(gòu)建簡單的單體的演講。我上次去的那次會議給我留下了很深的印象,就是許多公司的員工,他們的應(yīng)用程序規(guī)模很小,本來可以用簡單的架構(gòu)就能完成,但是他們使用的都是會議圈子和網(wǎng)絡(luò)上流行的最新、最復雜的技術(shù)。

          我們的架構(gòu)是如此簡單,以至于我都懶得去做一個架構(gòu)圖。我會討論我們所做的使一切乏味的事。

          我們目前使用的是乏味的、同步的 Python,這意味著,當我們的服務(wù)器進程在等待 I/O 時被阻塞,比如網(wǎng)絡(luò)請求。我們之前嘗試過 Eventlet,這是一種理論上能使我們從 Python 中獲得更高效率的異步框架,但是我們碰到了大量的 Bug,我們覺得,等待事件的 CPU 和延遲成本,都不值得我們?yōu)樘幚?Eventlent 問題而承擔操作上的痛苦。其他知名的 Python 框架也有類似的情況,但是大規(guī)模使用它們的用戶往往也會報告大規(guī)模使用這些框架帶來的嚴重后果。使用同步的 Python 代價很高,因為我們需要支付 CPU 的費用,而在網(wǎng)絡(luò)請求期間,CPU 除了等待之外什么都不做,但是,現(xiàn)在,我們每個月只能處理幾十億個請求,因此,即便是使用 Python 這種緩慢的語言,也要支付公共云的零售費用,這樣的成本也很低。我們工程團隊的成本完全決定了我們所運營的系統(tǒng)的成本。

          我們將長時間運行的任務(wù)(我們不想讓響應(yīng)阻塞)分配到一個隊列中,而不是承擔使我們的單體異步的復雜性。

          我們不能像我們想的那樣無聊的地方,就是我們的內(nèi)部數(shù)據(jù)中心。當我們只在塞內(nèi)加爾和科特迪瓦運營時,我們完全是在云端中運營,但是,隨著我們的業(yè)務(wù)范圍擴大到烏干達(以及未來更多的國家 / 地區(qū)),我們不得不拆分后端,部署到當?shù)氐膬?nèi)部數(shù)據(jù)中心,以遵守當?shù)氐臄?shù)據(jù)存儲法律和法規(guī)。這并非一項簡單的操作,但正如那些在面向服務(wù)的復雜架構(gòu)中做過相同工作的人所知道的那樣,這種操作要比使用復雜的服務(wù)導向的架構(gòu)要簡單得多。

          另外一個方面是我們必須研發(fā)的軟件,而非購買。剛起步時,我們強烈地傾向于購買軟件,而非研發(fā)軟件,因為一個由少數(shù)工程師組成的團隊無法承擔研發(fā)軟件的時間成本。雖然“購買”這一選項,通常會給你提供一些無效的工具(https://danluu.com/nothing-works/),但這在那個時候是正確的選擇。如果我們不能說服供應(yīng)商修復 Showstopper 錯誤,而這個錯誤對我們至關(guān)重要,那么在這種情況下,構(gòu)建更多的自己的工具,并且在更多的方面保留內(nèi)部的專業(yè)知識,這的確是很有意義的(https://danluu.com/in-house/),但這與公司應(yīng)只選擇“構(gòu)建”其核心能力的標準建議相悖。這種復雜性的大部分都是我們不愿意承擔的,但是對于某些類別的產(chǎn)品,即便是進行了相當廣泛的研究,我們?nèi)匀徽也坏焦?yīng)商能夠提供適合我們的產(chǎn)品。公平地說,我們的供應(yīng)商需要解決的問題比我們需要解決的問題復雜得多,因為我們的供應(yīng)商承擔著為每個客戶解決問題的復雜性,而我們只需要為一個客戶解決問題,那就是我們自己。

          譯注:Showtopper 錯誤是導致執(zhí)行停止并基本上變得無用的硬件或軟件錯誤。必須修復此嚴重錯誤,以使開發(fā)過程進一步進行。

          我們在運營的頭幾個月里,就犯了一個錯誤,就是沒有仔細地界定數(shù)據(jù)庫事務(wù)的邊界,這在今天已經(jīng)付出了一定的代價。在 Wave 的代碼庫中,SQLAlchemy 數(shù)據(jù)庫會話是一個請求全局變量;在任何時候訪問 DB 對象的屬性時,它都隱含地開始一個新的數(shù)據(jù)庫事務(wù),并且 Wave 代碼庫中的任何函數(shù)都可以在會話上調(diào)用 commit,使其提交所有掛起的更新。這使得我們很難控制數(shù)據(jù)庫更新發(fā)生的時間,從而增加了出現(xiàn)微妙的數(shù)據(jù)完整性錯誤的概率,并且很難依靠數(shù)據(jù)庫來構(gòu)建類似于冪等鍵(idempotency key)或事務(wù)性暫存的作業(yè)流失。這樣做還會增加我們意外地持有打開的長時間運行的數(shù)據(jù)庫事務(wù)的風險,這可能使模式遷移操作變得困難。

          一些我們不確定的選擇(因為我們在考慮更改,或建議其他從零起步的團隊考慮另一種方式)有:使用 RabbitMQ(就我們的目的而言,Redis 可能同樣適用于任務(wù)隊列,只需要 Redis 就可以減輕操作負擔);使用 Celery(這對于我們的用例來說過于復雜,并且已經(jīng)出現(xiàn)了好幾次故障,比如在版本升級過程中出現(xiàn)了向后兼容性問題);使用 SQLAlchemy(它使開發(fā)人員難以理解自己的代碼將會產(chǎn)生怎樣的數(shù)據(jù)庫查詢,從而導致各種難以調(diào)試的情況,同時也帶來了不必要的操作痛苦,尤其是與上面提到的數(shù)據(jù)庫事務(wù)邊界的觀點有關(guān));以及使用 Python(由于我們的創(chuàng)始 CTO 的技術(shù)背景,這是最初的正確選擇,但其并發(fā)支持、性能和廣泛的動態(tài)性使我們質(zhì)疑它是否是大規(guī)模后端代碼庫的正確選擇)。以上所有這些都不是主要的錯誤,而且對于一些(例如 Python) 來說,缺陷已經(jīng)很少了,因此,與投資到理論上更好的遷移相比,我們將花費更少的費用去進行更多的維護,但如果我們現(xiàn)在就從頭編寫一套類似的代碼庫,那么我們就會認真考慮,它們是否正確的選擇。

          在某些方面,我們很滿意能做出這樣的選擇,雖然這些聽上去并不像是最簡單可行的解決方案,比如我們的 API,我們使用 GraphQL;我們的傳輸協(xié)議,我們有一段時間使用自定義協(xié)議;還有我們的主機管理,我們使用 Kubernetes。對于我們的傳輸協(xié)議,我們曾經(jīng)使用了一種基于 UDP 的自定義協(xié)議,并帶有 SMS 和 USSD 后備功能,這也是這場講座所提到的性能理由。在 HTTP/3 發(fā)布后,我們已經(jīng)能夠用 HTTP/3 來替代我們的自定義協(xié)議,通常我們只需要 USSD 就可以解決像最近在馬里發(fā)生的互聯(lián)網(wǎng)關(guān)閉這樣的事件)。

          對于 GraphQL 的使用,我們相信其優(yōu)點多于缺點:

          優(yōu)點:

          • 精確返回類型的自文檔化;

          • 精確返回類型的代碼生成使得客戶端更加安全;

          • GraphiQL 交互式探索器是生產(chǎn)力的一個勝利;

          • 我們的各種應(yīng)用(用戶應(yīng)用、支持應(yīng)用、Wave agent 應(yīng)用等)大多可以共享一個 API,從而減少復雜性。

          • 可組合的查詢語言允許客戶端在一次數(shù)據(jù)包往返中準確獲取它們需要的數(shù)據(jù),而無需建立大量的特殊用途的端點;

          • 避免了對什么算作 RESTful API 的無意義爭論。

          缺點:

          • 當我們采用 GraphQL 時,GraphQL 庫并不是很好(基本的 Python 庫是從 JavaScript 庫中移植過來的,因此不是 Python 化的,Graphene 需要大量的模板,Apollo-Android 生成的優(yōu)化代碼非常爛)。

          • 默認的 GQL 編碼是冗余的,而且由于很多客戶端的帶寬較低,所以我們非常關(guān)心限制大小。

          對于 Kubernetes,我們之所以選擇 Kubernetes,是因為我們清楚,如果業(yè)務(wù)成功(確實如此),而且我們不斷擴張,我們最終會擴張到那些要求我們在該國內(nèi)運營服務(wù)的國家。各國之間的具體規(guī)定各不相同,但是我們在非洲的主要市場上拓展了業(yè)務(wù),這就要求我們在該國運營我們的 “主要數(shù)據(jù)中心”,還有其他一些規(guī)定,例如,要求我們能夠?qū)⒐收限D(zhuǎn)移到該國的數(shù)據(jù)中心。

          電信集成是我們無法回避的復雜性的一個方面。從理論上講,我們將使用 SaaS SMS 提供商來完成這一切,但是,非洲各大 SaaS SMS 提供商的業(yè)務(wù)并沒有遍及整個非洲https://youtu.be/6tb8ALAvodM?t=196,因此在那里使用這些服務(wù)的費用都讓人望而卻步。如果我們利用 SaaS SMS 提供商來解決我們所有的短信需求,那么以前的那些說工程師的薪酬成本如何主導我們系統(tǒng)成本的說法是站不住腳的;提供電信集成服務(wù)的團隊為此付出了數(shù)倍的代價。

          通過將應(yīng)用架構(gòu)盡量簡化,我們就可以將復雜性(以及人力)預(yù)算用于有利于業(yè)務(wù)發(fā)展的領(lǐng)域。如果沒有足夠的理由去提高復雜性,那么我們就可以基于盡可能簡單地做事的這一想法,用少量的工程師,創(chuàng)建一個規(guī)模不小的業(yè)務(wù),雖然我們所經(jīng)營的非洲金融業(yè)務(wù)通常被視為難以涉足的業(yè)務(wù),我們會在以后的文章中談到(我們的早期和最有幫助的咨詢顧問之一,他給我們提出的建議,對于 Wave 的成功非常關(guān)鍵,起初提出 Wave 是一個糟糕的商業(yè)點子,而創(chuàng)始人應(yīng)該選擇另一個,因為他預(yù)見到了許多潛在的困難)。

          原文鏈接:

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

          瀏覽 47
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  先锋影音三区四区 | 天天躁日日躁狠狠很躁 | 自拍成人在线观看 | 午夜成人网在线 | 免费看国产黄色电影 |