Ocelot(三)- 服務發現

来源:https://www.cnblogs.com/markjiang7m2/archive/2019/05/22/10907856.html
-Advertisement-
Play Games

Ocelot(三) 服務發現 作者:markjiang7m2 原文地址: 源碼地址:https://gitee.com/Sevenm2/OcelotDemo 本文是我關於Ocelot系列文章的第三篇,主要是給大家介紹Ocelot的另一功能。與其說是給大家介紹,不如說是我們一起來共同探討,因為我也是在 ...


Ocelot(三)- 服務發現

作者:markjiang7m2
原文地址:https://www.cnblogs.com/markjiang7m2/p/10907856.html
源碼地址:https://gitee.com/Sevenm2/OcelotDemo

本文是我關於Ocelot系列文章的第三篇,主要是給大家介紹Ocelot的另一功能。與其說是給大家介紹,不如說是我們一起來共同探討,因為我也是在一邊學習實踐的過程中,順便把學習的過程記錄下來罷了。
正如本文要介紹的服務發現,在Ocelot中本該是一個較小的功能,但也許大家也註意到,這篇文章距離我的上一篇文章也有一個星期了。主要是因為Ocelot的服務發現支持提供程式Consul,而我對Consul並不怎麼瞭解,因此花了比較長的時間去倒弄Consul。因為這個是關於Ocelot的系列文章,所以我暫時也不打算在本文中詳細介紹Consul的功能以及搭建過程了,可能會在完成Ocelot系列文章後,再整理一篇關於Consul的文章。

關於更多的Ocelot功能介紹,可以查看我的系列文章

本文中涉及案例的完整代碼都可以從我的代碼倉庫進行下載。

Ocelot介面更新:進階請求聚合

好了,也許大家有疑問,為什麼在這裡又會重提請求聚合的內容?
在上一篇文章Ocelot(二)- 請求聚合與負載均衡中,我曾說到進階請求聚合中,由於Aggregate方法中提供的參數類型只有List<DownstreamResponse>,但DownstreamResponse中並沒有關於ReRouteKeys的信息,所以處理返回結果時,並沒有像Ocelot內部返回結果一樣使用路由的Key作為屬性。
然後,今天我註意到了Ocelot有新版本發佈,於是我做了更新,從13.5.0更新到了13.5.1,然後居然是有意外驚喜。
介面方法Aggregate更新如下:
13.5.0

public interface IDefinedAggregator
{
    Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses);
}

13.5.1

public interface IDefinedAggregator
{
    Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses);
}

參數類型從List<DownstreamResponse>更改為List<DownstreamContext>。我們再來看看DownstreamContext

public class DownstreamContext
{
    public DownstreamContext(HttpContext httpContext);

    public List<PlaceholderNameAndValue> TemplatePlaceholderNameAndValues { get; set; }
    public HttpContext HttpContext { get; }
    public DownstreamReRoute DownstreamReRoute { get; set; }
    public DownstreamRequest DownstreamRequest { get; set; }
    public DownstreamResponse DownstreamResponse { get; set; }
    public List<Error> Errors { get; }
    public IInternalConfiguration Configuration { get; set; }
    public bool IsError { get; }
}

事實上,如果你有看過Ocelot內部處理請求聚合部分的代碼,就會發現它使用的就是DownstreamContext,而如今Ocelot已經將這些路由,配置,請求,響應,錯誤等信息都開放出來了。哈哈,當然,GitHub上面的realease note,人家主要是為了讓開發者能夠捕獲處理下游服務發生的錯誤,更多信息可以查看issue#892issue#890

既然如此,那我就按照它內部的輸出結果來一遍,當然我這裡沒有嚴格按照官方處理過程,只是簡單的輸出。

public async Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses)
{
    List<string> results = new List<string>();
    var contentBuilder = new StringBuilder();

    contentBuilder.Append("{");

    foreach (var down in responses)
    {
        string content = await down.DownstreamResponse.Content.ReadAsStringAsync();
        results.Add($"\"{down.DownstreamReRoute.Key}\":{content}");
    }
    //來自leader的聲音
    results.Add($"\"leader\":{{comment:\"我是leader,我組織了他們兩個進行調查\"}}");

    contentBuilder.Append(string.Join(",", results));
    contentBuilder.Append("}");

    var stringContent = new StringContent(contentBuilder.ToString())
    {
        Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
    };

    var headers = responses.SelectMany(x => x.DownstreamResponse.Headers).ToList();
    return new DownstreamResponse(stringContent, HttpStatusCode.OK, headers, "some reason");
}

輸出結果:

Ocelot_012_aggrleaderadvance_new

官方開放了這麼多信息,相信開發者還可以使用進階請求聚合做更多的東西,歡迎大家繼續研究探討,我這裡就暫時介紹到這裡了。

案例四 服務發現

終於到我們今天的正題——服務發現。關於服務發現,我的個人理解是在這個微服務時代,當下游服務太多的時候,我們就需要找一個專門的工具記錄這些服務的地址和埠等信息,這樣會更加便於對服務的管理,而當上游服務向這個專門記錄的工具查詢某個服務信息的過程,就是服務發現。

舉個例子,以前我要找的人也就只有Willing和Jack,所以我只要自己用本子(資料庫)記住他們兩個的位置就可以了,那隨著公司發展,部門的人越來越多,他們經常會調換位置,還有入職離職的人員,這就導致我本子記錄的信息沒有更新,所以我找來了HR部門(Consul)幫忙統一管理,所有人有信息更新都要到HR部門那裡進行登記(服務註冊),然後當我(上游服務)想找人做某件事情(發出請求)的時候,我先到HR那裡查詢可以幫我完成這個任務的人員在哪裡(服務發現),得到這些人員的位置信息,我也就可以選中某一個人幫我完成任務了。

這裡會涉及到的記錄工具,就是Consul。流程圖如下:

Ocelot_013_consul

當然了,在上面這個例子中好像沒有Ocelot什麼事,但是這樣就需要我每次要找人的時候,都必須先跑到Consul那裡查詢一次位置信息,然後再根據位置信息去找對應的人。而其實這個過程我們是可以交給Ocelot來完成的。這樣,每個下游服務都不需要單獨跑一趟了,只專註於完成自己的任務就可以了。流程圖如下:

Ocelot_014_consulocelot

通常當服務在10個以上的時候可以考慮使用服務發現。

關於Consul的介紹跟使用說明,網上已經有很多相關資料,所以我這裡是基於大家都瞭解Consul的情況下的介紹。
官方建議每個Consul Cluster至少有3個或以上的運行在Server Mode的Agent,Client節點不限。由於我就這麼一臺機子,又不想搞虛擬機,所以我就直接用了Docker來部署使用Consul。
(可能這裡又涉及到了一個Docker的知識點,我這裡暫時也不展開細說了。)

因為我電腦的系統是Windows的,所以安裝的Docker for Windows。

拉取鏡像
Docker安裝好之後,就用Windows自帶的PowerShell運行下麵的命令,拉取官方的Consul鏡像。

docker pull consul

啟動Consul
節點1

docker run -d -p 8500:8500 --name markserver1 consul agent -server -node marknode1 -bootstrap-expect 3 -data-dir=/tmp/consul -client="0.0.0.0" -ui

-ui 啟用 WEB UI,因為Consul節點啟動預設占用8500埠,因此8500:8500將節點容器內部的8500埠映射到外部8500,可以方便通過Web的方式查看Consul集群的狀態。預設數據中心為dc1。

查看markserver1的IP

docker inspect -f '{{.NetworkSettings.IPAddress}}' markserver1

假設你們跟我一樣,獲取到的IP地址也是172.17.0.2

節點2

docker run -d --name markserver2 consul agent -server -node marknode2 -join 172.17.0.2

啟動節點markserver2,並且將該節點加入到markserver1中(-join 172.17.0.2)

節點3

docker run -d --name markserver3 consul agent -server -node marknode3 -join 172.17.0.2

節點4以Client模式

docker run -d --name markclient1 consul agent -node marknode4 -join 172.17.0.2

沒有-server參數,就會新建一個Client節點。

這個時候可以查看一下數據中心dc1的節點

docker exec markserver1 consul members

Ocelot_015_consulmembers

同時也可以在瀏覽器查看集群的狀態。因為我在節點1中啟動了WEB UI,而且映射到外部埠8500,所以我在瀏覽器直接訪問http://localhost:8500/

Ocelot_016_consulservice

Ocelot_017_consulnode

OK,這樣我們就已經啟動了Consul,接下來就是將我們的下游服務註冊到Consul中。

服務註冊
為了能讓本案例看到不一樣的效果,我特意新建了一個下游服務方法。在OcelotDownAPI項目中的Controller添加

// GET api/ocelot/consulWilling
[HttpGet("consulWilling")]
public async Task<IActionResult> ConsulWilling(int id)
{
    var result = await Task.Run(() =>
    {
        ResponseResult response = new ResponseResult()
        { Comment = $"我是Willing,你可以在Consul那裡找到我的信息, host: {HttpContext.Request.Host.Value}, path: {HttpContext.Request.Path}" };
        return response;
    });
    return Ok(result);
}

然後重新發佈到本機上的8001和8002埠。

準備好下游服務後,就可以進行註冊了。在PowerShell執行下麵的命令:
<YourIP>為我本機的IP地址,大家使用時註意替換。這裡需要使用IP,而不能直接用localhost或者127.0.0.1,因為我的Consul是部署在Docker裡面的,所以當Consul進行HealthCheck時,就無法通過localhost訪問到我本機了。

curl http://localhost:8500/v1/agent/service/register -Method PUT -ContentType 'application/json' -Body '{
  "ID": "ocelotService1",  
  "Name": "ocelotService",
  "Tags": [
    "primary",
    "v1"
  ],
  "Address": "localhost",
  "Port": 8001,
  "EnableTagOverride": false,
  "Check": {
    "DeregisterCriticalServiceAfter": "90m",
    "HTTP": "http://<YourIP>:8001/api/ocelot/5",
    "Interval": "10s"
  }
}'

Ocelot_018_consulregister

我為了後面能實現負載均衡的效果,因此,也將8002埠的服務也一併註冊進來,命令跟上面一樣,只是要將埠號更換為8002就可以了。

多說一句,關於這個命令行,其實就是用命令行的方式調用Consul服務註冊的介面,所以在實際項目中,可以將這個註冊介面調用放在下游服務的Startup.cs中,當下游服務運行即註冊,還有註銷介面調用也是一樣的道理。

Ocelot_019_consul_ocelotservice

Ocelot_020_consulcheck

服務發現
直接通過瀏覽器或者PowerShell命令行都可以進行服務發現過程。
瀏覽器訪問http://localhost:8500/v1/catalog/service/ocelotService
或者命令行curl http://localhost:8500/v1/catalog/service/ocelotService

Ocelot_023_consulcatalog

Ocelot添加Consul支持
OcelotDemo項目中安裝Consul支持,命令行或者直接使用Nuget搜索安裝

Install-Package Ocelot.Provider.Consul

在Startup.cs的ConfigureServices方法中

services
    .AddOcelot()
    .AddConsul()
    .AddSingletonDefinedAggregator<LeaderAdvancedAggregator>();

Ocelot路由配置
首先在ReRoutes中添加一組路由

{
    "DownstreamPathTemplate": "/api/ocelot/consulWilling",
    "DownstreamScheme": "http",
    "UpstreamPathTemplate": "/ocelot/consulWilling",
    "UpstreamHttpMethod": [ "Get" ],
    "LoadBalancerOptions": {
    "Type": "RoundRobin"
    },
    "ServiceName": "ocelotService",
    "Priority": 2
}

可以發現這一組路由相對其它路由,少了DownstreamHostAndPorts,多了ServiceName,也就是這一組路由的下游服務,不是由Ocelot直接指定,而是通過Consul查詢得到。

GlobalConfiguration添加ServiceDiscoveryProvider,指定服務發現支持程式為Consul。

"GlobalConfiguration": {
"BaseUrl": "http://localhost:4727",
"ServiceDiscoveryProvider": {
    "Host": "localhost",
    "Port": 8500,
    "Type": "Consul"
}
}

運行OcelotDemo,併在瀏覽器中訪問http://localhost:4727/ocelot/consulWilling

Ocelot_021_consul8001

Ocelot_022_consul8002

因為我們在這組路由中配置了使用輪詢的方式進行負載均衡,所以可以看到我們的訪問結果中,是分別從8001和8002中輪詢訪問的。

除了支持Consul,Ocelot還支持Eureka,我這裡暫時就不另外做案例了。

動態路由
當使用服務發現提供程式時,Ocelot支持使用動態路由。

上游服務請求Url模板:<Scheme>://<BaseUrl>/<ServiceName>/<ApiPath>/

例如:http://localhost:4727/ocelotService/api/ocelot/consulWilling

當Ocelot接收到請求,會向Consul查詢服務ocelotService的信息,例如獲取到對應IP為localhost,Port為8001,於是Ocelot會轉發請求到http://localhost:8001/api/ocelot/consulWilling.

Ocelot不支持動態路由與ReRoutes配置混合使用,因此,當我們要使用動態路由,就必須要保證ReRoutes中沒有配置任何路由。

來看Ocelot.json的配置

{
  "ReRoutes": [],
  "Aggregates": [],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:4727",
    "ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "Consul"
    },
    "DownstreamScheme": "http"
  }
}

這就是使用動態路由最簡單的配置,當然,在這種模式下還支持RateLimitOptions,QoSOptions,LoadBalancerOptions和HttpHandlerOptions,DownstreamScheme等配置,也允許針對每個下游服務進行個性化設置,我這裡不演示具體案例。

{
    "ReRoutes": [],
    "Aggregates": [],
    "GlobalConfiguration": {
        "RequestIdKey": null,
        "ServiceDiscoveryProvider": {
            "Host": "localhost",
            "Port": 8500,
            "Type": "Consul",
            "Token": null,
            "ConfigurationKey": null
        },
        "RateLimitOptions": {
            "ClientIdHeader": "ClientId",
            "QuotaExceededMessage": null,
            "RateLimitCounterPrefix": "ocelot",
            "DisableRateLimitHeaders": false,
            "HttpStatusCode": 429
        },
        "QoSOptions": {
            "ExceptionsAllowedBeforeBreaking": 0,
            "DurationOfBreak": 0,
            "TimeoutValue": 0
        },
        "BaseUrl": null,
            "LoadBalancerOptions": {
            "Type": "LeastConnection",
            "Key": null,
            "Expiry": 0
        },
        "DownstreamScheme": "http",
        "HttpHandlerOptions": {
            "AllowAutoRedirect": false,
            "UseCookieContainer": false,
            "UseTracing": false
        }
    }
}

運行結果如下:

Ocelot_024_consuldynamic

因為使用動態路由就要清空其它的路由配置,因此,我就不將動態路由這部分的配置commit到倉庫中了,大家要使用的時候可將我案例中的配置直接複製到Ocelot.json文件中即可。

總結

Ocelot發佈13.5.1這個版本還是挺有驚喜的,而且正巧我剛做完請求聚合的案例,所以也方便大家實踐。服務發現,就Ocelot而言只是很小的一個篇幅,因為確實只要配置幾個參數就可以靈活運用了,但在於Consul提供程式,還有Docker,這兩個都是新的知識點,對於已經接觸過的朋友很快就能搭建出來,但對於還沒玩過的朋友,就需要花點時間研究。
OK,今天就先跟大家介紹到這裡,希望大家能持續關註我們。

dotNet框架學苑


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近在研究Java爬蟲,小有收穫,打算一邊學一邊跟大家分享下,在乾貨開始前想先跟大家啰嗦幾句。 一、首先說下為什麼要研究Java爬蟲 Python已經火了很久了,它功能強大,其中很擅長的一個就是寫爬蟲程式。作為一名Javaer,想要寫爬蟲的話難道要學習python嗎? 想到這個問題我去度娘了下,其實 ...
  • 1 package com.demo; 2 3 import java.util.Scanner; 4 5 /* 6 * 題目:根據指定月份,列印該月份所屬的季節 7 * 8 * 春季:3 4 5 9 * 夏季:6 7 8 10 * 秋季:9 10 11 11 * 冬季:12 1 2 12 */ 1... ...
  • 在微服務項目中,一個系統可以分割成很多個不同的服務模塊,不同模塊之間我們通常需要進行相互調用。springcloud中可以使用RestTemplate+Ribbon和Feign來調用(工作中基本都是使用feign)。有時為了提高系統的健壯性,某些訪問量大的服務模塊還會做集群部署。但是服務之間的調用不 ...
  • 1 public class Demo { 2 3 public static void main(String[] args) { 4 5 /* 6 * 求出1~100之間,既是3又是7的倍數的自然數出現的次數 7 */ 8 int count = 0; // 計數 9 for (... ...
  • 昨天在使用VS通過ODT連接資料庫扒模型的時候發現了這個異常。經過測試,發現這個異常是因為 ODT 插件無法識別服務名中的“.”字元 導致的,比如“orcl.asian.com”。其他不包含“.”字元的服務名皆可正常連接。做了下簡單的回溯,一個月前的ODT插件是正常工作的,期間資料庫未作任何改動。唯 ...
  • 線段式佈局 有時候需要實現下麵類型的佈局方案,不知道有沒有約定俗成的稱呼,我個人強名為線段式佈局。因為元素恰好放置線上段的端點上。 實現 WPF所有佈局控制項都直接或間接的繼承自System.Windows.Controls. Panel,常用的佈局控制項有Canvas、DockPanel、Grid、S ...
  • 問題一:如何不讓WebBrowser中彈出“安全警告” 當鏈接https網址時,IE會自動彈出上圖中的視窗。 關閉視窗的具體思路如下: 使用WebBrowser載入中/載入完畢後觸發的事件處理程式,在處理程式中查找“安全警告”視窗,併在找到視窗後自動點擊“是”或“否”來關閉視窗。 具體方法是: 1. ...
  • 什麼是 I2C 匯流排 I2C 匯流排(Inter Integrated Circuit Bus)是設備與設備間通信方式的一種。它是一種串列通信匯流排,由飛利浦公司在1980年代為了讓主板、嵌入式系統或手機用以連接低速周邊設備而發展 "[1]" 。I2C 匯流排包含兩根信號線,一根為信號線 SDA ,另一根 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...