Ocelot-基于.NET Core的开源网关实现
寫在前面
? ?API網(wǎng)關(guān)是系統(tǒng)內(nèi)部服務(wù)暴露在外部的一個訪問入口,類似于代理服務(wù)器,就像一個公司的門衛(wèi)承擔著尋址、限制進入、安全檢查、位置引導(dǎo)等工作,我們可以形象的用下圖來表示: 外部設(shè)備需要訪問內(nèi)部系統(tǒng)服務(wù)時必須要通過我們的API Gateway,目的是為了隔離內(nèi)部服務(wù)和外部訪問來做統(tǒng)一的認證授權(quán),限流熔斷,請求聚合,負載均衡,日志記錄,監(jiān)控預(yù)警等 通用功能,就像是我們系統(tǒng)的防火墻一樣,在任何外部請求訪問系統(tǒng)時都必須經(jīng)過防火墻的驗證。
更多關(guān)于網(wǎng)關(guān)的信息請參考前面的一篇文章《API網(wǎng)關(guān)模式》
Ocelot是什么?
? ? ?Ocelot是基于.NET Core實現(xiàn)的輕量級API網(wǎng)關(guān),它包括的主要功能有:路由、請求聚合、服務(wù)發(fā)現(xiàn)、認證、授權(quán)、限流熔斷、并內(nèi)置了LoadBanalce以及集成了Service Fabric、 Consul、Eureka等功能,這些功能只都只需要簡單的配置即可使用。目前騰訊財付通的API Gateway就是基于此做的實現(xiàn)(參考善友兄的這篇文章),下面是詳細信息以及Ocelot如何在微軟官方示例代碼庫 eShopContainers中的使用。
Ocelot在騰訊的使用:https://customers.microsoft.com/en-us/story/tencent-telecommunications-dotnetcore
微軟官方示例:https://github.com/dotnet-architecture/eShopOnContainers
Ocelot的實現(xiàn)機制
? ??簡單的來說它是一堆的asp.net core middleware組成的pipeline,當它拿到請求之后會用一個request builder來構(gòu)造一個HttpRequestMessage發(fā)到下游的真實服務(wù)器,等下游的服務(wù) 返回response之后再由一個middleware將它返回的HttpResponseMessage映射到HttpResponse上。
代碼示例
我在Github上創(chuàng)建了示例代碼庫僅供參考,我們可以使用下面的步驟來創(chuàng)建示例代碼:(示例代碼)
1.創(chuàng)建BookingApi: dotnet new -n BookingApi
2.創(chuàng)建PassengerApi: dotnet new -n PassengerApi
3.創(chuàng)建ApiGateway: dotnet new -n ApiGateway
4.添加BookingApi和PassengerApi的實現(xiàn)代碼
5.在ApiGateway項目中用Nuget安裝Ocelot依賴包
6.添加configuration.json的配置文件
7.配置路由響應(yīng)規(guī)則
8.啟動服務(wù)并通過Api網(wǎng)關(guān)訪問服務(wù)
啟動BookingApi PassengerApi這兩個服務(wù),我們可以看到他們分別提供了兩個接口
此時再啟動我們的Api Gateway項目,通過Gateway來訪問我們這兩個API
我們可以看到原本我們可以直接訪問的兩個API現(xiàn)在都可以通過Gateway來訪問了,那這一切是怎么做到的呢?
當我們通過Nuget安裝Ocelot的依賴之后,我們需要在項目中添加.json的配置文件,在此項目中我們配置文件命名為configuration.json,內(nèi)容如下:
| {??"ReRoutes": [????{??????"DownstreamPathTemplate": "/api/booking",??????"UpstreamPathTemplate": "/api/getbooking",??????"UpstreamHttpMethod": [ "Get"?],??????"ReRouteIsCaseSensitive": false,??????"DownstreamScheme": "http",??????"DownstreamHostAndPorts": [????????{??????????"Host": "localhost",??????????"Port": 8001????????}??????],??????"Key": "booking",??????"RateLimitOptions": {????????"ClientWhitelist": [],????????"EnableRateLimiting": true,????????"Period": "1s",????????"PeriodTimespan": 15,????????"Limit": 1??????}????},????{??????"DownstreamPathTemplate": "/api/booking/{pnr}",??????"UpstreamPathTemplate": "/api/getbooking/{pnr}",??????"UpstreamHttpMethod": [ "Get"?],??????"ReRouteIsCaseSensitive": false,??????"DownstreamScheme": "http",??????"DownstreamHostAndPorts": [????????{??????????"Host": "localhost",??????????"Port": 8001????????}??????]????},????{??????"DownstreamPathTemplate": "/api/passenger",??????"UpstreamPathTemplate": "/api/getpassenger",??????"UpstreamHttpMethod": [ "Get"?],??????"ReRouteIsCaseSensitive": false,??????"DownstreamScheme": "http",??????"DownstreamHostAndPorts": [????????{??????????"Host": "localhost",??????????"Port": 8002????????}??????],??????"Key": "passenger"????},????{??????"DownstreamPathTemplate": "/api/passenger/{id}",??????"UpstreamPathTemplate": "/api/getpassenger/{id}",??????"UpstreamHttpMethod": [ "Get"?],??????"ReRouteIsCaseSensitive": false,??????"DownstreamScheme": "http",??????"DownstreamHostAndPorts": [????????{??????????"Host": "localhost",??????????"Port": 8002????????}??????]????}??],??"GlobalConfiguration": {????"BaseUrl": "https://localhost:5000"??},??"Aggregates": [????{??????"ReRouteKeys": [????????"booking",????????"passenger"??????],??????"UpstreamPathTemplate": "/api/getbookingpassengerinfo"????}??]} |
? ?API Gateway幫助我們做的事情是當有請求訪問網(wǎng)關(guān)的時候,我們經(jīng)過認證授權(quán)等一系列操作確保此次訪問是被允許的之后便會轉(zhuǎn)發(fā)到它實際需要請求服務(wù)上去,請求結(jié)束之后再由Gateway統(tǒng)一將結(jié)果返回給客戶端,從模板中我們可以看到UpStreamPathTemplate實際上就是我們上游請求的地址,即網(wǎng)關(guān)公開給外部調(diào)用的地址(此服務(wù)名稱和地址我們可以根據(jù)需要隨便設(shè)置更多的是為了對外界隱藏我們真實的服務(wù)地址),而實際的調(diào)用地址便是DownStreamPathTemplate中給定的實際地址。為了方便大家理解此配置的含義,我查閱了官方資料,將我們上面用到的配置文件做了注解:(更齊全的參數(shù)請參考官方文檔)
| {??"ReRoutes": [ //路由是API網(wǎng)關(guān)最基本也是最核心的功能、ReRoutes下就是由多個路由節(jié)點組成。????{??????"DownstreamPathTemplate": "", //下游服務(wù)模板??????"UpstreamPathTemplate": "", //上游服務(wù)模板??????"UpstreamHttpMethod": [ "Get"?],//上游方法類型Get,Post,Put??????"AddHeadersToRequest": {},//需要在轉(zhuǎn)發(fā)過程中添加到Header的內(nèi)容??????"FileCacheOptions": { //可以對下游請求結(jié)果進行緩存,主要依賴于CacheManager實現(xiàn)????????"TtlSeconds": 10,????????"Region": ""??????},??????"ReRouteIsCaseSensitive": false,//重寫路由是否區(qū)分大小寫??????"ServiceName": "",//服務(wù)名稱??????"DownstreamScheme": "http",//下游服務(wù)schema:http, https??????"DownstreamHostAndPorts": [ //下游服務(wù)端口號和地址????????{??????????"Host": "localhost",??????????"Port": 8001????????}??????],??????"RateLimitOptions": { //限流設(shè)置????????"ClientWhitelist": [], //客戶端白名單????????"EnableRateLimiting": true,//是否啟用限流設(shè)置????????"Period": "1s", //每次請求時間間隔????????"PeriodTimespan": 15,//恢復(fù)的時間間隔????????"Limit": 1 //請求數(shù)量??????},??????"QoSOptions": { //服務(wù)質(zhì)量與熔斷,熔斷的意思是停止將請求轉(zhuǎn)發(fā)到下游服務(wù)。當下游服務(wù)已經(jīng)出現(xiàn)故障的時候再請求也是無功而返,??????并且增加下游服務(wù)器和API網(wǎng)關(guān)的負擔,這個功能是用的Polly來實現(xiàn)的,我們只需要為路由做一些簡單配置即可????????"ExceptionsAllowedBeforeBreaking": 0, //允許多少個異常請求????????"DurationOfBreak": 0, //熔斷的時間,單位為秒????????"TimeoutValue": 0 //如果下游請求的處理時間超過多少則自如將請求設(shè)置為超時??????}????}??],??"UseServiceDiscovery": false,//是否啟用服務(wù)發(fā)現(xiàn)??"Aggregates": [ //請求聚合????{??????"ReRouteKeys": [ //設(shè)置需要聚合的路由key????????"booking",????????"passenger"??????],??????"UpstreamPathTemplate": "/api/getbookingpassengerinfo"?//暴露給外部的聚合請求路徑????},??"GlobalConfiguration": { //全局配置節(jié)點????"BaseUrl": "https://localhost:5000"?//網(wǎng)關(guān)基地址??}} |
? 示例代碼中我們在Aggregates節(jié)點下配置了路由聚合,它將兩個請求的結(jié)果combine到一起再返回給客戶端,當我們請求/api/getbookingpassengerinfo 時就會返回下面結(jié)果:
需要注意的是:
聚合服務(wù)目前只支持返回json
目前只支持Get方式請求下游服務(wù)
任何下游的response header并會被丟棄
如果下游服務(wù)返回404,聚合服務(wù)只是這個key的value為空,它不會返回404
有木有覺得這里的聚合很類似于GraphQL的功能,但實際上在Ocelot中并不打算實現(xiàn)GraphQL的功能,因為畢竟Ocelot的主要職責(zé)是實現(xiàn)網(wǎng)關(guān)的功能,聚合只是其中的一個feature,GraphQL提供了一個庫 graphql-dotnet ,我們可以用它來完成需要的功能,而在Ocelot中實現(xiàn)類似認證,授權(quán)等這樣它擅長的事情:?
| {????"ReRoutes": [????????{????????????"DownstreamPathTemplate": "/graphql",????????????"DownstreamScheme": "http",????????????"DownstreamHostAndPorts": [??????????????{????????????????"Host": "yourgraphqlhost.com",????????????????"Port": 80??????????????}????????????],????????????"UpstreamPathTemplate": "/graphql",????????????"DelegatingHandlers": [????????????????"GraphQlDelegatingHandler"????????????]????????}????]??} |
官方也給出了示例:https://github.com/ThreeMammals/Ocelot/tree/develop/samples/OcelotGraphQL
此框架包含的內(nèi)容比較多,在此并不一一解釋,下面將談?wù)勂渌膸讉€功能:
請求限流
大家注意到我們在上面例子中通過RateLimitOptions節(jié)點配置了限流的相關(guān)設(shè)置,目前我們配置的是1s鐘之內(nèi)只允許對booking api訪問一次,否則的話便停止繼續(xù)轉(zhuǎn)發(fā)至下游服務(wù),我們通過測試就會發(fā)現(xiàn)當在1s內(nèi)多次訪問的時候,網(wǎng)關(guān)便會返回下面的信息:
負載均衡
當我們路由到的下游服務(wù)有多個結(jié)點的時候,我們可以在DownstreamHostAndPorts中進行配置負載
| {????"DownstreamPathTemplate": "/api/posts/{postId}",????"DownstreamScheme": "https",????"DownstreamHostAndPorts": [????????????{????????????????"Host": "10.127.1.10",????????????????"Port": 5001,????????????},????????????{????????????????"Host": "10.127.1.11",????????????????"Port": 5002,????????????}????????],????"UpstreamPathTemplate": "/posts/{postId}",????"LoadBalancer": "LeastConnection",????"UpstreamHttpMethod": [ "Put", "Delete"?]} |
LoadBalancer將決定負載均衡的算法,目前支持下面三種方式
LeastConnection – 將請求發(fā)往最空閑的那個服務(wù)器
RoundRobin – 輪流發(fā)送
NoLoadBalance – 總是發(fā)往第一個請求或者是服務(wù)發(fā)現(xiàn)
Prioirty優(yōu)先級
當我們配置多個請求產(chǎn)生沖突的時候,通過路由設(shè)置訪問優(yōu)化級??
| {????"UpstreamPathTemplate": "/goods/{catchAll}"????"Priority": 0}{????"UpstreamPathTemplate": "/goods/delete"????"Priority": 1} |
?萬能模板
如果不希望對請求做任何的處理,則可以使用下面的萬能模板:(萬能模板的優(yōu)先級最低,只要有其它的路由模板,其它的路由模板則會優(yōu)先生效)
| {????"DownstreamPathTemplate": "/{url}",????"DownstreamScheme": "https",????"DownstreamHostAndPorts": [????????????{????????????????"Host": "localhost",????????????????"Port": 80,????????????}????????],????"UpstreamPathTemplate": "/{url}",????"UpstreamHttpMethod": [ "Get"?]} |
? 本篇內(nèi)容就先介紹到這里,后面將會繼續(xù)探究Ocelot的內(nèi)部實現(xiàn)。個人感覺現(xiàn)在.NET Core的生態(tài)越來越好,越來越多的開發(fā)人員開始嘗試.NET Core并創(chuàng)建了很多優(yōu)秀的開源項目,從微軟這幾年的開源策略我們更多的感受到了微軟對于擁抱開源的決心,這也更加的讓我們有信心在Core平臺上去構(gòu)建越來越多的優(yōu)秀項目。如果你對技術(shù)有熱情可以掃碼加入我們的微信群一起探討。
參考資料:
http://ocelot.readthedocs.io/en/latest/index.html
https://www.cnblogs.com/shanyou/p/7787183.html
Polly:
https://github.com/App-vNext/Polly
Consul:
https://github.com/hashicorp/consul
https://github.com/dotnet/home
Microsoft Blog:
https://blogs.msdn.microsoft.com/cesardelatorre/2018/05/15/designing-and-implementing-api-gateways-with-ocelot-in-a-microservices-and-container-based-architecture/
原文地址:https://www.cnblogs.com/xiandnc/p/9374533.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的Ocelot-基于.NET Core的开源网关实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【招聘(北京)】东方国信 工业互联网
- 下一篇: Blazor 0.5.0 升级及新特性介