首頁>技術>

Sudeep Chauhan InfoQ

作者 | Sudeep Chauhan

譯者 | 核子可樂

策劃 | 蔡芳芳

本文講述了我們在首款產品上市之前就差點破產、最後倖存下來並從中汲取教訓的故事。

2020 年 3 月,COVID-19 疫情全面爆發,我們的初創公司 Milkie Way 也遭受巨大打擊,差點破產。因為我們在對 Firebase 和 Cloud Run 進行內部測試的期間,一不小心在幾個小時裡燒掉了 72000 美元(約 47 萬人民幣)。

2019 年 11 月,我們開始開發 https://announce.today 服務,希望藉此打造 MVP 產品的可用功能 V1 版本。作為初步嘗試,我們的程式碼以簡單的底層棧為依託,使用 JS、Python 程式碼並將產品部署在 Google App 引擎之上。

因為團隊規模很小,所以我們的重點放在編寫程式碼、設計 UI 以及準備產品身上。我們沒在雲管理上花多少心思,當時的目標很簡單——能支撐起基本的開發流程(CI/CD)就行。

在這款 V1 Web 應用程式中,使用者體驗並不算流暢。但沒關係,我們的訴求只是開發出一些可供使用者體驗的產品,同時也構建了更好的 Announce 版本。隨著 COVID 疫情全面來襲,我們認為這正是做出改變的最佳時機,沒準 Announce 會成為各國政府在全球範圍內釋出公告的理想選擇。

當時使用者還沒有建立任何內容,但我們認為能在平臺上提供一些既有資料可能更好。所以我們又建立了 Announce-AI 專案,旨在自動釋出由 AI 建立的豐富內容。這裡的豐富內容是指各類事件、地震等安全警告,以及本地使用者可能關心的相關新聞。

1技術細節

為了開發 Announce-AI,我們決定使用 Cloud Functions。由於我們抓取資料的週期還很短,所以 Cloud Functions 幾乎是完美的選項。但在決定擴充套件規模之後,我們馬上遇到了麻煩——Cloud Functions 的超時時間長達 9 分鐘。

於是我們開始研究 Cloud Run,並發現它提供規模可觀的免費資源使用層!必須承認,那時候我們對 Cloud Run 並不夠了解,只是匆忙要求團隊在 Cloud Fun 上部署“測試”Announce-AI 功能。我們當時想得很簡單:儘快熟悉 Cloud Run,在探索中不斷學習。

為了簡單起見,我們在實驗中只引入一個很小的站點,就使用了 Firebase 作為資料庫(因為 Cloud Run 不提供任何儲存功能)。站點規模真的很小,完全用不上 SQL Server 或者任何其他成熟的商業資料庫。

我建立了名為 ANC-AI Dev 的新 GCP 專案,設定了 7 美元的雲資源使用預算,並選擇使用 Firebase Project on the Free(Spark) 計劃。我們當時覺得,最糟糕的結果應該無非就是超出每日 Firestore 的免費限額,對吧?

在稍稍調整了程式碼之後,我們開始部署流程,向其發出了幾條手動請求,而後就留下它保持執行。

2噩夢由此開始

測試當天一切順利,我們又回到了 Announce 本體的開發當中。在第二天下班之後,我稍微睡了一會。醒來之後,我發現郵箱裡有幾封來自 Google Cloud 的提醒郵件,而且郵件之間的間隔只有幾分鐘。

第一封郵件:Firebase Project 自動升級

第二封郵件:預算超支

幸運的是,我使用的信用卡設有 100 美元消費限額。於是收費停止,谷歌暫停了我們的所有賬戶。

第三封郵件:信用卡支付被拒

我跳下床,登入 Google Cloud Billing,並看到一張約 5000 美元的賬單。說實話,那一刻我慌得不行,根本沒辦法正常思考。我到處張望,想弄明白出了什麼問題,包括到底該怎麼付清這筆 5000 美元鉅款。

但問題在於,賬單金額每分鐘都在上漲。

5 分鐘之後,賬單數額增長到了 15000 美元;20 分鐘後,數額增長至 25000 美元。我不確定這一切什麼時候會停,或者說恐怕永遠不會停止?

2 個小時後,數額最終定格在 72000 美元。

這時我和我的團隊正忙著瘋狂確認情況。我徹底呆若木雞,根本不知道接下來該做點什麼。我們停用了結算功能,同時關閉了所有服務。

由於我們在全部 GCP 專案中使用的都是同一張對公支付卡,所以谷歌已經全面關停了我們的賬戶及專案。

3噩夢仍在繼續

事情發生在 3 月 27 日星期五晚上,即我們計劃釋出 Announce V1 的三天之前。由於谷歌凍結了繫結同一張信用卡的全部專案,我們的產品開發工作陷入了僵局。士氣低落,這家年輕的公司前途未卜。

所有云專案都被關停,開發工作陷入僵局

到這天午夜,我終於緩過神來,開始展開調查。我把調查工作中的每個步驟都詳細記錄在了檔案當中……並將檔案命名為“第 11 章”。

另外兩位團隊成員也加入了調查工作,與我一同不眠不休地探索真相。

第二天,也就是 3 月 28 日星期六,我打電話或發郵件給了十幾家律師事務所預約面談。大多數律所拒絕受理,只有一封郵件發來回覆,讓我具體解釋解釋整個過程。必須承認,這件事即使對工程師來說也是細節過多、複雜難懂,我壓根不知道該怎麼用簡單易懂的語言向律師做出說明。

作為一家自負盈虧的公司,我們拿不出 72000 美元。

到這時,我甚至認真研究過了《破產法》的第 7 章與第 11 章,並對接下來可能發生的一切做好了心理準備。

4喘息之機:GCP 的漏洞

就在同一個週六,我開始查閱更多內容,特別是 GCP 說明文件中的各種條目。好吧,我們確實犯了錯誤,但谷歌在一筆實際支付都沒完成的情況下就給我們計上了 72000 美元的賬,這正常嗎?!

GCP 與 Firebase 

1. 自動將 Firebase 賬戶升級為付費賬戶

在註冊 Firebase 時,我們從沒想過這還帶自動升級的,提示條款中也絕對沒有提及。我們的 GCP 專案確實接受了結算條款,因為只有這樣才能正常使用 Cloud Run;但 Firebase 不是,我們用的可是免費計劃。GCP 突然就進行了升級,並向我們收取鉅額費用。

事實證明,他們就是這麼設計的,理由是“Firebase 與 GCP 深度整合。”

2. 所謂的計費“限額”根本不存在,預算管理至少延遲了一天

GCP Billing 實際至少了延遲了一天。谷歌在大多數說明文件中都建議使用者使用 Budgets 與自動關閉雲功能。但你猜怎麼著?在中斷功能被觸發或者通知到雲使用者時,問題可能已經發生了。

結算過程大約需要一整天時間,所以我們第二天才收到計費提醒。

3. 谷歌應該向我們收取 100 美元,而不是 72000 美元!

由於我們的賬戶一直沒有實際支付,所以 GCP 應該先根據賬單資訊收取 100 美元的費用,並在無法繼續付款後停止服務。但實際情況並非如此,後來我弄清了原因,問題仍然跟使用者這方無關。

我們賬戶的第一筆費用約為 5000 美元,下一筆就暴漲到了 72000 美元。

我們賬戶的計費上限為 100 美元

4. 別相信 Firebase 儀表板!

不只是 Billing 功能,就連 Firebase 儀表板也要超過 24 個小時才能正常更新。

根據 Firebase 控制檯說明文件,Firebase 控制檯的儀表板數字可能與 Billing 賬單報告“略有不同”。

以我們的情況為例,二者的差異高達 86585365.85%,也就是 86 萬倍。而且在向我們發出賬單之後,Firebase 控制檯的儀表板仍然顯示當月出現了 42000 次讀取 + 寫入操作(低於每日上限)。

5新的一天,新的挑戰

我之前曾在谷歌工作過大約六年半,也寫過幾十份專案說明文件、取證報告。結合過往工作經驗,我整理出一份檔案,向谷歌概述了這次事件,並總結了谷歌方面的錯誤和疏漏。照理來說,兩天後的週一,谷歌工作小組就會正常上班並接手處理。

增訂:部分讀者朋友建議我直接跟之前的谷歌同事聯絡。事實上,我沒有動用任何原有的人脈,使用的就是普通開發商 / 公司採取的常規辦法。於是乎,我在聊天頻道、諮詢、冗餘的電子郵件和一個個小錯誤身上浪費了無數時間。下面,咱們具體來看交涉過程中的種種細節。

離開谷歌的那一天

與此同時,我們也在整理自己這邊犯下的錯誤,並制定新的產品開發策略。團隊裡還有不少人根本不清楚發生了什麼,只知道公司遇上了大麻煩。

作為前谷歌員工,我有豐富的“犯錯”經驗,還給谷歌造成了數百萬美元的損失。但谷歌的企業文化拯救了員工(當然,涉事工程師還是得寫一份長長的事件回顧報告)。這一次,我不再是谷歌人,我們手頭的資金有限、而之前投入巨大心力的成果正身陷風險。

先來看一個數字:1160 億,這是我們的測試程式碼在一個小時之內讀取 Firestore 資料庫的次數。

這是我人生中第一次遭遇如此重挫,有可能徹底改變整個公司乃至我生活的未來方向。關於問題,我們可以說很多,但其中最重要的反而是個簡單的道理——保持堅強。

作為一家小公司的管理者,我手底下只有一支由 7 名工程師 / 實習生組成的團隊。谷歌那邊大概得 10 天左右才能與我們進一步接洽。在此期間,我們必須恢復開發,找到解決賬戶關停的方法。此外,產品及功能的設計工作也得儘快重啟。

6我們到底做了什麼?

因為團隊規模不大,我們希望儘可能使用無伺服器架構。而 Cloud Functions 與 Cloud Run 等無伺服器解決方案處理問題的基本思路,就是超時。

具體來講,例項會持續將 URL 抓取到網頁當中;但在 9 分鐘後,該例項就會超時。

可能是失敗激發了腦中的智慧,我在幾分鐘內就在白板上列出了一大堆設計問題。不知道為什麼,在部署之前,我們能想到的就只有快速犯錯、快速嘗試。

Announce-AI 在 Cloud Run 上的“Hello World”版本

為了克服超時限制,我建議使用 POST 請求(將 URL 作為資料)將作業傳送至某一例項,且併發使用多個例項以替代序列使用單一例項。這樣 Cloud Run 中的每個例項只會抓取一個頁面,所以永遠不會超時。另外,由於 Cloud Run 的處理操作能夠精確到毫秒,所以全部頁面都將得到併發處理,整體效能得以高度最佳化。

部署在 Cloud Run 上的抓取器

如果仔細觀察,就會發現流程中缺失了一些重要的部分:

不中斷的指數遞迴:由於沒有 break 語句,因此例項不知道該何時中斷。POST 請求可以具有相同的 URL。如果存在指向上一頁的反射連結,則 Cloud Run 服務將陷入無限遞迴當中;而最糟糕的是,這個遞迴將呈指數增長(我們將最大例項數設定為 1000!)。

大家可以想象,這意味著多達 1000 個例項會不斷查詢,且每幾毫秒就向 Firebase 資料庫寫入一次。檢視資料釋出事件,我們發現 Firebase 在某一時間點上的每分鐘請求數量增長到了 10 億個!

GCP Billing Account 的月末交易摘要 

1160 億次讀取,3300 萬次寫入

總體來看,我們這套部署在 Cloud Run 的“Hello World”版本共執行了 1160 億次讀取與 3300 萬次寫入……我的媽呀!

Firebase 上的讀取操作成本:

(0.06 美元 / 100,000) * 116,000,000,000 = 69,600 美元

1600 個 Cloud Run 計算時

在 24 個小時之內,這些服務版本各自擴充套件到了 1000 個例項,共消耗掉 16022 個計算時。

7我們犯了什麼錯誤?

在雲上部署了存在缺陷的演算法

使用預設選項部署 Cloud Run

在建立 Cloud Run 服務時,我們在服務中選擇使用預設值,即 max-instances 被設定為 1000,concurrency 設定為 80。一開始我們並不知道,這些預設值對我們的測試程式來說可以算是最不適用的組合。

如果我們把 max-instances 設定為 2,那我們的成本只會是現在的五百分之一,即由 72000 美元轉變為 144 美元。

如果我們將 concurrency 設定為 1,那麼基本不會產生任何費用。

在不完全瞭解的情況下使用 Firebase

有些經驗必須從實踐當中獲取。Firebase 不像是能夠直接學習的程式語言,它是谷歌提供的一項容器化平臺服務,其中使用的是大量預定義規則,而且規則內容跟使用者的直覺或者傾向沒有任何關係。

另外,在 Node.js 中編寫程式碼時,必須注意後臺程序。如果程式碼進入後臺程序,則開發者很難意識到該服務仍在執行、而且在很長一段時間內持續執行。後來我們發現,這正是我們大多數雲功能同樣出現超時的原因所在。

別在雲上搞“快速失敗、快速學習”

雲平臺像是一把雙刃劍。如果使用得當,它確實威力巨大;但如果使用不當,後果也將極為嚴重。

翻翻 GCP 說明文件,大家就會發現它的頁數比幾本小說加起來還多。換言之,瞭解雲定價及使用方式不僅非常耗時,而且要求相關人員充分了解雲服務的工作原理。所以,別以為在傳統頭銜前面加個“雲”是騙人的——這真是項技術活!

Firebase 與 Cloud Run 真的很強大

在峰值時期,Firebase 每分鐘能夠處理約 10 億次讀取,這真是太強大了。我們已經在 Firebase 上測試了 2 到 3 個月,目前仍在繼續學習,但完全沒有觸及到它的極限。

Cloud Run 也是如此!當 Concurrency == 60, max_containers == 1000 且每條 Request 用時 400 毫秒時,Cloud Run 每分鐘能夠處理 900 萬條請求!

60 * 1000 * 2.5 * 60 = 9,000,000 請求/分鐘

相比之下,谷歌搜尋每分鐘也只能完成 380 萬次搜尋。

使用 Cloud Monitoring

雖然 Google Cloud Monitoring 不會停止計費,但它能及時傳送警報(延遲僅為 3 到 4 分鐘)。Google Cloud 的原型 / 命名結構有一定學習曲線,但在投入時間和精力之後,儀表板、警報與指標確實能讓我們更為輕鬆。

這些指標將保留 90 天。遺憾的是,我們在此次事件中的指標已經過期了,否則我很樂意在本文中向大家展示。

8好訊息:我們沒倒閉!

但很懸,太懸了

我們又恢復了活力,能夠繼續開發 Announce。而且這一次,我們擁有更好的視角、更強的架構與更安全的實現思路。

谷歌是我最欣賞的科技企業,這不只是因為它是一家值得為之工作的偉大公司,同時也因為它有著很強的同理心。谷歌提供的工具很合開發者的胃口,很重視說明文件質量(大多數情況下),而且一直在不斷髮展。(作者注:這只是我作為獨立軟體開發者的個人感受,絕非軟文或者刻意吹捧。)

9接下來怎麼辦?

經歷了這次事件,我們花了幾個月時間學習雲架構和我們自己的業務體系。幾周之後,我們的知識提升到新的境界,於是開始使用經過改進的演算法透過 Cloud Run 抓取“整個網路”。

而在事後的整體分析中,我們決定放棄 V1 版本架構,轉而使用更具可擴充套件性的基礎設施為產品提供支援。

在 Announce V2 中,我們不再構建 MVP;相反,我們打造出一套平臺,藉此快速迭代新產品,並在安全環境中進行全面測試。

這段經歷確實拖慢了我們的腳步……V2 在 11 月底才正式亮相,比原計劃的 V1 釋出日晚了大約 7 個月。但 V2 可擴充套件性更強,能夠更充分地動用雲資源,同時也擁有更好的最佳化水平。

我們還得以將其推向所有平臺,而不僅僅是 Web 平臺。

更重要的是,我們利用同一套平臺構建起第二款產品 Point Address。這兩種產品不僅可擴充套件性極佳、擁有出色的架構與高效性,還建立在同一套平臺之上。這使我們得以快速將業務靈感轉化為現實,並立即將其引入實際產品當中。

14
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Drupal8 Theme Twig主題模板