Skip to main content

Command Palette

Search for a command to run...

Lesson 25: 淺談 單體架構、微服務架構與單/多租戶架構

Published
2 min read

過去我們討論了 要把程式寫在哪、程式要怎麼拆的題目,接下來我們來看看「如何服務不同客戶」,這些架構反映了軟體開發在擴充性與複雜度之間的權衡。

軟體架構深度解析:從系統拆分到商業規模化

在軟體工程的演進中,架構的選擇往往是在「開發效率」、「系統擴充性」與「營運成本」之間尋求平衡。我們可以從兩個核心維度來觀察這些架構:系統如何運行(單體 vs. 分散式) 以及 如何服務客戶(單租戶 vs. 多租戶)。

規模與擴展維度:程式該如何運行?

單體架構 (Monolithic Architecture)

整個系統(API、業務邏輯、資料存取)打包成一個應用程式部署。

一個典型的Laravel 專案就是單體架構。

  • 代表實例: 標準的 Laravel 或 Rails 專案。

  • 特性: 同步的 Function Call、共用單一資料庫、單一部署流程。

  • 優點: 初期開發速度極快、測試與部署簡單、維運壓力小。

  • 缺點: 「牽一髮而動全身」,任一模組崩潰會導致全站失效;且難以針對特定功能進行水平擴展(Scaling)。

分散式架構 (Distributed Architecture)

系統跨越多個節點運行,透過網路協作完成任務。微服務即是分散式架構的一種具體實現。

  • 關鍵挑戰: 必須面對 CAP 定理 的物理限制(一致性、可用性、分區容忍性)。

  • 優點: 高可用性(HA)與強大的水平擴展能力,具備容錯機制。

  • 缺點: 網路延遲、數據一致性(Eventual Consistency)問題,以及複雜的 Race Condition 處理。

微服務架構 (Microservices Architecture)

將系統拆分為「多個獨立服務」,每個服務負責單一業務能力(bounded context)。

  • 特性: 每個服務獨立部署、擁有專屬 DB、透過 HTTP/gRPC/MQ 通訊。

  • 核心痛點: 運維複雜度(Observability)與分散式交易處理(如 Saga Pattern)。

  • 決策關鍵: 依據 DDD(領域驅動設計) 的「界限上下文」來拆分,避免淪為分散式單體。

  • 一致性模型改變:單體架構可以容易地實現強一致性,微服務在「跨服務」場景下通常需要採用最終一致性。

常見設計 Pattern

  • API Gateway

  • Circuit Breaker

  • Saga Pattern

  • Event-driven Architecture

服務與商業維度:如何服務不同客戶?

當進入 SaaS(軟體即服務)領域時,核心決策點在於如何處理多個客戶(Tenant)的數據與資源。

獨立部署(單租戶模型)

每個客戶擁有獨立的運行環境與資料邊界。

  • 適用: 高資安需求的標案或極大企業客戶。

  • 問題: 維護 100 個客戶需要更新 100 次,難以規模化。

多租戶架構(Multi-Tenant Architecture)

一套系統服務「多個客戶(Tenant)」,但資料彼此隔離。多租戶架構主要是在「SaaS 情境下的資料隔離策略」。

  • 資源利用度高且多客戶管理容易(集中部署與統一版本管理)

  • 權限與資料隔離設計需要更謹慎且複雜

  • 在多租戶架構中,當租戶數量成長時,會面臨資料遷移與資源重新分配(例如:將大型租戶遷移至獨立資料庫)的挑戰。

三種實作模式

  1. Shared DB, Shared Schema

    • tenant_id 區分

    • 成本最低,但隔離性最差,任何 query 若未正確套用 tenant 條件(例如:global scope),將導致資料越權存取

  2. Shared DB, Separate Schema

    • 每個 tenant 一個 schema,隔離性提升 且可以 可 partial backup

    • schema 管理複雜、migration 要處理多 schema

  3. Separate Database(DB Per Tenant)

    • 每個 tenant 一個 DB

    • 隔離最好,成本最高

實務運用

單體與微服務的邊界

當單體要轉微服務時,最難的不是技術,而是「怎麼拆」。

  • 關鍵概念: DDD(領域驅動設計)中的 界限上下文。

  • 實務建議: 如果邊界劃分錯誤(例如:訂單服務與庫存服務耦合太深),會變成最糟糕的情況——「分散式單體」。這具備了微服務的所有缺點(網路延遲、部署複雜),卻沒有任何優點(開發依然互相牽制)。

分散式架構的幽靈:CAP 定理

在討論分散式與微服務時,CAP 定理是繞不開的物理限制。

  • 一致性 (Consistency)

  • 可用性 (Availability)

  • 分區容忍性 (Partition Tolerance) 在分散式系統中,我們被迫在 C 與 A 之間做選擇。例如:

  • 金融交易: 寧可系統暫時無法服務 (A),也要保證金額絕對正確 (C)。

  • 社群貼文: 寧可讓不同使用者看到稍微不同的按讚數 (C),也要保證系統隨時能讀取 (A)。

多租戶架構的隱形陷阱:Noisy Neighbor

在 SaaS 開發中,多租戶最怕 吵鬧鄰居 效應。

  • 問題: 當 A 租戶突然有暴增流量,若使用「共享資料庫 (Shared Schema)」,B 租戶的服務品質也會下降。

  • 解決方案: 這時需要引入 Rate Limiting(限流) 或 Resource Quota。如果你的客戶是像「台積電」這種等級的大企業,通常會要求 Separate Database,不只是為了效能,更多是為了資安合規。

結論

選擇架構時不應盲目追求「微服務」,因為架構的引入是有代價的。很多成功的產品都是從單體開始,隨後演進為分散式,最後為了團隊協作才拆分為微服務。而多租戶則是打算將這套系統賣給多個客戶時,必須考慮的數據隔離策略。

從Rookie到Junior,一個後端成長的30堂課

Part 2 of 31

“從 Rookie 到 Junior:一個後端成長的 30 堂課” 是一套專為後端新手所設計的成長型技術系列文章。內容以實務為導向,逐步拆解後端工程的核心能力,包括程式語言基礎、架構思維、框架運作原理、業務邏輯設計、資料庫操作、以及常見的開發模式。 本系列的目標是協助讀者從零散的學習堆疊,建立成體系的後端知識框架。讀者能夠理解各語言背後不變的工程思維與設計原則。這套內容旨在讓學習者從「會寫程式」進入「能理解系統設計」的階段,逐步具備勝任 Junior Backend Engineer 的能力。

Up next

Lesson 24: 資料庫擴展術-讀寫分離、複寫機制與快取一致性挑戰

為什麼要讀寫分離? 大多數的 Web 應用都是 「讀多寫少」(例如:看文的人多,發文的人少,Heavy Read System)。當所有的請求都塞給同一台資料庫時,磁碟 I/O 和連線數會成為瓶頸。 Master (主庫): 負責寫入 (Insert/Update/Delete),確保數據一致性。 Slave (從庫): 負責讀取 (Select),可以有多個從庫來分擔讀取壓力。 為什麼讀

More from this blog

Lesson 26 : 系統韌性的守護者-限流、熔斷與背壓的設計模式

當這幾個名詞出現後,代表我們進到了一個高併發/大流量的系統了。在這個章節中,我們一起來看看如何透過一些方式來避免高併發導致我們的系統crash掉。 限流(Rate Limiting) 相信大家對這個名詞並不陌生,限流其實就是字面上的含意,限制流量。 限流的目的是保護「接收方」,確保系統不會因為瞬間的高併發請求而癱瘓。 限流通常發生在 API Gateway 或服務的最前端。它像是一個夜店門口的保全

Mar 26, 20262 min read

Lesson 24: 資料庫擴展術-讀寫分離、複寫機制與快取一致性挑戰

為什麼要讀寫分離? 大多數的 Web 應用都是 「讀多寫少」(例如:看文的人多,發文的人少,Heavy Read System)。當所有的請求都塞給同一台資料庫時,磁碟 I/O 和連線數會成為瓶頸。 Master (主庫): 負責寫入 (Insert/Update/Delete),確保數據一致性。 Slave (從庫): 負責讀取 (Select),可以有多個從庫來分擔讀取壓力。 為什麼讀

Mar 25, 20262 min read

面試經驗談 2025-2026

從2025年3月開始,我陸陸續續參與了從新創到上市櫃公司的Senior - Tech Lead的相關面試,其中有不乏 尊重面試者、展現高度專業的企業(公司),當然也有遇到幾場面試鬼故事,這篇文章主要分享我對於軟體工程師面試的方向分享,以及部分鬼故事,以此警惕自己不要成為這樣的面試官。 AI的洪流,改變了SWE的生態 LLM的發展確確實實的影響到了軟體工程師的生態。 過去受限於算力與資料規模,深度學

Mar 23, 20262 min read

Lesson 23: 系統的緩衝區-Queue 佇列與非同步處理 (Asynchronous)

佇列 佇列的實作工具非常多,舉凡AWS SQS、RabbitMQ、Kafka…等。 佇列的特性,其實是一個非常強大的系統緩衝區,應用層面非常廣。 什麼是佇列? 佇列可以想像成,在既有流程中外,有另一個”水管”,來連接原有的資料流(或邏輯過程),其中 呼叫方將資料 推(Push)到水管中,接受方(監聽) 從水管中將資料拉(Pull)出處理 為什麼佇列是「強大的緩衝區」? 在同步處理中,系統像是一

Mar 23, 20262 min read

Bennett's Tech Blog | 後端架構、系統設計

32 posts

來自台灣的軟體工程師,相信軟體可以改變世界