在生產環境中實施微服務

最後更新: 22月2026
  • 微服務需要對服務、資料、彈性以及契約進行精心設計,才能在生產環境中正常運作。
  • Kubernetes/OpenShift、CI/CD 和 GitOps 實現了大規模部署、擴展和維運的自動化。
  • 零信任安全、強大的配置管理以及透過 OpenTelemetry 實現的可觀測性是該平台的支柱。
  • 產品團隊組織和分散式治理與所選的技術同等重要。

生產環境中的微服務架構

在實際環境中採用微服務架構並非只是將單體應用程式分割成更小的模組;它還涉及對基礎設施、團隊、流程、資料、安全性和運維的重新思考。當系統從理論走向生產集群時,服務發現、團隊間契約、持續整合/持續交付 (CI/CD)、可觀測性、彈性以及可擴展性等方面都會出現問題。如果這些問題無法妥善解決,微服務架構可能會變成分散式混亂。

好消息是,如今我們擁有來自 Netflix、亞馬遜、Google等大型企業累積的豐富經驗,這些企業在生產環境中運作著數百個微服務。借鑒這些經驗,結合企業環境中使用 Kubernetes 和 OpenShift 的最佳實踐,我們可以開發出非常穩健的方法,用於大規模地設計、部署和運行微服務,而不會失去控制。

為什麼要將微服務部署到生產環境(以及何時不值得這樣做)

精心設計的微服務架構可讓您與小型、自主且跨職能的團隊合作,這些團隊負責端到端的服務。每個團隊都在定義明確的上下文中運行,可以頻繁部署,並對其服務承擔全部責任,從而縮短開發週期並加快新功能的交付。

另一個關鍵優勢是每個服務可以獨立擴展。如果只有商品目錄、結帳頁面或公共 API 出現流量高峰,您無需大幅擴展整個應用程式。您可以根據每個微服務的負載模式進行水平或垂直調整,精確衡量每個功能的成本,即使特定區域的流量激增,也能保持可用性。

這些服務的打包和部署方式有助於實現持續、低風險的實施。獨立發布每個微服務使得測試新想法和回滾問題版本變得更加簡單:金絲雀部署、藍綠回滾和自動回滾降低了失敗成本,並為實驗提供了空間。

從技術角度來看,微服務架構允許開發者為每個服務自由選擇語言、框架和資料庫。並非所有需求都適合同一套技術堆疊:業務服務可能使用 .NET 或 Java,資料處理可能使用 Scala/Spark,專業服務可能使用 Python 或 F#,而 AI 微服務可能使用 R。這種可控的多樣性使開發者能夠針對每個特定情況選擇合適的工具,而無需對整個應用程式進行全局性的技術遷移。

此外,將系統分解成小的、定義明確的模組,以便將功能作為建置模組進行複用。最初作為更大功能的一部分創建的微服務,之後可以作為系統其他部分的依賴項進行複用,而無需重寫邏輯。而且,由於各個服務是相互隔離的,只要從一開始就設計了彈性機制,其中一個服務的故障通常只會導致部分系統效能下降,而不會導致整個系統癱瘓。

建築及服務設計

生產環境中的微服務設計

為了使微服務在生產環境中運作良好,至關重要的是首先要精心設計服務邊界和職責。實際上,這通常始於在現有單體架構中識別粗粒度服務:即已經存在一定邏輯分離的大型功能區域或業務領域(例如,訂單、目錄、使用者、計費)。

從這些大型建置模組出發,該流程包括對設計進行細粒度優化,以獲得基於統一資料集、擁有自身模型且明確知道需要從其他服務讀取或寫入哪些資料的微服務。此過程通常依賴領域驅動設計 (DDD) 的概念和限界上下文,從而防止微服務演變成「小型單體應用」。

提供這些服務的 API 必須具有定義明確且穩定的契約。這意味著需要編寫詳盡的文件(例如,REST 使用 OpenAPI,gRPC 使用 .proto 文件等),明確版本控制,盡可能保持向後相容性,並自動執行契約驗證,以便在變更進入生產環境之前檢測到破壞性變更。

在擁有數十甚至數百個服務的環境中,從設計階段就融入彈性模式至關重要,這樣系統才能應對部分故障。諸如斷路器、具有退避機制的重試、明確的超時時間、隔離區和反壓等模式有助於防止一個服務的故障導致其他服務癱瘓。 ChaosMonkey 或 Gremlin 等混沌工程工具可用於實際測試平台在模擬故障下的運作。

許多複雜的系統會將相對簡單的CRUD服務與處理不斷演變的業務規則的更複雜的服務相結合。並非所有微服務都需要複雜的內部架構:有些可以是提供基本資料存取的簡單HTTP控制器,而有些微服務,例如訂單或計費服務,則可以利用更高級的模式(例如領域驅動設計、CQRS、領域事件等)。

生產基礎設施:雲端、容器和 Kubernetes/OpenShift

實際經驗表明,微服務部署在基於容器和編排的雲端基礎架構上,效能遠優於部署在隔離的虛擬機器上。 Kubernetes 和 OpenShift 等平台提供了必要的底層機制,可以將服務打包成容器,並實現擴展、更新、負載平衡和高可用性管理。

  軟體工程師做什麼:角色和職責

通常,每個微服務都打包在一個基於企業基礎鏡像(例如,Java 服務使用 OpenJDK 21)的容器鏡像中,該基礎鏡像由基礎設施團隊管理。此基礎鏡像會定期更新安全性補丁,當發布新版本時,開發團隊負責在相應的環境中重建和重新部署他們的服務。

在 Kubernetes/OpenShift 中,基本部署單元是Pod,它封裝了一個或多個容器。通常,微服務對應一個 Pod 類型,並使用 Deployment(用於無狀態服務)或 StatefulSet(用於有狀態的服務)等資源進行部署。從一開始就為每個環境定義了最小副本數,以確保測試、預生產和生產環境的可用性等級與其重要性相符。

自動擴縮容功能透過Horizo​​ntalPodAutoscaler (HPA)實現,它會根據 CPU、記憶體或其他自訂指標等參數調整副本數量。平台還必須配置 Pod 反親和性規則,將相同服務的副本分佈在不同的節點上,以防止單一節點故障導致所有執行個體宕機。

關於垂直資源配置,`resources.requests` 和 `resources.limits`用來定義 Pod 可以使用的 CPU 和記憶體範圍。例如,為 Java 服務預留至少 100MB 的 CPU 和 256MB 的內存,並允許其分別使用高達 500MB 和 2GB 的 CPU 和內存,同時調整 JVM(Xms、Xmx、Xss)以充分利用容器的資源。

狀態管理:無狀態和有狀態微服務

大多數業務微服務都被設計成無狀態服務。這意味著 Pod 本身不儲存需要在重新啟動後仍然存在的資訊;狀態持久化在外部資料庫、訊息佇列或其他儲存媒體中。這種方法便於動態水平擴展和無縫部署,因為任何副本都可以處理任何請求。

然而,在某些情況下,使用持久卷支援的有狀態微服務是別無選擇。例如,某些資料庫、分散式檔案系統或需要維護本機資料的元件就屬於這種情況。這些 Pod 通常使用 StatefulSet 部署,並透過 PersistentVolumeClaims 連結到 PersistentVolume,並且採用垂直擴展而非水平擴展。

當微服務需要持久性儲存時,會要求一個包含其大小、存取模式和預期用途的持久性磁碟區聲明 (PVC) ,維運團隊會根據平台策略進行設定。該 PVC 會在部署清單中引用並掛載到 Pod 上,以便服務可以持久地讀寫資料。

雖然在特定情況下有狀態模型可能是必要的,但通常建議盡可能保持服務的無狀態性。這可以簡化部署、擴展、彈性恢復和災難恢復,並降低微服務眾多環境中的維運複雜性。

資料去中心化和服務主權

在傳統架構中,為了最大限度地提高效率,通常會將資料庫和儲存集中化。但在微服務架構中,這種方法與團隊自治和解耦相衝突。如果多個服務共享相同的關係型資料庫模式,任何結構性變更都可能阻礙多個團隊的工作,並無意中破壞相容性。

因此,建議的做法是每個微服務都有自己的資料模型和資料庫。在開發環境中,為了簡化部署,資料庫通常以容器的形式運行在叢集內。在生產環境中,通常會使用雲端託管執行個體或其他高可用性資料庫伺服器,並最終保持清晰的所有權邊界。

這並不意味著沒有資料整合;而是意味著服務間的一致性是透過事件和非同步訊息傳遞來管理的,並在合理的情況下接受最終一致性。通常使用事件匯流排(例如 RabbitMQ、Azure 服務匯流排、Kafka 等)在微服務之間傳播狀態變更,從而減少對單一資料庫的強烈依賴。

雲端平台讓團隊能夠輕鬆地為每個服務選擇最佳資料庫類型(關係型、文件型、鍵值型、時間序列型等),而無需強制採用單一技術。關鍵在於,設計方案考慮了在不破壞與其他服務契約的情況下遷移模式和結構的可能性,並且資料決策與每個微服務的領域邊界保持一致。

分散式治理、團隊和組織

如果不改變組織架構就轉向微服務,無異於自找麻煩。我們鼓勵採用以產品團隊為基礎的架構,摒棄傳統的網路、系統、資料庫、開發和維運等功能孤島,將開發、測試、維運以及(在適用情況下)業務或資料分析師等人員整合在一起。

每個團隊負責同一功能領域內的一個或多個微服務,包辦開發和維運(既負責建置也負責運作)。這意味著團隊需要管理自身的 CI/CD 管線,與基礎設施團隊合作以滿足特定需求,並參與監控和事件回應。基礎設施和雲端平台則專注於提供通用且標準化的服務。

  雲端運算:降低成本並提高公司效率

為了防止這種分散式治理陷入無政府狀態,定義輕量級標準和共享目錄至關重要:例如,已批准的基礎映像、部署模式、命名空間和服務的命名約定、API 指南、Dockerfile 和 Kustomize 範本等。這些指南就像「護欄」一樣,為團隊指明方向,同時又不妨礙他們做決策。

在許多企業環境中,每個專案或領域都會使用獨立的命名空間,每個環境(開發、預生產、生產)至少需要一個命名空間。大型專案可以將微服務分佈在多個命名空間中,前提是內部通訊配置正確且安全規則得到遵守。

CI/CD、自動化和 GitOps 模型

當一個架構包含數十個甚至數百個微服務時,保持其正常運作的唯一方法就是大力投資端對端自動化。這包括一致的 CI/CD 管線、聲明式部署定義、自動化測試和自動回溯機制。

典型的持續整合和交付管線負責編譯程式碼、運行測試、使用 SonarQube 等工具分析品質、根據企業 Dockerfile 建置容器映像以及更新部署清單。之後,ArgoCD 或類似系統會使用 GitOps 方法將這些變更套用到叢集。

每個微服務倉庫通常包含一個標準化的 Dockerfile、一個管線設定檔(例如 ci.json)、用於品質分析的屬性,以及一個部署目錄,其中包含按環境劃分的 Kubernetes 定義(Kustomize 或 Helm)。當發生標籤推送或合併請求等事件時,倉庫的 Webhook 會觸發管線。

GitOps 模式將Git 倉庫確立為基礎架構和部署的唯一資料來源。部署、服務、ConfigMap、PVC、SealedSecret 和其他資源的清單檔案都會在 Git 中進行版本控制,並且特定的工具會負責將叢集狀態與 Git 中的定義同步。這提供了可追溯性、拉取請求審查和便捷的回滾功能。

設定、秘密和安全

在成熟的微服務平台中,組態管理依賴ConfigMap 來儲存非敏感參數,而使用 Secret 來儲存機密資訊。每個微服務通常都有其自身特定於環境的 ConfigMap,其中儲存著依賴服務的 URL、功能標誌和調優參數等屬性。

機密資訊(憑證、金鑰、令牌、憑證)的處理遵循嚴格的安全策略。在較不重要的環境中,開發團隊可以將其以明文形式保存,但在預生產和生產環境中,建議使用 Sealed Secrets 等工具或特定的雲端外部管理器對其進行加密。

當需要在多個服務之間共用金鑰時(例如,OTEL Collector 憑證或公用金鑰庫),可以將其集中儲存在每個命名空間的組態儲存庫中。共享該命名空間的項目會根據需要進行協調更新,從而控制誰可以讀取或修改這些資源。

在通訊安全方面,主流模式是零信任:即使流量是「內部」的,也不能想當然。所有服務之間的調用,無論內部或外部,都必須經過身份驗證和授權,理想情況下使用 mTLS、JWT 令牌或其他等效機制。微服務不會盲目地將安全性委託給 API 管理器或網路;它們也會執行自身的安全性檢查。

微服務、API 和訊息傳遞之間的通信

在成熟的微服務架構中,通訊層被劃分為多個部分。對於從用戶端(瀏覽器、行動應用程式、第三方服務)到後端的流量,使用由 API 管理器管理的已發佈 API。這些 API 通常是 RESTful 的(通常使用 OpenAPI),或者在某些情況下,透過網關公開 gRPC。

位於同一命名空間內的微服務之間,甚至同一專案內跨多個命名空間的微服務之間的調用,通常由帶有內部 DNS 的內部 Kubernetes 服務處理。這些呼叫繞過了公共 API 管理器,但會遵循安全性、驗證和授權策略。對於這些場景,可以使用服務網格或強制執行通用策略的內部網關。

當微服務屬於不同的功能領域或專案時,組織層面的溝通被視為「公開的」。在這種情況下,通常的做法是使用 API 管理器或互通性匯流排,透過管理契約、配額、安全性、版本控制和稽核等機制,防止獨立叢集或命名空間之間的直接耦合。

對於與可能並非總是提供現代 API 的遺留系統或外部系統的集成,通常的做法是依賴特定的連接器而非互通總線。這樣,微服務可以使用通用語言(例如事件或內部 REST API)進行通信,而連接器則負責與遺留系統進行雙向轉換,並始終確保安全性。

除了同步通訊之外,非同步訊息傳遞也發揮關鍵作用。它用於解耦進程、應對流量高峰、在服務間傳播業務事件以及提高系統彈性。每個事件通常都有一個定義明確且版本化的方案,並配有追蹤機制,以防止生產者和消費者在演進過程中出現故障。

可觀測性、OTEL 收集器和操作

在由眾多微服務組成的系統中,如果沒有良好的可觀測性,幾乎不可能診斷出問題。因此,從設計階段就開始整合指標、集中式日誌和分散式追踪,以便了解服務層和平台層上發生的情況。

  系統分析師的職責:深入了解

此方案的核心元件是OpenTelemetry Collector(OTEL Collector),它可以部署在命名空間中或集中部署,用於收集所有元件的指標、日誌和追蹤資訊。微服務只需知道它們應該將遙測資料傳送給 Collector;Collector 隨後會將資料轉發給可觀測性系統(Prometheus、Grafana、Jaeger、Elastic 等),而服務本身無需了解具體細節。

在基礎設施層,節點級收集器和導出器用於從 Pod 收集 CPU、記憶體、磁碟、網路和日誌指標,並分別將其發送到 Prometheus 和 Elasticsearch。 Grafana 和 Kibana 等工具用於視覺化這些資訊、建立儀表板,以及定義具有智慧閾值和相關運作手冊的警告。

當一個專案需要對其指標或追蹤進行非常具體的處理時,它可以在自己的命名空間中部署自己的 OTEL Collector 實例,前提是它獲得了營運批准並且生產維護模型很明確。

測試策略、合約和本地開發經驗

測試分散式微服務架構需要比測試單體架構更複雜的測試策略。單元測試仍然至關重要,但契約測試(針對 API 和事件)、服務間的整合測試以及遍歷完整流程的端到端測試正變得越來越重要。

為了防止相容性問題,我們採用了面向消費者的契約測試等技術,其中客戶端定義 API 預期,服務提供者則負責滿足這些預期。每次契約變更都會在持續整合 (CI) 管線中進行自動化測試,從而避免部署破壞任何已知消費者的功能。

當服務數量超過一百個時,在本地複製整個系統就變得不切實際。因此,開發工作依賴對依賴服務的模擬或透過隧道連接到遠端環境。開發人員通常只啟動一部分微服務,並使用類比物件、偽造物件或模擬器來模擬其餘服務,或將某些呼叫重新導向到共享的整合環境。

端到端測試越來越依賴從功能分支創建的臨時環境或「預覽版」,這些預覽版能夠建立一個隔離的環境,其中包含與該功能相關的服務。這最大限度地減少了團隊之間的摩擦,降低了「在我機器上運行正常」的影響,並在部署到成本更高的環境(例如預生產環境)之前檢測到整合問題。

生產環境中的微服務部署模式

除了 Kubernetes 之外,生產環境中還有幾種值得了解的微服務部署模式,因為它們針對不同的隔離性、成本和成熟度情境。其中一個最古老的模式是每個主機運行多個服務實例,即單一實體或虛擬主機運行多個不同服務的實例,通常運行在共享的應用伺服器上。

基於虛擬機器的服務執行個體模式下,每個服務都被打包成一個虛擬機器鏡像(例如 EC2 AMI),並在其自身的執行個體上執行。這種模式提供了強大的隔離性,但代價是更高的資源消耗和更慢的啟動速度。 Packer 等工具或雲端供應商提供的特定解決方案可以輕鬆產生可用於生產環境的虛擬機器鏡像。

目前最普遍的模式是每個容器對應一個服務實例,其中每個微服務都建構成一個容器鏡像,並部署在編排器(Kubernetes、OpenShift 等)上。容器比虛擬機器更輕量級,啟動速度極快,並且允許您將服務所需的一切打包在一起,從而簡化部署並實現自動擴展。

最後,諸如 AWS Lambda 之類的無伺服器方案也逐漸流行起來。這些方案打包了回應 HTTP 請求或來自其他服務(例如 S3、DynamoDB、佇列等)事件的函數,使用者只需為實際使用的資源付費。這種模式尤其適用於小型微服務或生命週期短的事件驅動型任務,但也引入了關於可觀測性、冷啟動和執行限制等方面的額外考慮。

實際上,許多組織最終都會採用混合生態系統:系統的核心部分運行在容器和編排器上,而某些輔助組件則以無伺服器函數或專用虛擬機的形式實現,始終具有清晰的接口和完善的協議,以便將它們集成到整體中。

當這一切真正投入生產時,關鍵不僅在於選擇的​​技術,更在於建構一個能夠容忍故障、按需擴展、自動部署且可觀測的架構。有了產品導向的團隊、管理完善的合約、去中心化的數據以及強大的雲端平台,微服務就能從最初的願景轉變為一種高效且可持續的方式,使複雜的應用程式能夠持續演進多年。