

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Strangler 無花果模式
<a name="strangler-fig"></a>

## 意圖
<a name="strangler-fig-intent"></a>

Strangler fig 模式有助於逐步將單體應用程式遷移至微服務架構，並降低轉型風險和業務中斷。

## 動機
<a name="strangler-fig-motivation"></a>

開發單體應用程式是為了在單一程序或容器中提供其大部分功能。程式碼會緊密耦合。因此，應用程式變更需要徹底重新測試，以避免迴歸問題。變更無法單獨測試，這會影響週期時間。隨著應用程式擁有更多功能，高複雜性可能會導致在維護上花費更多時間、增加上市時間，因此導致產品創新速度變慢。

當應用程式擴展大小時，會增加團隊的認知負載，並可能導致團隊擁有權界限不明。無法根據負載擴展個別功能 - 必須擴展整個應用程式以支援尖峰負載。隨著系統老化，技術可能會變得過時，進而增加支援成本。單體舊版應用程式遵循開發時可用的最佳實務，並非設計為可分發。

當單一應用程式遷移到微服務架構時，它可以分割成較小的元件。這些元件可以獨立擴展，可以獨立發行，並且可以由個別團隊擁有。這會導致更高的變更速度，因為變更是本地化的，並且可以快速測試和發佈。變更的影響範圍較小，因為元件鬆散耦合且可個別部署。

透過重寫或重構程式碼，將整體完全取代為微服務應用程式，是一項巨大的任務，也是很大的風險。在單一操作中遷移整體的大型巨型遷移，會帶來轉型風險和業務中斷。當應用程式正在重構時，新增新功能非常困難，甚至不可能。

解決此問題的一種方法是使用由 Martin Fowler 引進的 strangler fig 模式。此模式涉及逐步擷取功能，並在現有系統周圍建立新的應用程式，以移至微服務。整體中的功能會逐漸被微服務取代，應用程式使用者能夠逐步使用新遷移的功能。當所有功能移至新系統時，單體應用程式可以安全地停用。

## 適用性
<a name="strangler-fig-applicability"></a>

在下列情況下使用 strangler fig 模式：
+ 您想要將整體應用程式逐步遷移至微服務架構。
+ 由於整體的大小和複雜性，大型巨型遷移方法具有風險。
+ 企業想要新增新功能，而且無法等待轉換完成。
+ 在轉換期間，最終使用者必須受到最小的影響。

## 問題和考量
<a name="strangler-fig-issues"></a>
+ **程式碼基礎存取：**若要實作 strangler fig 模式，您必須能夠存取整體應用程式的程式碼基礎。隨著功能從整體遷移，您需要進行次要程式碼變更，並在整體中實作反貪汙層，以將呼叫路由到新的微服務。在沒有程式碼基礎存取的情況下，您無法攔截呼叫。程式碼基礎存取對於重新導向傳入請求也很重要，因為可能需要一些程式碼重構，以便代理層可以攔截遷移功能的呼叫，並將其路由到微服務。
+ **不清楚的網域：**系統過早分解可能成本高昂，特別是當網域不清楚時，而且可能使服務界限出錯時。網域驅動設計 (DDD) 是了解網域的機制，而事件風暴是判斷網域界限的技術。
+ **識別微服務：**您可以使用 DDD 作為識別微服務的關鍵工具。若要識別微服務，請尋找服務類別之間的自然分割。許多 服務將擁有自己的資料存取物件，並可輕鬆解耦。具有相關商業邏輯的服務和沒有或很少相依性的類別，是微型服務的理想候選者。您可以在分解整體之前重構程式碼，以防止緊密耦合。您也應該考慮合規要求、發行節奏、團隊的地理位置、擴展需求、使用案例驅動的技術需求，以及團隊的認知負載。
+ **反損毀層：**在遷移過程中，當整體中的功能必須呼叫遷移為微服務的功能時，您應該實作反損毀層 (ACL)，將每個呼叫路由至適當的微服務。為了分離和防止對整體中現有發起人進行變更，ACL 可作為轉接器或外觀，將呼叫轉換為較新的界面。本指南稍早的 ACL 模式[實作一節](acl.md#acl-implementation)會詳細說明。
+ **代理層失敗：**在遷移期間，代理層會攔截送至單體應用程式的請求，並將其路由至舊版系統或新系統。不過，此代理層可能會成為單一故障點或效能瓶頸。
+ **應用程式複雜性：**大型整體受益於 strangler fig 模式。對於完全重構的複雜性很低的小型應用程式，在微服務架構中重寫應用程式可能更有效率，而不是遷移應用程式。
+ **服務互動：**微服務可以同步或非同步通訊。需要同步通訊時，請考慮逾時是否會導致連線或執行緒集區耗用，進而導致應用程式效能問題。在這種情況下，請使用[斷路器模式](circuit-breaker.md)，針對可能會長時間失敗的操作傳回立即故障。您可以使用事件和訊息佇列來達成非同步通訊。
+ **資料彙總：**在微服務架構中，資料會分散到資料庫。需要資料彙總時，您可以在[AWS AppSync](https://aws.amazon.com/appsync/)前端使用 ，或在後端使用命令查詢責任隔離 (CQRS) 模式。
+ **資料一致性：**微型服務擁有其資料存放區，而單體應用程式也可能使用此資料。若要啟用共用，您可以使用佇列和代理程式，將新的微服務的資料存放區與單體應用程式的資料庫同步。不過，這可能會導致兩個資料存放區之間的資料備援和最終一致性，因此建議您將其視為策略解決方案，直到您可以建立資料湖等長期解決方案為止。

## 實作
<a name="strangler-fig-implementation"></a>

在 strangler fig 模式中，您可以將特定功能取代為新的服務或應用程式，一次一個元件。代理層會攔截送至單體應用程式的請求，並將其路由至舊版系統或新系統。由於代理層會將使用者路由至正確的應用程式，因此您可以將功能新增至新系統，同時確保整體繼續運作。新系統最終會取代舊系統的所有功能，而且您可以將其停用。

### 高層級架構
<a name="fig-high-level-arch"></a>

在下圖中，單一應用程式有三種服務：使用者服務、購物車服務和帳戶服務。購物車服務取決於使用者服務，而應用程式會使用單體關聯式資料庫。

![具有三個服務的單體應用程式。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-1.png)


第一步是在存放區 UI 和單體應用程式之間新增代理層。一開始，代理會將所有流量路由到整體應用程式。

![將代理新增至單體應用程式。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-2.png)


當您想要將新功能新增至應用程式時，您可以將它們實作為新的微服務，而不是將功能新增至現有的整體。不過，您可以繼續修正整體中的錯誤，以確保應用程式的穩定性。在下圖中，代理層會根據 API URL 將呼叫路由到整體或新的微服務。

![Proxy 將呼叫路由到整體或新的微服務。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-3.png)


#### 新增反貪汙層
<a name="strangler-fig-implementation-acl"></a>

在下列架構中，使用者服務已遷移至微服務。購物車服務會呼叫使用者服務，但整體內不再提供實作。此外，新遷移服務的界面可能不符合其在整體應用程式內的先前界面。若要解決這些變更，請實作 ACL。在遷移過程中，當整體中的功能需要呼叫遷移為微服務的功能時，ACL 會將呼叫轉換為新界面，並將其路由至適當的微服務。

![新增 ACL 將呼叫轉換為新界面。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-4.png)


您可以在單體應用程式內實作 ACL，做為已遷移服務特有的類別；例如 `UserServiceFacade`或 `UserServiceAdapter`。在將所有相依服務遷移至微服務架構之後，必須停用 ACL。

當您使用 ACL 時，購物車服務仍會呼叫整體中的使用者服務，而使用者服務會透過 ACL 重新導向對微服務的呼叫。在不知道微服務遷移的情況下，購物車服務仍應呼叫使用者服務。需要這種鬆散耦合來減少迴歸和業務中斷。

#### 處理資料同步
<a name="strangler-fig-implementation-sync"></a>

最佳實務是，微型服務應該擁有其資料。使用者服務將其資料存放在自己的資料存放區中。它可能需要將資料與單體資料庫同步，以處理報告等相依性，並支援尚未準備好直接存取微服務的下游應用程式。單體應用程式也可能需要其他尚未遷移至微服務之函數和元件的資料。因此，新微服務與整體之間需要資料同步。若要同步資料，您可以在使用者微服務和單體資料庫之間引入同步代理程式，如下圖所示。使用者微服務會在資料庫更新時，將事件傳送至佇列。同步代理程式會接聽佇列，並持續更新整體資料庫。單體資料庫中的資料最終與正在同步的資料一致。

![新增同步代理程式。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-5.png)


#### 遷移其他服務
<a name="strangler-fig-implementation-more"></a>

當購物車服務遷移出單體應用程式時，其程式碼會修改為直接呼叫新服務，因此 ACL 不會再路由這些呼叫。下圖說明此架構。

![遷移其他服務。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-6.png)


下圖顯示最終的絞結狀態，其中所有 服務都已從整體遷移，且僅保留整體骨架。歷史資料可以遷移到個別 服務擁有的資料存放區。可以移除 ACL，而且單體已準備好在此階段停用。

![遷移所有 服務後的最終扭曲狀態。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-7.png)


下圖顯示停用單體應用程式之後的最終架構。您可以根據您的應用程式需求，透過以資源為基礎的 URL （例如 `http://www.storefront.com/user`) 或透過自己的網域 （例如 `http://user.storefront.com`) 託管個別微服務。如需使用主機名稱和路徑向上游消費者公開 HTTP APIs 的主要方法的詳細資訊，請參閱 [API 路由模式](api-routing.md)一節。

![停用整體之後的最終架構。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-8.png)


### 使用 AWS 服務實作
<a name="strangler-fig-implementation-aws-services"></a>

#### 使用 API Gateway 做為應用程式代理
<a name="strangler-fig-implementation-api-gateway"></a>

下圖顯示單體應用程式的初始狀態。假設它透過 AWS 使用lift-and-shift策略遷移到 ，因此它在 [Amazon Elastic Compute Cloud (Amazon EC2)](https://aws.amazon.com/ec2/) 執行個體上執行，並使用 [Amazon Relational Database Service (Amazon RDS)](https://aws.amazon.com/rds/) 資料庫。為了簡化，架構使用單一虛擬私有雲端 (VPC) 搭配一個私有和一個公有子網路，讓我們假設微服務一開始會部署在相同的 中 AWS 帳戶。（生產環境中的最佳實務是使用多帳戶架構來確保部署獨立性。) EC2 執行個體位於公有子網路中的單一可用區域，RDS 執行個體則位於私有子網路中的單一可用區域。[Amazon Simple Storage Service (Amazon S3)](https://aws.amazon.com/s3/) 存放靜態資產，例如網站的 JavaScript、CSS 和 React 檔案。

![使用 strangler fig 模式時，整體應用程式的初始狀態。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-9.png)


在下列架構中， [AWS Migration Hub Refactor Spaces](https://docs.aws.amazon.com/migrationhub-refactor-spaces/latest/userguide/what-is-mhub-refactor-spaces.html) 會在單體應用程式前面部署 [Amazon API Gateway](https://aws.amazon.com/api-gateway/)。Refactor Spaces 會在您的帳戶內建立重構基礎設施，而 API Gateway 會做為將呼叫路由到整體的代理層。一開始，所有呼叫都會透過代理層路由到單體應用程式。如前所述，代理層可能會成為單一故障點。不過，使用 API Gateway 做為代理可降低風險，因為它是無伺服器、多可用區域服務。

**注意**  
AWS Migration Hub Refactor Spaces 自 2025 年 11 月 7 日起不再向新客戶開放。對於類似 的功能 AWS Migration Hub Refactor Spaces，請探索 [AWS Transform](https://aws.amazon.com/transform)。

![使用 API Gateway 實作 strangler fig 模式。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-10.png)


使用者服務會遷移至 Lambda 函數，Amazon [ DynamoDB](https://aws.amazon.com/dynamodb/) 資料庫會存放其資料。Lambda 服務端點和預設路由會新增至 Refactor Spaces，而 API Gateway 會自動設定為將呼叫路由到 Lambda 函數。

![使用 API Gateway 實作 strangler fig 模式：設定路由。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-11.png)


在下圖中，購物車服務也已從整體遷移到 Lambda 函數。額外的路由和服務端點會新增至重構空間，而流量會自動切換到 `Cart` Lambda 函數。Lambda 函數的資料存放區由 [Amazon ElastiCache](https://aws.amazon.com/elasticache/) 管理。單體應用程式仍會與 Amazon RDS 資料庫一起保留在 EC2 執行個體中。

![使用 strangler fig 模式將服務移出整體。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-12.png)


在下圖中，最後一個服務 （帳戶） 會從整體遷移到 Lambda 函數。它會繼續使用原始 Amazon RDS 資料庫。新的架構現在有三個具有不同資料庫的微服務。每個服務使用不同類型的資料庫。這種使用專用資料庫以滿足微服務特定需求的概念稱為*多槽持久性*。Lambda 函數也可以以不同的程式設計語言實作，具體取決於使用案例。在重構期間，重構空間會將流量的切換和路由自動化到 Lambda。這可為您的建置器節省建構、部署和設定路由基礎設施所需的時間。

![使用 strangler fig 模式將所有服務移出整體。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-13.png)


#### 使用多個帳戶
<a name="strangler-fig-implementation-migration-hub"></a>

在先前的實作中，我們為單體應用程式使用具有私有和公有子網路的單一 VPC，為了簡化 AWS 帳戶 起見，我們在相同的 中部署微服務。不過，在實際案例中很少發生這種情況，其中微服務通常部署在多個 中 AWS 帳戶 ，以實現部署獨立性。在多帳戶結構中，您需要設定將流量從整體路由到不同帳戶中的新服務。

[Refactor Spaces](https://docs.aws.amazon.com/migrationhub-refactor-spaces/latest/userguide/what-is-mhub-refactor-spaces.html) 可協助您建立和設定 AWS 基礎設施，以從單體應用程式路由 API 呼叫。Refactor Spaces 會在您的帳戶 AWS 內協調 [API Gateway](https://aws.amazon.com/api-gateway/)、[Network Load Balancer](https://aws.amazon.com/elasticloadbalancing/) 和資源型 [AWS Identity and Access Management (IAM)](https://aws.amazon.com/iam/) 政策，做為其應用程式資源的一部分。您可以透明地將單一帳戶 AWS 帳戶 或跨多個帳戶的新服務新增至外部 HTTP 端點。所有這些資源都會在您的 中協調 AWS 帳戶 ，並在部署後進行自訂和設定。

假設使用者和購物車服務部署到兩個不同的帳戶，如下圖所示。當您使用 Refactor Spaces 時，只需要設定服務端點和路由。Refactor Spaces 會將 [API Gateway–Lambda](https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-with-lambda-integration.html) 整合和 Lambda 資源政策的建立自動化，因此您可以專注於安全地重構整體的服務。

![使用 實作 strangler fig 模式 AWS Migration Hub Refactor Spaces。](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/fig-14.png)


如需使用重構空間的影片教學課程，請參閱[使用 遞增重構應用程式 AWS Migration Hub Refactor Spaces](https://www.youtube.com/watch?v=2KAyPNEi9aw)。

## 研討會
<a name="strangler-fig-workshop"></a>
+ [迭代應用程式現代化研討會](https://catalog.us-east-1.prod.workshops.aws/workshops/f2c0706c-7192-495f-853c-fd3341db265a/en-US)

## 部落格參考
<a name="strangler-fig-blog"></a>
+ [AWS Migration Hub Refactor Spaces](https://aws.amazon.com/blogs/aws/new-aws-migration-hub-refactor-spaces-helps-to-incrementally-refactor-your-applications/)
+ [在 上深入探索 AWS Migration Hub Refactor Spaces](https://aws.amazon.com/blogs/mt/deep-dive-on-an-aws-migration-hub-refactor-spaces-environment/)
+ [部署管道參考架構和參考實作](https://aws.amazon.com/blogs/aws/new_deployment_pipelines_reference_architecture_and_-reference_implementations/)

## 相關內容
<a name="strangler-fig-resources"></a>
+ [API 路由模式](api-routing.md)
+ [重構空間文件](https://docs.aws.amazon.com/migrationhub-refactor-spaces/latest/userguide/what-is-mhub-refactor-spaces.html)