“騎手與大象”架構:超越微服務與單體之爭的務實之道?
在軟件架構的江湖里,關于“微服務”與“單體”的論戰,幾乎從未停歇。一方推崇微服務的靈活性、可擴展性和獨立部署,另一方則堅守單體的簡潔性、低通信開銷和易于本地調試。近年來,我們甚至看到像亞馬遜 Prime Video 這樣重量級的玩家,也公開分享了其從微服務“回歸”到某種形式的單體(或者說更粗粒度的服務)的實踐,引發了業界新一輪的思考。
這不禁讓我們反問:微服務與單體,真的就是非此即彼的“二元對立”嗎?
最近,國外一家名為DealGate公司的一篇文章《Introducing the Rider and Elephant Software Architecture》,提出了一種他們稱之為“騎手與大象”的架構模式,試圖在這場看似無解的爭論中,找到一條務實的中間道路。這種模式不僅在他們的實踐中取得了顯著成效,其背后的設計哲學和對技術選型的思考,也頗具啟發意義。
“騎手與大象”:一個古老隱喻的現代架構演繹
DealGate 將其架構模式命名為“騎手與大象”,其靈感來源于心理學中的一個經典比喻:人類的思維由兩部分組成——理性的“騎手”(對應我們發達的前額葉皮層,負責規劃、分析和決策)和感性的、更強大的“大象”(對應我們原始的、更底層的“蜥蜴腦”或“穴居人腦”,驅動著本能和情緒)。騎手雖然可以嘗試引導大象,但無法完全控制它;而如果騎手想獨自前行,又會發現大象的力量是其無法比擬的。只有當騎手與大象協同合作時,才能發揮出最大的效能。
在 DealGate 的架構中,這個隱喻被巧妙地映射到了技術組件上:
- “大象 (Elephant)”:由 Go語言構建的應用。它不包含任何復雜的業務邏輯,但卻承擔著所有“臟活累活”——大規模的、高并發的數據處理。在 DealGate 的場景中,這可能意味著在任何時刻都有數萬個 goroutine 在處理圖像、PDF,抓取數千萬級別的網頁,并在每個網頁上運行數千萬次的正則表達式匹配?!按笙蟆钡暮诵穆氊熓牵簭姶蟆⒏咝?、能扛事兒。
- “騎手 (Rider)”:由NextJS (Node.js) 構建的應用。它承載了所有的業務邏輯、數據庫訪問、用戶交互等?!膀T手”的核心職責是:靈活、敏捷、快速響應業務變化。
- 韁繩 (Communication):“騎手”通過 gRPC 來“引導”和控制“大象”,兩者之間保持低開銷、高效率的通信。
這種架構的核心思想是:將需要極致性能和高并發處理的“重計算”部分(大象),與需要快速迭代和靈活業務邏輯的“輕應用”部分(騎手)進行分離,并讓它們通過高效的通信方式協同工作。
為何選擇“騎手與大象”?DealGate 的實踐與思考
DealGate 之所以采用這種架構,源于他們在實際業務中遇到的挑戰和對現有架構模式的反思。
- 對“微服務 vs 單體”的“虛假二分法”說不:他們認為,單純地在微服務和單體之間做選擇,往往忽略了業務的復雜性和多樣性。他們希望能夠“have the best of both worlds”(取兩者之長)。
- Node.js/NextJS 的局限性:盡管 DealGate 的主要應用是用 NextJS 編寫的,但他們發現,即使 Node.js 在 I/O 和網絡處理上有多線程優勢,其正則表達式等 CPU 密集型操作仍然受限于單線程(JavaScript 的執行模型)。當需要在后臺進行大量正則匹配,同時還要響應 Web 應用請求時,性能瓶頸就顯而易見了。
- Go 語言的“大象”潛質:文章中明確指出:“Go語言非常適合這種場景,你可以輕松地扔給它數萬個CPU密集型進程,它會愉快地處理掉所有這些”。這充分肯定了 Go 語言在并發處理和性能方面的核心優勢。
- 對微服務通信開銷的警惕:DealGate 批評了許多微服務架構使用 JSON 進行進程間通信的做法,認為其“序列化和反序列化開銷是令人發指的”。他們選擇 gRPC,正是為了最大限度地降低“騎手”與“大象”之間的通信成本,確保即使在需要傳輸大量數據(因為“大象”不包含業務邏輯,需要被視為“愚笨的工人”)的情況下,也能保持高效。
Go 語言:扮演“大象”的理想之選
在“騎手與大象”的架構中,Go 語言之所以被選中扮演“吃苦耐勞的大象”,并非偶然。這得益于 Go 語言的核心特性:
- 極致的并發性能:Goroutine 和 Channel 機制,配合高效的調度器,使得 Go 能夠輕松創建和管理海量的并發任務,這對于處理 DealGate 所述的“數萬個 goroutine 同時處理數據”的場景至關重要。
- 高效的執行效率:Go 語言編譯為原生機器碼,其性能接近 C/C++,遠超解釋型語言,非常適合 CPU 密集型的數據處理任務。
- 強大的標準庫:Go 的標準庫提供了豐富的網絡編程、文本處理(包括正則表達式)、數據編解碼等功能,為構建“大象”應用提供了堅實的基礎。
- 簡潔的部署:Go 應用可以編譯成單個靜態鏈接的可執行文件,部署簡單,依賴少。
可以說,Go 語言的設計哲學和核心能力,使其成為承載這種“無業務邏輯、高并發、重計算”角色的理想選擇。
語言選型的“二八原則”與“務實主義”
“騎手與大象”架構的另一個核心啟示,在于其對不同技術棧的選擇策略,體現了一種深刻的“務實主義”和對“成本效益”的考量。
文章明確反駁了“既然有更高性能的語言(如 Rust 或 Go 本身),為什么不把所有應用都用它來寫?”的觀點,并將其類比為“那所有應用都應該用匯編來寫了”。
其核心邏輯是:
- 高級語言(如 JavaScript, Python)的優勢:更安全(內存管理等)、生產力更高(表達力強、語法糖和輪子多)、開發者社群更大、單位時間開發成本相對更低。
- 高性能/底層語言(如 Go, Rust, C++)的優勢:性能極致、對系統資源有更精細的控制。但通常也意味著更陡峭的學習曲線、更高的開發成本、以及(在某些情況下)更長的開發周期。
DealGate 的策略是:“在你必須快的地方快,其他一切都選擇高級語言和(相對)單體的模式。” 這意味著:
- 將昂貴的、需要精細優化的高性能代碼(大象)限制在最小的必要范圍內(例如,只占整個業務系統的 10%)。
- 將大部分的業務邏輯、用戶交互(騎手)用生產力更高、開發更快的高級語言來實現。
這種“混合編程”或“多語言架構”的思路,實際上是在性能、開發效率、人才獲取成本、維護成本等多個維度之間進行權衡和優化。它提醒我們,技術選型不應盲目追求“最新最酷”或“性能極致”,而應服務于業務需求,并充分考慮團隊和公司的實際情況。
文章中也提及了對“Just write Rust”(就用 Rust 寫)這類口號的反思,指出大多數公司和開發者可能無法承擔全員學習和使用像 Rust 這樣“高門檻”語言的成本。這并非否定 Rust 的優秀,而是強調技術選型的現實約束。
小結:“沒有完美的解決方案,只有明智的權衡”
“沒有完美的解決方案,只有權衡取舍”。DealGate 的文章以這句經典的名言作為總結,恰如其分。
“騎手與大象”架構,正是在微服務的靈活性、分布式能力與單體的低心智負擔、高開發效率之間做出的一種明智權衡。它并非適用于所有場景的“銀彈”,但在類似 DealGate 這樣需要處理大規模數據密集型任務,同時又需要快速迭代業務邏輯的場景下,無疑提供了一種極具價值的、務實的架構思路。
它也再次印證了一個樸素的道理:優秀的架構設計,往往不是對某種“主義”的盲從,而是對業務需求的深刻理解和對不同技術優劣的精準把握,最終在各種約束條件下找到那個“恰到好處”的平衡點。
或許,在微服務與單體的喧囂爭論之外,我們更應該學習這種“騎手與大象”的智慧——在正確的地方,用正確的方式,做正確的事情。
參考文獻: Introducing the Rider and Elephant Software Architecture - https://d-gate.io/blog/rider-and-elephant-architecture































