<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>

          30 萬行代碼的平臺(tái)升級(jí):給跑著的汽車換輪胎

          共 6176字,需瀏覽 13分鐘

           ·

          2021-05-15 22:18

          作者 | Mahmoud Hashemi
          譯者 | 平川
          策劃 | Tina

          本文最初發(fā)布于 Mahmoud Hashemi 的個(gè)人博客,經(jīng)原作者授權(quán)由 InfoQ 中文站翻譯并分享。

          2020 年可謂反復(fù)無常。盡管一切都超出了人們的控制,但隨著時(shí)間的推移,我發(fā)現(xiàn)自己把越來越多的時(shí)間地投入到一件感覺唾手可及的事情中:為我?guī)椭鷺?gòu)建的大型企業(yè)級(jí) Web 應(yīng)用程序 SimpleLegal 設(shè)計(jì)一個(gè)面向未來的解決方案。

          現(xiàn)在已經(jīng)完成了,這次平臺(tái)升級(jí)很容易就可以在我最復(fù)雜的項(xiàng)目中名列前茅,此時(shí)此刻,最幸福的結(jié)局。幸福是要付出代價(jià)的,但是借助一些恰當(dāng)?shù)姆椒ǎ鷥r(jià)可能不會(huì)像你想的那么高。

          概述

          我們將 SimpleLegal 的主要產(chǎn)品,一個(gè) 30 萬行的 Django-1.11-Python 2.7-Redis-Postgres-10 代碼庫,移植到 Django 2.2-Python 3.8-Postgres-12 技術(shù)棧,如期完成,而且沒有發(fā)生重大站點(diǎn)事件。這感覺很棒。

          作為這個(gè)項(xiàng)目的技術(shù)主管,它看起來是什么樣子?對(duì)我來說,是這樣的:

          但作為工程總監(jiān),它的成本是多少?3.5 年的開發(fā)時(shí)間,每行代碼只需要 2 美元。

          我對(duì)這個(gè)結(jié)果感到特別自豪,因?yàn)樵谶@個(gè)過程中,我們也大大提高了網(wǎng)站和開發(fā)過程本身的速度和可靠性。現(xiàn)在,該產(chǎn)品有了一個(gè)光明的未來,已經(jīng)準(zhǔn)備好在銷售征求建議書和合規(guī)調(diào)查問卷上大放異彩了。最重要的是,你不必?fù)?dān)心怎樣委婉地告訴潛在客戶,他們將使用的是不受支持的技術(shù)。

          簡而言之,這是一筆巨大的、穩(wěn)健的投資,而且已經(jīng)取得了回報(bào)。如果你來這里只是為了看看我們自己對(duì)這項(xiàng)工作的估計(jì),那就是上面這些了。這篇文章是介紹如何讓你的團(tuán)隊(duì)達(dá)到同樣的結(jié)果。

          背景

          故事開始于 2013 年,剛剛從 YC 孵化出來的 SimpleLegal 為一家新成立的 SaaS 法律技術(shù)公司做了所有正確的決定:Python、Django、Postgres 和 Redis。在典型的初創(chuàng)公司模式中,在技術(shù)不成障礙的情況下,功能是第一位的。軟件包只是順帶升級(jí)。

          到 2019 年,這條技術(shù)跑道的終點(diǎn)已經(jīng)臨近。雖然 Python 2 可能得到了來自不同供應(yīng)商的擴(kuò)展支持,但在 2021 年,Django 1 CVE 補(bǔ)丁的志愿者已經(jīng)非常少了。Web 框架成了風(fēng)險(xiǎn)較大的攻擊面,所以是時(shí)候償還我們的技術(shù)債務(wù)了。

          開端

          因此,我們?cè)?2019 年第 4 季度開始了 Tech Refresh 平臺(tái)升級(jí)計(jì)劃。其目標(biāo)是:升級(jí)技術(shù)棧,同時(shí)仍然提供新特性,就像給跑著的汽車換輪胎。我們要小心謹(jǐn)慎,而那需要時(shí)間。以下是一些長期項(xiàng)目的基本原則:

          1. 任何每周工作 10 小時(shí)以上的項(xiàng)目都應(yīng)該每周花 30 分鐘進(jìn)行同步。

          2. 每次定期會(huì)議都應(yīng)該有記錄。把它放在邀請(qǐng)函里。使用項(xiàng)目日志記錄進(jìn)度、阻礙因素和決策。

          3. 這是一場馬拉松,不是短跑。要避免在晚上、周末和假期工作。

          我們從一個(gè)計(jì)劃草圖開始,經(jīng)過開放地討論,最終只有一半正確。有一些早期的猜測成功實(shí)現(xiàn):

          1. 轉(zhuǎn)到 pip-tools,并根據(jù)廣泛的變更日志分析解除依賴關(guān)系。識(shí)別不兼容 py23 版本的包。(盡管我們已經(jīng)轉(zhuǎn)向 poetry。)

          2. 在 CI 中加入行覆蓋率報(bào)告。

          3. 改進(jìn)內(nèi)部測試框架,讓開發(fā)者可以快速編寫測試。

          下面有更多相關(guān)內(nèi)容。其他的計(jì)劃就不那么現(xiàn)實(shí)了:

          1. 在 6 個(gè)月內(nèi)將 CI 行覆蓋率從大約 60% 提升到 95%。

          2. 在三個(gè)月內(nèi)并行轉(zhuǎn)換 app 程序包。

          3. 利用美國節(jié)假日(感恩節(jié)、圣誕節(jié)、新年)期間的低流量時(shí)間,在 2021 年之前逐步切換到新應(yīng)用。

          我們年輕!雖然我們天真,但至少我們知道有很多工作要做。為了分擔(dān)這項(xiàng)工作,我們尋找、雇傭并培訓(xùn)了三名敬業(yè)的海外開發(fā)人員。

          導(dǎo)向問題

          即使新增了開發(fā)人員,到 2020 年中期,我們?cè)絹碓秸J(rèn)識(shí)到,95% 的覆蓋率就是在做夢,更不用說 100% 了。全部覆蓋可能是最佳實(shí)踐,但 3 個(gè)半開發(fā)人員沒法做到這樣的覆蓋范圍。我們做了有價(jià)值的測試,甚至發(fā)現(xiàn)了以前的 Bug,但如果我們堅(jiān)持這個(gè)計(jì)劃,Django 2 最終將成為一個(gè) 2022 年的項(xiàng)目。70%,我們決定修改目標(biāo)。

          我們意識(shí)到,對(duì)于大多數(shù)站點(diǎn)來說,CI 比大多數(shù)用戶更敏感。所以我們專注于測試影響最大的代碼。怎么才算影響大?1)失敗了最易被察覺的代碼;2)最難重試的代碼。通過查看流量統(tǒng)計(jì)數(shù)據(jù)、批處理作業(yè)計(jì)劃和詢問支持人員,你可以在一周內(nèi)構(gòu)建出高影響代碼清單。

          大約 80% 的代碼庫都不在這個(gè)高流量 / 高影響列表中。那 80% 該怎么辦呢?利用錯(cuò)誤檢測和快速修復(fù)。

          轉(zhuǎn)換 Sentry 的角色

          創(chuàng)業(yè)生活的一個(gè)好處是,嘗試新工具很容易。我們?cè)?SimpleLegal 所采用的一種做法是,把每 5 個(gè)周的最后一周(即 20% 的時(shí)間)留給開發(fā)人員,讓他們專注于開發(fā)過程本身。即使是最好的廚師也不能在臟亂的廚房里做出五星級(jí)的食物。這是我們改進(jìn)工作的方法,最終加快了交付速度。

          在這樣一個(gè)時(shí)期,有人想出了一個(gè)天才的主意,使用 Sentry 將專門的錯(cuò)誤報(bào)告添加到系統(tǒng)中。在一兩天內(nèi),我們就有了一個(gè)網(wǎng)站,你可以訪問并獲取堆棧跟蹤。這非常神奇,但直到 Tech Refresh 計(jì)劃開始我們才意識(shí)到,雖然集成只需要一天的開發(fā)時(shí)間,但完全采用卻需要團(tuán)隊(duì)幾個(gè)月的時(shí)間。

          你看,在一個(gè)成熟但快速運(yùn)轉(zhuǎn)的系統(tǒng)上增加 Sentry 意味著一件事:噪音。我們的網(wǎng)站一直在出錯(cuò)。大多數(shù)錯(cuò)誤是不可見的,也沒有妨礙用戶使用,有些用戶已經(jīng)悄悄學(xué)會(huì)了如何處理長期存在的網(wǎng)站怪癖。很快,我們的開發(fā)人員就學(xué)會(huì)了把 Sentry 當(dāng)作調(diào)試信息的存儲(chǔ)庫。2019 年,Sentry 事件本身并不值得認(rèn)真對(duì)待。2020 年,情況發(fā)生了變化,負(fù)責(zé)將平臺(tái)無縫升級(jí)的團(tuán)隊(duì)需要把 Sentry 變成另一種東西:響應(yīng)性網(wǎng)站質(zhì)量工具。

          我們是怎么做到的呢?第一步,通過以下最佳實(shí)踐增強(qiáng)流入 Sentry 的數(shù)據(jù):

          1. 將產(chǎn)品拆分成單獨(dú)的 Sentry 項(xiàng)目。這包括前端和后端。

          2. 標(biāo)記版本。不要用分支來標(biāo)記開發(fā)環(huán)境部署,這會(huì)導(dǎo)致 Releases UI 混亂。添加一個(gè)單獨(dú)的分支標(biāo)簽用于搜索。

          3. 把環(huán)境分開。這對(duì)于定向報(bào)警至關(guān)重要。Sentry 客戶端環(huán)境是通過域約定和 Django 的 sites 框架來配置的。為了便于理解,這里有一個(gè)基線,我們使用這些環(huán)境:

          4. 生產(chǎn)環(huán)境:當(dāng)前正式版本。DevOps 監(jiān)控。

          5. 沙箱環(huán)境:當(dāng)前正式版本(部分公司會(huì)做下一次發(fā)布)。供用戶測試變更使用。DevOps 監(jiān)控。

          6. 演示 / 銷售環(huán)境:上一個(gè)正式版本。主要是內(nèi)部流量,但在前景演示時(shí)外部也可見。DevOps 監(jiān)控。

          7. 金絲雀環(huán)境:下一個(gè)正式版本。也稱為過渡環(huán)境。內(nèi)部流量。Dev 監(jiān)控。

          8. ProdQA 環(huán)境:當(dāng)前正式版本。內(nèi)部用于重現(xiàn)技術(shù)支持問題。Dev 監(jiān)控。

          9. QA 環(huán)境:Dev 分支、dev 發(fā)布、內(nèi)部流量。未監(jiān)控調(diào)試數(shù)據(jù)。

          10. 本地測試 /CI 環(huán)境:默認(rèn)不發(fā)布到 Sentry。

          當(dāng)問題最終被正確標(biāo)記并且可以搜索之后,我們使用 Sentry 新增的 Discover 工具每周導(dǎo)出問題,并對(duì)遺留錯(cuò)誤進(jìn)行優(yōu)先級(jí)排序。我們首先關(guān)注的是對(duì)于非內(nèi)部人類用戶高可見的生產(chǎn)錯(cuò)誤。具體查詢是:
          has:user !transaction:/api/* event.type:error !user.username:*@simplelegal.*

          我們將其分為 4 類:快速修復(fù)(小漏洞)、快速錯(cuò)誤(將一個(gè)含糊的 500 錯(cuò)誤轉(zhuǎn)變成某種形式的可操作的 400 錯(cuò)誤)、Spike(比較大的漏洞,需要研究)和 Silence(使用 Sentry 的忽略功能)。在 6 周的時(shí)間里,每周事件量由每周超過 2500 次下降到了不到 500 次。

          通過進(jìn)一步的努力,每周的事件量已經(jīng)少于 100 次,并且分散在幾個(gè)問題上,對(duì)于一個(gè)精益團(tuán)隊(duì)來說,這非常容易管理。雖然“Sentry Zero”是最理想的,但我們實(shí)現(xiàn)并維持了響應(yīng)流的真正目標(biāo),這在很大程度上要?dú)w功于 Slack 集成。我們的團(tuán)隊(duì)不再從支持團(tuán)隊(duì)那里獲取服務(wù)器錯(cuò)誤信息。事實(shí)上,現(xiàn)在,當(dāng)客戶遇到麻煩時(shí),我們會(huì)告訴他們,而我們已經(jīng)有了一個(gè)處理中的工單。

          和支持團(tuán)隊(duì)建立緊密的聯(lián)系非常重要。在上面的策略中,我們嵌入了比真實(shí)用戶更敏感的 CI。雖然完美很誘人,但要求企業(yè)用戶有一點(diǎn)耐心也是可以的,前提是支持團(tuán)隊(duì)已經(jīng)做好了準(zhǔn)備。每周都和他們同步,這樣驚喜就少了。如果他們干勁十足,你也可以教他們一些 Sentry 基礎(chǔ)知識(shí)。

          新征程

          隨著噪音的消除,我們已準(zhǔn)備好快速行動(dòng)。以下是我們?cè)谧龀鲞@些改變時(shí)積累的一些經(jīng)驗(yàn)。

          訴諸事務(wù)

          如果使用得當(dāng),回滾可以使錯(cuò)誤看起來像從未發(fā)生過,這是快速修復(fù)策略的完美補(bǔ)充。

           真正的原子請(qǐng)求

          把操作盡可能地放入事務(wù)中。打開 ATOMIC_REQUESTS(如果沒打開的話)。但是,有些請(qǐng)求所做的不僅僅是更改數(shù)據(jù)庫,比如它們會(huì)發(fā)送通知,將后臺(tái)任務(wù)入隊(duì)。

          在 SimpleLegal,我們重新設(shè)計(jì)了架構(gòu),將所有副作用(除了日志記錄)推遲到成功返回響應(yīng)時(shí)。中間件可以提供幫助,但我們主要是通過將 Redis 隊(duì)列切換到基于 PostgreSQL 的任務(wù)隊(duì)列 / 代理來實(shí)現(xiàn)的。這種配置可以確保,如果發(fā)生錯(cuò)誤,事務(wù)將被回滾,任務(wù)不會(huì)進(jìn)入隊(duì)列,用戶將得到一個(gè)干凈的失敗。我們?cè)?Sentry 中定位故障,切換到舊站點(diǎn)進(jìn)行消除,他們下一次重試就會(huì)成功。

           事務(wù)性測試設(shè)置

          事實(shí)證明,事務(wù)性對(duì)我們的測試策略來說也很關(guān)鍵。SimpleLegal 早已超過了 Django 原始的 fixture 系統(tǒng)。大多數(shù)測試都需要復(fù)雜的 Python 設(shè)置,這使得編寫測試和運(yùn)行測試都很慢。為了加快編寫和運(yùn)行的速度,我們將整個(gè)測試會(huì)話封裝到一個(gè)事務(wù)中,然后,在運(yùn)行任何測試用例之前,我們?cè)O(shè)置了示例性的基本狀態(tài)。測試用例使用這些基本狀態(tài)作為 fixture,并在每個(gè)測試用例之后回滾到基本狀態(tài)。詳情請(qǐng)參閱 contest.py 摘錄:

          https://gist.github.com/mahmoud/10f6b6b0a9c5860030693357124131df

          有些最佳實(shí)踐并不適合你

          軟件場景的差別如此之大,知道哪些建議不適合你是一門藝術(shù)。以下是我們親身了解到的各種死胡同。

           命名空間的運(yùn)用

          考慮到代碼被劃分成模塊、包、Django 應(yīng)用等的方式,把它們作為工作單元可能很有誘惑力。開始時(shí)不要這樣。代碼劃分可能非常隨意,很難知道你何時(shí)就進(jìn)入了一個(gè)有風(fēng)險(xiǎn)的思路。

          假如有自動(dòng)重構(gòu),就像在 2to3 轉(zhuǎn)換中一樣,首先要按轉(zhuǎn)換類型進(jìn)行移植。這樣,你只需要查看一個(gè)命令和受影響的路徑列表。另外,自動(dòng)修復(fù)必須遵循一種模式,這意味著更多的人可以修復(fù)重構(gòu)導(dǎo)致的錯(cuò)誤。

           蓋覆蓋率工具

          覆蓋率對(duì)我們來說是好壞參半。顯然,覆蓋率優(yōu)先策略是站不住腳的,但對(duì)優(yōu)先級(jí)劃分和狀態(tài)檢查,它仍然有用。就單次變更來說,我們發(fā)現(xiàn)覆蓋率工具有些不可靠。我們從來沒有弄清楚為什么覆蓋率的作用有不確定性,我們得出了這樣的結(jié)論:“像 codecov 這樣的現(xiàn)成工具可能并不是針對(duì)我們這種規(guī)模的 monorepos?!?/p>

          在撞上覆蓋率墻的過程中,我們研究了其他許多關(guān)于覆蓋率的解釋。對(duì)我們來說,“路由覆蓋”(即每個(gè) URL 至少有一個(gè)集成測試)和“模型表示覆蓋”(即每個(gè)模型對(duì)象都有一個(gè)有用的文本表示,可以用于 Sentry 調(diào)試)比行覆蓋優(yōu)先級(jí)高得多。如果有更多的時(shí)間,我們會(huì)希望圍繞這些構(gòu)建工具,甚至是圍繞基于在線分析的覆蓋率統(tǒng)計(jì),從而優(yōu)先考慮流量最高的路由,而不僅僅是流量最高的代碼行。如果你聽說過這些方法,我們很想和你討論一下。

           扁平化數(shù)據(jù)庫遷移

          從表面上看,減少需要升級(jí)的文件數(shù)量似乎是合理的。事實(shí)證明,扁平化遷移是一種消除文件的低收益策略。更改歷史遷移文件結(jié)構(gòu)會(huì)使上線過程變得復(fù)雜,而升級(jí)沒有扁平化的遷移文件則很簡單。更不用說,如果只是想要加速 CI,你可以像我們?cè)?Open edX 平臺(tái)上所做的那樣:

          建立一個(gè)基本的 DB 緩存,每隔幾個(gè)月檢查一次:

          https://github.com/edx/edx-platform/blob/66f0f9891f00994f77604a51dbb29736aa605fa8/scripts/reset-test-db.sh#L75

          事實(shí)證明,你可以從開源應(yīng)用程序中學(xué)到很多東西。

          慢慢適應(yīng)新技術(shù)棧

          如果你有多個(gè)應(yīng)用程序,請(qǐng)使用相對(duì)比較小也比較簡單的應(yīng)用程序來試驗(yàn)更改。幸運(yùn)的是,我們有一個(gè)獨(dú)立的應(yīng)用,它的測試運(yùn)行速度更快,這讓我們能夠更緊湊地了解開發(fā)循環(huán)。同樣地,如果你有多個(gè)生產(chǎn)環(huán)境,則從影響最小的一個(gè)環(huán)境開始推出。

          把 CI 作業(yè)復(fù)制到新的技術(shù)棧中,它們都會(huì)失敗,但要克制住把它們標(biāo)記為可選項(xiàng)的沖動(dòng)。相反,構(gòu)建一個(gè)包含所有測試及其當(dāng)前測試狀態(tài)的單文件清單。我們?yōu)闇y試運(yùn)行程序 pytest 構(gòu)建了一個(gè)小擴(kuò)展,它基于狀態(tài)清單文件批量跳過測試。然后,ratchet:取消并修復(fù)測試,更新文件,檢查測試是否通過,然后重復(fù)。這比遍布代碼庫的 pytest 標(biāo)記裝飾器更方便和可掃描。詳情請(qǐng)參閱 contest .py 摘錄:

          https://gist.github.com/mahmoud/10f6b6b0a9c5860030693357124131df

          上線試運(yùn)行

          在 2020 年第四季度,我們?cè)黾恿嘶A(chǔ)設(shè)施,以在相同的數(shù)據(jù)庫支持下并行運(yùn)行新舊站點(diǎn)。我們進(jìn)入了這樣一個(gè)循環(huán),使流量到達(dá)新技術(shù)棧,構(gòu)建一個(gè)需要修復(fù)的 Sentry 問題隊(duì)列,然后關(guān)閉它,并跟蹤時(shí)間。使用新技術(shù)棧大約 120 個(gè)小時(shí)后,經(jīng)過晝夜不停地策略性擴(kuò)展,組織已經(jīng)建立起足夠的信心,我們可以在最關(guān)鍵的時(shí)間讓站點(diǎn)繼續(xù)運(yùn)行:在月初的周一和周二。

          唯一的問題是 AWS 在感恩節(jié)周的宕機(jī)。此時(shí)我們已經(jīng)提前完成了計(jì)劃,并且對(duì)快速修復(fù)工作流建立起了足夠的信心,不再需要最初的假日測試窗口。為此,我們感謝了很多人。

          我們一直用快速修復(fù)的方法,直到我們完成?!巴瓿伞辈皇侵感孪到y(tǒng)沒有錯(cuò)誤,而是指流量在新系統(tǒng)上時(shí)事件比舊系統(tǒng)少。然后,繼續(xù)修復(fù),并開始安排時(shí)間刪除腳手架。

          后記

          所以,一旦你使用了 Django、Python、Linux 和 Postgres 當(dāng)前的 LTS 版本,任務(wù)就完成了,對(duì)吧?

          謝天謝地,技術(shù)債務(wù)從不會(huì)到 0。雖然按期更新并更換核心技術(shù)不是一件小事,但用閃亮的部件替換生銹的部件并不會(huì)改變?cè)O(shè)計(jì)。架構(gòu)技術(shù)債務(wù)——抽象中的錯(cuò)誤,包括缺乏抽象——可能會(huì)帶來更大的挑戰(zhàn)。這些問題的解決方案并不能在項(xiàng)目之間完全推廣,但它們確實(shí)會(huì)受益于這個(gè)最新的、無錯(cuò)誤的基礎(chǔ)。

          對(duì)于所有希望更換輪胎的項(xiàng)目,我們希望這次回顧能夠幫助你在未來幾年充滿信心地、務(wù)實(shí)地改進(jìn)技術(shù)棧。

           延伸閱讀

          https://sedimental.org/tech_refresh.html

          瀏覽 51
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  欧美一性一乱一交一视爱豆传媒 | 秋霞福利网| 亚洲高清不卡视频 | 台湾在线视频一区二 | 天天干天天弄 |