使用.net中的API網關模式封裝微服務
- 2021 年 1 月 21 日
- 筆記
在本文中,我們將了解如何使用API網關模式來封裝微服務並抽象出底層實現細節,從而允許使用者擁有進入我們系統的一致入口點。
為了構建和測試我們的應用程式,我們需要:
1.Visual Studio 2019
2..NET Core 5 SDK
由於微服務是一個相當複雜的主題,在我們進入下一節的程式碼之前,讓我們花點時間解釋一下基礎知識。
微服務是一種架構風格,因此這種風格的實現可能會有很大的差異,並且經常是一個備受爭議的話題。然而,大多數專家認為微服務具有以下屬性:
- 鬆散耦合
- 容易維護
- 獨立部署
- 可測試
- 圍繞業務能力組織
龐然大物 vs 微服務
讓我們考慮下面的圖表來比較龐然大物和微服務架構:
我們大多數人都熟悉「龐然大物」體系結構,其中單個應用程式(通常包含多個邏輯「層」,如UI/業務/數據)作為單個流程部署到一個或多個伺服器上。
微服務體系結構試圖將應用程式分解為更小的部分,並獨立部署它們。分解應用程式的過程是一個複雜而重要的過程,超出了本文的範圍,因此在這裡推薦一些關於領域驅動設計(DDD)的研究。
描述龐然大物和微服務體系結構之間的區別本身就是一個主題,由於我們在前面已經談到了微服務的一些好處,所以這裡就不做太多的詳細討論了。就本文而言,我們想要關注的主要好處是獨立性。也就是說,我們將看到改變一個微服務是如何不會使整個應用程式崩潰的,因為其他微服務甚至不需要關心這個變化。這與龐然大物架構有很大的不同,在龐然大物架構中,任何微小的更改都需要關閉並更新整個應用程式。
分解我們的龐然大物
我們的示例龐然大物應用程式,解決方案如下:
我們可以看到它是一個簡單的ASP.NET Core API,為Authors和Books分別提供一個控制器。
讓我們按下CTRL+F5在瀏覽器中運行應用程式,它將調用” /books “:
我們可以看到它返回了一個書單。
讓我們把瀏覽器中的URL改為/authors:
創建AuthorsService
首先,讓我們通過添加一個新的ASP.NET Core API來創建AuthorsService:
現在,我們可以進行一些重構,將相關程式碼從提取到新的AuthorsService中。
讓我們複製:
1.Controllers文件夾中的AuthorsController
2.Models文件夾中的Author
3.Data文件夾中的Repository
我們應該以以下結構結束:
接下來,我們將進行一些調整以啟動並運行AuthorsService。
首先,讓我們在Startup.cs中的ConfigureServices方法中添加以下程式碼:
services.AddSingleton<Repository>();
接下來,讓我們刪除Repository中對Book的引用,最後得到:
public class Repository { private IEnumerable<Author> _authors { get; set; } public Repository() { _authors = new[] { new Author { AuthorId = 1, Name = "John Doe" }, new Author { AuthorId = 2, Name = "Jane Smith" } }; } public IEnumerable<Author> GetAuthors() => _authors; }
現在,我們可以運行新的AuthorsService,並將URL指向「/authors」路徑:
太棒了!我們已經啟動並運行了作者微服務。
創建BooksService
現在,讓我們按照上面完全相同的步驟,將相關的Books程式碼從這個龐然大物提取到一個新的BooksService API中。我們將在這裡再次重複所有的步驟,因為這應該是不言而喻的。
讓我們運行這個新服務,並將URL指向「/books」路徑:
現在,我們的Books微服務已經啟動並運行。
現在,我們可以在兩個不同的伺服器上獨立部署這兩個微服務,並公開它們使用。它們沒有以任何方式耦合在一起。
但是在下一節中,我們將討論如何使用API網關模式這種方法解決一些問題。
API網關模式
如果有人想要使用我們的龐然大物API,這非常簡單,因為只有一個主機需要處理,例如「//ourmonolithapi.ourcompany.com」
然而,現在我們已經把這個龐然大物提取成兩個獨立的微服務,這變得更加困難,因為消費者需要與多個api交互:
出現的問題包括:
1.每個服務都在哪裡?(發現)
2.這些服務使用相同的協議嗎?(複雜性)
3.我需要多少次往返才能呈現包含Books和Authors的頁面?(性能)
API網關模式有哪些幫助
這就是API網關模式的作用所在,它通過坐在微服務的「前面」,將消費者與所有這些問題隔離開來:
現在回到我們之前的問題:
每個服務都在哪裡?回答:消費者不在乎。它只處理API網關,然後API網關代表消費者與服務進行交互
這些服務使用相同的協議嗎?回答:消費者也不在乎。如果微服務使用不同的協議(例如,如果我們想將BooksService改為使用gRPC而不是HTTP), API網關就有責任在這些協議之間進行映射。
我需要多少次往返才能使這個頁面同時包含Books和Authors?答:API網關可以為消費者「聚合」這些調用。這是特別重要的,因為我們不能控制用戶的網路(他們可能在一個緩慢的連接上),但是,我們可以控制我們的內部網路。因此,通過將API網關和微服務緊密結合在一起,我們可以最大化網路效率。
還有一個類似的模式值得一提,稱為「BFF」模式。不,這並不意味著永遠是最好的朋友(best friends forever),而是「後端為前端」(Backend-for-frontend)。這個模式與API網關非常相似,但是它涉及到為每個「前端」創建一個API網關。
這張圖說明了我們如何為我們的用例實現BFF模式:
在這種情況下,每個客戶端都有自己的BFF / API網關,其功能可以為特定的客戶端量身訂製。例如,也許web應用程式需要一些搜索引擎優化功能,而移動應用程式並不關心。這允許移動和web團隊自主操作,並擁有自己的數據層。
然而,在本文中,我們只關注單個消費者的單個API網關。
我們如何實現API網關模式?
有很多方法可以實現API網關模式,包括使用現成的軟體。最終的選擇將取決於API網關所需的特性。
我們可能需要的一些常見功能包括:
1.身份驗證
2.限制速度
3.分析
4.日誌記錄
5.文檔
Traefik、Kong和Azure API Management等服務可以提供這些特性的全部或部分,因此,根據你的用例需要什麼,有必要仔細閱讀它們。
然而,出於本文的目的,我們將排除這些特性,而將重點放在最基本的功能上,即消費者和微服務之間的一個簡單的基於http的代理。為了實現這一點,我們可以很容易地自己用ASP.NET Core來實現。
添加我們的API網關
因為我們已經在我們的解決方案中有了龐然大物API,我們計劃使用ASP.NET Core作為我們的API網關,我們可以簡單地將它轉換成我們想要的。
首先,讓我們刪除「Controllers」、「Data」和「Models」文件夾,因為我們不再需要它們了。
接下來,讓我們在Startup中向ConfigureServices()添加以下一行:
services.AddHttpClient();
這樣我們就可以通過HTTP客戶端調用新的微服務。
接下來,讓我們添加一個名為ProxyController的新控制器:
[Route("[action]")] [ApiController] public class ProxyController : ControllerBase { private readonly HttpClient _httpClient; public ProxyController(IHttpClientFactory httpClientFactory) { _httpClient = httpClientFactory.CreateClient(); } [HttpGet] public async Task<IActionResult> Books() => await ProxyTo("//localhost:44388/books"); [HttpGet] public async Task<IActionResult> Authors() => await ProxyTo("//localhost:44307/authors"); private async Task<ContentResult> ProxyTo(string url) => Content(await _httpClient.GetStringAsync(url)); }
程式碼應該是相當不言自明的,但本質上我們使用HttpClient來調用我們的新微服務並直接返迴響應。
讓我們在解決方案中構建並運行我們所有的三個項目,我們應該有:
//localhost: 44307(Authors)
//localhost: 44388(Books)
//localhost: 5001 (API網關)
運行完所有程式後,讓我們打開瀏覽器//localhost:5001/books
同樣,讓我們導航到//localhost:5001/authors:
我們現在有了一個功能正常的API網關,可以將請求代理到我們的兩個微服務!
在下一節中,讓我們添加API網關的一個簡單消費者。
添加一個簡單的消費者
現在我們有了一個API網關,讓我們來看看如何添加一個簡單的web頁面,它可以使用我們的API。
在此之前,我們需要在API網關中啟用CORS,以便能夠發出跨域請求。
讓我們打開Startup.cs並修改ConfigureServices():
services.AddCors(options => { options.AddDefaultPolicy(builder => { builder.AllowAnyOrigin(); }); });
出於測試目的,我們允許任何來源的CORS。但是對於生產應用程式,我們需要更嚴格的CORS策略。
接下來,讓我們將CORS中間件添加到ASP.NET Core管道中的Configure()方法:
app.UseCors();
讓我們變異並運行我們的應用程式,以部署新的更改。
接下來,讓我們創建一個非常簡單的HTML頁面:
<html> <head> </head> <body> <button onclick="callAPI('books')">Get Books</button> <button onclick="callAPI('authors')">Get Authors</button> <script type="text/javascript"> function callAPI(path) { let request = new XMLHttpRequest(); request.open("GET", "//localhost:5001/" + path); request.send(); request.onload = () => { if (request.status === 200) { alert(request.response); } else { alert(`Error: ${request.status} ${request.statusText}`); } } } </script> </body> </html>
這裡我們有幾個按鈕,當點擊時將調用我們的API網關並通知結果。
讓我們在瀏覽器中打開HTML頁面,點擊「Get Books」按鈕,我們看到一個瀏覽器彈出:
讓我們點擊「Get Authors」按鈕:
我們看到消費者能夠調用我們的API網關,而API網關又能夠將這些請求代理到相關的微服務。
在下一節中,讓我們看看如何更改我們的一個微服務,這將突出微服務API網關模式的好處之一。
改變Microservice
我們在前面討論了微服務應該如何獨立部署,以及更改一個微服務不需要關閉整個應用程式(在本例中,「應用程式」就是API網關)。
我們可以通過改變「Authors」微服務來證明這一理論。
首先,讓我們「關閉」Authors的微服務,停止IIS Express中的站點:
如果我們再次點擊「Get Authors」按鈕,我們會看到一個錯誤:
然而,如果我們點擊「Get Books」按鈕:
正如預期的那樣,它仍然返回一個結果。
現在,我們將對Authors微服務進行一些更改。
改變Authors的微服務
首先,讓我們為Author類添加一個新屬性:
public string Country { get; set; }
接下來,讓我們更新我們的Repository,以返回我們的新欄位:
_authors = new[] { new Author { AuthorId = 1, Name = "John Doe", Country = "Australia" }, new Author { AuthorId = 2, Name = "Jane Smith", Country = "United States" } };
這是一個微不足道的更改,但關鍵是,更改可以是任何東西:來自新資料庫的新欄位、升級包,甚至用不同的程式語言重寫整個應用程式。只要遵守了微服務和API網關之間的契約(例如沒有破壞性的更改),就不需要發生任何其他事情。
讓我們再次構建並運行我們的Authors服務,然後點擊「Get Authors」按鈕:
我們看到我們的新變化正在傳遞給消費者。
值得在此駐足片刻,看看我們取得了哪些成就:
1.我們創建了一個消費者,它通過一個應用程式(API網關)與兩個微服務交互。
2.我們關閉了其中一個微服務並進行了更新
3.另一個微服務能夠繼續提供功能
考慮一下我們的用戶是否功能更豐富,例如,列出了所有的Book。如果該特性不需要任何Author功能,則可以繼續為用戶提供該特性,甚至對作者進行更新。
這是非常強大的,因為它允許「優雅」地降低某些功能,同時保留其他功能。我們甚至可以為此向API網關添加更多特性,例如,檢測下游服務的中斷並返回快取的數據,或利用備份功能。關鍵是,我們的後端消費者通過API網關與後台的任何更改隔離開來。
結論
在本文中,我們簡要介紹了微服務和API網關模式背後的理論,並創建了一個非常簡單的設置,演示了一些關鍵概念。
儘管我們的實現非常基本,但重要的是我們所設置的可能性。我們能夠繼續為我們的用戶提供應用程式的一些功能,儘管我們正在對其他功能進行一些升級。這在微服務中很常見,它們可能是不同的團隊,從事不同的功能和微服務。使用這種方法,升級功能的團隊負責更新,而不需要在其他團隊之間進行廣泛的協調。
API網關為我們的後端提供了一個很棒的「面子」,可以很容易地控制如何將我們的後端功能服務給我們的消費者,而不必將這些關注點推到下游的每個服務。這意味著實際的服務要靈活得多,只需要關心它們需要交付給API網關的內容。
下一個邏輯步驟是建立更多的微服務,提高API網關等更多的功能,比如日誌,分析和彈性,然而,每一個點本質上是一個新課題。
希望你喜歡這篇文章。編碼快樂!
歡迎關注我的公眾號,如果你有喜歡的外文技術文章,可以通過公眾號留言推薦給我。
原文鏈接://code-maze.com/api-gateway-pattern-dotnet-encapsulate-microservices/