單一 Repo,不是微服務
微服務的承諾很誘人:獨立的團隊、獨立的部署、獨立的擴展。對大多數公司來說,現實卻是完全不同的東西。
這個 framework 建立在 monolith 之上。單一 repo、單一程式碼庫、單一套規範。而當你需要擴展時——你以類似微服務的方式部署同一套程式碼,而不需要拆分 repo。
微服務實際上的代價
反對微服務的論點,不是說它們在技術上是錯的。而是說它們是一個組織解法,被用來解決一個團隊規模的問題。
微服務在你有數百位工程師在真正獨立的領域工作時才有意義——那時協調單次部署的成本,超過了運營分散式基礎設施的成本。Netflix 有這個問題。你幾乎肯定沒有。
對於規模在約 50 人以下的團隊,微服務製造的問題多於它解決的:
五個 repo 意味著五段入職體驗。 每位新工程師必須學的不是一個程式碼庫,而是整個生態系。不同的規範、不同的工具、不同的部署 pipeline。你的升溫時間成倍增加。
跨服務除錯是噩夢。 跨越服務邊界的 bug,需要跨多個 log、多個環境、多個 repo 追蹤一個 request。在 monolith 裡 10 分鐘能修完的事,變成了兩小時的考古工程。
「獨立團隊」的假設是錯的。 在新創公司或成長期公司,你沒有獨立的團隊——你有一個身兼多職的團隊。你的前端工程師會碰 auth。你的 backend 主力會碰 billing。在一個無法真正遵守服務邊界的團隊上強加人為的邊界,帶來了協調開銷,卻沒有任何承諾中的自主性。
一致性會衰退。 當你的用戶服務是 Node.js、帳單服務是 Python、通知服務是 Go,你已經保證了任何在它們之間移動的工程師每次都必須切換 context。函式庫各自漂移。錯誤格式不同。監控不一致。程式碼庫不再是程式碼庫,而是一群碰巧共享同一個領域的專案集合。
真實代價:一千萬美元與凌晨兩點醒來的 DevOps 團隊
在 FiscalNote,我們在 AWS 上跨多種語言運行了 17 個服務。我們有一支專職的 DevOps 團隊。他們定期在凌晨兩點醒來救火——不是偶爾,而是定期。系統太複雜,無法做到可靠;太客製化,沒有任何一個人能完全理解。
那些架構決策的總代價——工程師薪資、重寫專案、運營開銷、因為動不了而錯失的機會——在十年間超過一千萬美元。這個數字不是假設性的。這是糟糕的架構在你把帳算清楚之後真正的代價。
在 Nitra,用 monolith 在託管服務上運行 Orbital Express:五年來零基礎設施事故。零 on-call 呼叫。零 DevOps 團隊。原本要花在基礎設施管理上的時間和金錢,全部拿去開發功能了。
Monolith 的優勢:單一 repo,完全一致
單一 repo 意味著:
- 單一套規範。 每個 feature folder 長得一樣。每個 model 遵循相同的模式。每個 action 有相同的結構。碰過一個功能的工程師,第一天就能在任何其他功能中導航。
- 單一段入職體驗。 學一次 framework。立刻在任何地方做出貢獻。
- 共享函式庫、共享 schema、共享常數。 服務之間不再漂移。不再有「哪個服務有 canonical 的 user schema?」不再有內部套件的版本不符。
- 跨功能的工作輕而易舉。 需要從 Notifications 功能查詢 Orders 表?import model。完成。在微服務架構中,那是一個有延遲、有故障模式、有需要維護的合約的同步 API 呼叫。
- 單一部署 pipeline。 push 程式碼,它就部署了。沒有「先部署服務 A,等一下,部署服務 B,確認它們相容」。
當你需要擴展:像微服務一樣部署,留在單一 repo
這是大多數人忽略的部分:你不需要拆分 repo 就能獲得水平擴展。
Orbital Express 是一個標準的 Express.js 應用程式。當你準備好擴展到單一伺服器之外,你可以把同一套程式碼部署到多台伺服器,並配置每個實例只處理你 API 路由的一個子集。
Server A → handles /v1/users/*, /v1/auth/*
Server B → handles /v1/orders/*, /v1/payments/*
Server C → handles /v1/notifications/*, /v1/search/*每台伺服器跑相同的程式碼、相同的資料庫連線、相同的規範。你在 load balancer 層路由流量。你根據負載獨立擴展各台伺服器。你得到了水平分散,卻不需要拆分任何一個檔案。
程式碼庫保持統一。入職保持簡單。規範保持一致。你擴展的是基礎設施,而不是複雜度。
關於託管部署:Heroku 和 Render
AWS 的論點是相關的。AWS 給你對基礎設施的最大控制權。它向你收取的代價是巨大的運營負擔:VPC、IAM 政策、負載平衡器、auto-scaling group、自訂部署 pipeline、監控配置、on-call 輪值。
對一個產品團隊來說,這不是個好的交換。在配置基礎設施的工程師,沒有在開發功能。DevOps 團隊是一個不交付任何用戶看得見的東西的開銷。
託管平台——Heroku、Render、Railway——幫你處理基礎設施,讓你不必操心。它們是生產級、可靠的。部署就是 git push。擴展是一個滑桿。資料庫幾分鐘內就能配置好。運營開銷降到趨近於零。
當你是新創公司或成長期公司,唯一重要的指標是你能多快交付用戶想要的功能。託管部署讓這個指標最大化。自己管理 AWS 讓它最小化。
使用託管服務,直到你有具體的特定理由不這樣做。大多數公司永遠到不了那個時間點。
這一切背後的模式
Monolith 的推薦、託管部署的推薦、單一語言的推薦——它們都是同一個論據:
複雜度是一種稅。你增加的每一層複雜度,都要付出入職時間、培訓開銷和除錯工時的代價。這份工作就是在建出能擴展的東西的同時,把這個稅降到最低。
一個結構良好的 monolith,在託管服務上運行,在需要時部署到多台伺服器,能給你微服務在自建基礎設施上所能給你的 90%——卻只需要 10% 的運營成本。
這就是我們在這裡做的交換。這是正確的交換。