日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

构建简单的微服务架构

發(fā)布時(shí)間:2023/12/4 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 构建简单的微服务架构 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言? ? ? ? ? ? ? ?

本篇僅作引導(dǎo),內(nèi)容較多,如果閱讀不方便,可以使用電腦打開(kāi)我們的文檔官網(wǎng)進(jìn)行閱讀。如下圖所示:

文檔官網(wǎng)地址:docs.xin-lai.com


目錄

總體介紹

? 微服務(wù)架構(gòu)的好處?

? 微服務(wù)架構(gòu)的不足(這個(gè)時(shí)候就需要用到服務(wù)發(fā)現(xiàn))

? 傳統(tǒng)模式

? Ocelot(網(wǎng)關(guān))模式

? 集成IdentityService(認(rèn)證)?

? 集成consul(服務(wù)發(fā)現(xiàn))?

基于Ocelot搭建一個(gè)簡(jiǎn)單的微服務(wù)架構(gòu)?

? Ocelot?

? ? 基本集成?

? ? 添加Ocelot?

? ? 添加測(cè)試API項(xiàng)目?

? ? 配置項(xiàng)目的上游請(qǐng)求對(duì)象(ocelot.json)

? ? 啟動(dòng)結(jié)果

? 聚合API文檔(SwaggerUI)

? ? ConfigureServices

? ? Configure

? ? appsettings.json

? ? 配置Swagger的上游請(qǐng)求對(duì)象(ocelot.json)?

? ? 啟動(dòng)結(jié)果?

? IdentityServer 集成?

? ? 添加授權(quán)服務(wù)項(xiàng)目?

? ? 配置appsetting.json?

? ? 添加IdentityServerConfig類(lèi)?

? ? 定義API資源?

? ? 定義身份資源?

? ? 定義測(cè)試客服端?

? ? 配置Startup?

? ? ? ConfigureServices

? ? ? Configure

? ? 啟動(dòng)結(jié)果

? 配置ApiGateway網(wǎng)關(guān)項(xiàng)目?

? 調(diào)用Ocelot管理API?

? API方法?

? Consul(服務(wù)發(fā)現(xiàn))

? ? 本地部署?

? ? 安裝?

? ? 添加服務(wù)配置?

? ? 添加檢查配置

? docker部署(騰訊云)?

? 配置Ocelot 網(wǎng)關(guān)?

? 集成消息隊(duì)列——CAP?

? ? 簡(jiǎn)介?

? ? 環(huán)境準(zhǔn)備?

? ? .Net Core 集成 CAP

? ? Cap 發(fā)布?

? ? Cap 訂閱(接收)?

最后——附上總體代碼


總體介紹


隨著業(yè)務(wù)需求的快速發(fā)展變化,需求不斷增長(zhǎng),迫切需要一種更加快速高效的軟件交付方式。微服務(wù)可以彌補(bǔ)單體應(yīng)用不足,是一種更加快速高效軟件架構(gòu)風(fēng)格。單體應(yīng)用被分解成多個(gè)更小的服務(wù),每個(gè)服務(wù)有自己的獨(dú)立模塊,單獨(dú)部署,然后共同組成一個(gè)應(yīng)用程序。把范圍限定到單個(gè)獨(dú)立業(yè)務(wù)模塊功能。分布式部署在各臺(tái)服務(wù)器上。本篇我們將介紹如何使用.NET Core打造自己的微服務(wù)架構(gòu)。


注意:微服務(wù)架構(gòu)不是萬(wàn)能藥,本篇僅供參考和探討。對(duì)于大部分小項(xiàng)目來(lái)說(shuō),請(qǐng)不要為了微服務(wù)而微服務(wù)。畢竟技術(shù)不是萬(wàn)能的,技術(shù)是為業(yè)務(wù)服務(wù)的。


微服務(wù)架構(gòu)的好處
  • 單個(gè)服務(wù)很容易開(kāi)發(fā)、理解和維護(hù)。

  • 每個(gè)服務(wù)都可以有專(zhuān)門(mén)開(kāi)發(fā)團(tuán)隊(duì)來(lái)開(kāi)發(fā)。

  • 每個(gè)微服務(wù)獨(dú)立的部署。

  • 每個(gè)服務(wù)獨(dú)立擴(kuò)展。


微服務(wù)架構(gòu)的不足(這個(gè)時(shí)候就需要用到服務(wù)發(fā)現(xiàn))

  • 微服務(wù)應(yīng)用是分布式系統(tǒng),由此會(huì)帶來(lái)固有的復(fù)雜性。

  • 服務(wù)地址目錄,服務(wù)健康度,部署困難,服務(wù)依賴(lài)問(wèn)題,數(shù)據(jù)庫(kù)分區(qū)問(wèn)題。


傳統(tǒng)模式



Ocelot(網(wǎng)關(guān))模式



集成IdentityService(認(rèn)證)



集成consul(服務(wù)發(fā)現(xiàn))




基于Ocelot搭建一個(gè)簡(jiǎn)單的微服務(wù)架構(gòu)


規(guī)劃


初步規(guī)劃如下圖所示:


Ocelot

Ocelot 是一個(gè)僅適用于 .Net Core 的網(wǎng)關(guān)組件。Ocelot
中間件使用非常簡(jiǎn)單,難的點(diǎn)在于如何去配置。它的功能包括了:路由、請(qǐng)求聚合、服務(wù)發(fā)現(xiàn)、認(rèn)證、鑒權(quán)、限流熔斷、并內(nèi)置了負(fù)載均衡器等的集成,而這些功能都是通過(guò)配置實(shí)現(xiàn)。

Ocelot的開(kāi)源地址:https://github.com/ThreeMammals/Ocelot

Ocelot官網(wǎng)地址:https://ocelot.readthedocs.io/en/latest/index.html


基本集成


添加Ocelot

新建一個(gè) .Net core 2.2 web 項(xiàng)目(ApiGateway),添加以下Nuget包:

  • Ocelot

  • Ocelot.Administration?Ocelot支持在運(yùn)行時(shí)通過(guò)經(jīng)過(guò)身份驗(yàn)證的HTTP
    API更改配置。這可以通過(guò)兩種方式進(jìn)行身份驗(yàn)證:使用Ocelot的內(nèi)部IdentityServer(僅用于驗(yàn)證對(duì)管理API的請(qǐng)求)或?qū)⒐芾鞟PI身份驗(yàn)證掛鉤到您自己的IdentityServer中。

  • Ocelot.Cache.CacheManager?CacheManager.Net擴(kuò)展包

  • Ocelot.Provider.Polly?Polly.NET擴(kuò)展包

在項(xiàng)目根目錄添加ocelot.json,名字可以自取。

前面說(shuō)了,所有功能都是通過(guò)配置實(shí)現(xiàn)的,所以配置也相對(duì)復(fù)雜。配置有兩個(gè)部分。一組ReRoutes和一個(gè)GlobalConfiguration。ReRoutes是告訴Ocelot如何處理上游請(qǐng)求的對(duì)象。GlobalConfiguration顧名思義是全局配置,具體配置請(qǐng)查看官網(wǎng)。下面列舉簡(jiǎn)單配置

{ "GlobalConfiguration": { //外部訪(fǎng)問(wèn)路徑 "BaseUrl": "http://localhost:13000", //限速配置 "RateLimitOptions": { //白名單 "ClientWhitelist": [], "EnableRateLimiting": true, //限制時(shí)間段,例如1s,5m,1h,1d "Period": "1s", //重試等待的時(shí)間間隔(秒) "PeriodTimespan": 1, //限制 "Limit": 1, //自定義消息 "QuotaExceededMessage": "單位時(shí)間內(nèi)請(qǐng)求次數(shù)超過(guò)限制!", "HttpStatusCode": 999 }, //熔斷配置 "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 3, "DurationOfBreak": 5, //超時(shí)值(毫秒) "TimeoutValue": 5000 } }, "ReRoutes": [] }

配置文件初始化好之后,需要在Program.cs

文件中加載JSON配置,Ocelot支持根據(jù)環(huán)境變量使用配置文件。

public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => new WebHostBuilder() .UseKestrel((context, opt) => { opt.AddServerHeader = false; 從配置文件讀取配置 //opt.Configure(context.Configuration.GetSection("Kestrel")); }) .UseContentRoot(Directory.GetCurrentDirectory()) .ConfigureAppConfiguration((hostingContext, config) => { var env = hostingContext.HostingEnvironment; //根據(jù)環(huán)境變量加載不同的JSON配置 config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true) .AddJsonFile("ocelot.json") .AddEnvironmentVariables(); //從環(huán)境變量添加配置 }) .UseIISIntegration() .ConfigureLogging((hostingContext, logging) => { logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); //添加控制臺(tái)日志,Docker環(huán)境下請(qǐng)務(wù)必啟用 logging.AddConsole(); //添加調(diào)試日志 logging.AddDebug(); }) .UseStartup<Startup>(); }

然后在Startup.cs
文件ConfigureServices方法中注冊(cè)服務(wù)時(shí)使用AddOcelot(),Configure
方法中使用app.UseOcelot().Wait();?這樣網(wǎng)關(guān)的配置就完成了。

services.AddOcelot(Configuration) app.UseOcelot().Wait();


添加測(cè)試API項(xiàng)目

新建兩個(gè) .Net core 2.2 web項(xiàng)目(vs 自建的那種就OK),并使用Swagger來(lái)做接口說(shuō)明。

Nuget 添加?Swashbuckle.AspNetCore 和
Microsoft.Extensions.PlatformAbstractions?實(shí)現(xiàn)Swagger ui,代碼如下

public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddSwaggerGen(options => { options.SwaggerDoc("SwaggerAPI1", new Info { Title = "API1", Version = "v1" }); var basePath = PlatformServices.Default.Application.ApplicationBasePath; var xmlPath = Path.Combine(basePath, "Services.Test1.xml"); options.IncludeXmlComments(xmlPath); }); //服務(wù)注冊(cè) //services.Configure<ServiceRegistrationOptions> } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseSwagger(c => { c.RouteTemplate = "{documentName}/swagger.json"; }); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/SwaggerAPI1/swagger.json", "API1"); }); app.UseMvc(); }

項(xiàng)目.csproj文件中設(shè)置XML文檔輸出路徑

Services.Test1 和 Services.Test2
一樣的配置,略過(guò)。編譯啟動(dòng),頁(yè)面如下,接口配置完成。


配置項(xiàng)目的上游請(qǐng)求對(duì)象(ocelot.json)

"ReRoutes": [ //API1項(xiàng)目配置 { "UpstreamPathTemplate": "/gateway/1/{url}", "UpstreamHttpMethod": [ "Get", "Post", "Delete", "Put" ], "DownstreamPathTemplate": "/api1/{url}", "DownstreamScheme": "http", "ServiceName": "API1", "UseServiceDiscovery": true, "LoadBalancer": "RoundRobin", "DownstreamHostAndPorts": [ { "Host": "119.29.50.115", "Port": 80 }, { "Host": "localhost", "Port": 13001 } ], "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 3, "DurationOfBreak": 10, "TimeoutValue": 5000 } //"AuthenticationOptions": { // "AuthenticationProviderKey": "Bearer", // "AllowedScopes": [ // ] //} }, //API2項(xiàng)目配置 { "UpstreamPathTemplate": "/gateway/2/{url}", "UpstreamHttpMethod": [ "Get", "Post", "Delete", "Put" ], "DownstreamPathTemplate": "/api2/{url}", "DownstreamScheme": "http", "ServiceName": "API2", "UseServiceDiscovery": true, "LoadBalancer": "RoundRobin", "DownstreamHostAndPorts": [ { "Host": "111.230.160.62", "Port": 80 }, { "Host": "localhost", "Port": 13002 } ], "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 3, "DurationOfBreak": 10, "TimeoutValue": 5000 } //"AuthenticationOptions": { // "AuthenticationProviderKey": "Bearer", // "AllowedScopes": [ // ] //} }, ]

ReRoutes API對(duì)象模板配置節(jié)點(diǎn)解釋如下:

UpstreamPathTemplate

上游路徑模板

UpstreamHttpMethod

上游HTTP請(qǐng)求方法

DownstreamPathTemplate

下游路徑模板

DownstreamScheme

下游協(xié)議Https/Http

DownstreamHostAndPorts

下游主機(jī)和端口號(hào),允許配置多個(gè)

UseServiceDiscovery

是否使用服務(wù)發(fā)現(xiàn)(True/False)

ServiceName

服務(wù)名稱(chēng)(結(jié)合服務(wù)發(fā)現(xiàn)使用)

LoadBalancer

指定一個(gè)負(fù)載均衡算法: RoundRobin:輪詢(xún) LeastConnection:最少連接數(shù) NoLoadBalancer:不適用負(fù)載均衡

LoadBalancerOptions

負(fù)載均衡器配置

QoSOptions

熔斷配置,在請(qǐng)求向下游服務(wù)時(shí)使用斷路

AuthenticationOptions

權(quán)限配置


啟動(dòng)結(jié)果

啟動(dòng)web
項(xiàng)目,web頁(yè)面報(bào)錯(cuò),但無(wú)妨,使用PostMan請(qǐng)求網(wǎng)關(guān)接口訪(fǎng)問(wèn)api1/TestOnes成功。


聚合API文檔(SwaggerUI)

前面配置了網(wǎng)關(guān)接口上游,但是頁(yè)面Swagger沒(méi)有顯示,這節(jié)主要是整合SwaggerUI。

首先需要配置ApiGateway項(xiàng)目的Swagger,在配置文件配置上面兩個(gè)接口的SwaggerNames,代碼中遍歷添加到網(wǎng)關(guān)項(xiàng)目的SwaggerUI中,代碼如下


ConfigureServices

services.AddSwaggerGen(options => { options.SwaggerDoc(Configuration["Swagger:Name"], new Info { Title = Configuration["Swagger:Title"], Version = Configuration["Swagger:Version"] }); });


Configure

public void Configure(IApplicationBuilder app, IHostingEnvironment env) { var apis = Configuration["Apis:SwaggerNames"].Split(";").ToList(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc() .UseSwagger() .UseSwaggerUI(options => { apis.ToList().ForEach(key => { options.SwaggerEndpoint($"/{key}/swagger.json", key); }); options.DocumentTitle = "網(wǎng)關(guān)"; }); app.UseOcelot().Wait(); }


appsettings.json

"Swagger": { "Name": "ApiGateway", "Title": "網(wǎng)關(guān)服務(wù)", "Version": "v1" }, "Apis": { "SwaggerNames": "SwaggerAPI1;SwaggerAPI2" }

PS:SwaggerAPI1、SwaggerAPI2是前面兩個(gè)接口的SwaggerName,這里需要對(duì)應(yīng)上。


配置Swagger的上游請(qǐng)求對(duì)象(ocelot.json)

//swagger API1配置 { "DownstreamPathTemplate": "/SwaggerAPI1/swagger.json", "DownstreamScheme": "http", "UpstreamPathTemplate": "/SwaggerAPI1/swagger.json", "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ], "DownstreamHostAndPorts": [ { "Host": "119.29.50.115", "Port": 80 }, { "Host": "localhost", "Port": 13001 } ] }, //swagger API2配置 { "DownstreamPathTemplate": "/SwaggerAPI2/swagger.json", "DownstreamScheme": "http", "UpstreamPathTemplate": "/SwaggerAPI2/swagger.json", "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ], "DownstreamHostAndPorts": [ { "Host": "111.230.160.62", "Port": 80 }, { "Host": "localhost", "Port": 13002 } ] }


啟動(dòng)結(jié)果

使用SwaggerUI整合了API1和API2的接口文檔。


IdentityServer 集成

官網(wǎng)文檔地址:http://docs.identityserver.io/en/latest/index.html

IdentityServer4是一個(gè)基于OpenID Connect和 OAuth 2.0的針對(duì) ASP .NET Core 2.0的框架。

IdentityServer是將規(guī)范兼容的OpenID Connect和OAuth 2.0終結(jié)點(diǎn)添加到任意ASP .NET
Core應(yīng)用程序的中間件。你構(gòu)建包含登錄和注銷(xiāo)頁(yè)面的應(yīng)用程序,IdentityServer中間件會(huì)向其添加必要的協(xié)議頭,以便客戶(hù)端應(yīng)用程序可以使用這些標(biāo)準(zhǔn)協(xié)議與其對(duì)話(huà)。


添加授權(quán)服務(wù)項(xiàng)目

新建 .Net core 2.2 web項(xiàng)目,添加以下Nuget包:

  • IdentityServer4.AspNetIdentity

  • IdentityServer4.EntityFramework?使用數(shù)據(jù)存儲(chǔ)機(jī)制

配置appsetting.json

配置測(cè)試環(huán)境下的客服端信息和Identity API
資源配置,具體配置需要按照自己的邏輯定義,這里只是為了結(jié)合我下面的IdentityServerConfig文件所定義,代碼如下,

為了結(jié)合我下面的IdentityServerConfig文件所定義,代碼如下, "IdentityServer": { "ApiName": "default-api", "ApiSecret": "secret", "Clients": [ { "ClientId": "client", "AllowedGrantTypes": [ "password" ], "ClientSecrets": [ { "Value": "def2edf7-5d42-4edc-a84a-30136c340e13" } ], "AllowedScopes": [ "default-api" ] }, { "ClientId": "demo", "ClientName": "MVC Client Demo", "AllowedGrantTypes": [ "hybrid", "client_credentials" ], "RequireConsent": "true", "ClientSecrets": [ { "Value": "def2edf7-5d42-4edc-a84a-30136c340e13" } ], "RedirectUris": [ "http://openidclientdemo.com:8001/signin-oidc" ], "PostLogoutRedirectUris": [ "http://openidclientdemo.com:8001/signout-callback-oidc" ], "AllowedScopes": [ "openid", "profile", "default-api" ], "AllowOfflineAccess": "true" } ] }


添加IdentityServerConfig類(lèi)

IdentityServerConfig 類(lèi)分為三個(gè)方法:

  • 定義API資源

public static IEnumerable<ApiResource> GetApiResources() { return new List<ApiResource> { new ApiResource("default-api", "Default (all) API") { Description = "AllFunctionalityYouHaveInTheApplication", ApiSecrets= {new Secret("secret") } } }; }


  • 定義身份資源:

public static IEnumerable<IdentityResource> GetIdentityResources() { return new List<IdentityResource> { new IdentityResources.OpenId(), new IdentityResources.Profile(), new IdentityResources.Email(), new IdentityResources.Phone(), new IdentityResources.Address() }; } public static IEnumerable<IdentityResource> GetIdentityResources() { var customProfile = new IdentityResource( name: "custom.profile", displayName: "Custom profile", claimTypes: new[] { "name", "email", "status" }); return new List<IdentityResource> { new IdentityResources.OpenId(), new IdentityResources.Profile(), customProfile }; }


IdentityResource?具體屬性

Enabled

指示此資源是否已啟用且可以請(qǐng)求。默認(rèn)為true。

Name

標(biāo)識(shí)資源的唯一名稱(chēng)。這是客戶(hù)端將用于授權(quán)請(qǐng)求中的scope參數(shù)的值。

DisplayName

顯示名稱(chēng)。

Description

描述。

Required

默認(rèn)為false。(暫未深究理解)

Emphasize

默認(rèn)為false。(暫未深究理解)

ShowInDiscoveryDocument

指定此范圍是否顯示在發(fā)現(xiàn)文檔中。默認(rèn)為true。

UserClaims

應(yīng)包含在身份令牌中的關(guān)聯(lián)用戶(hù)聲明類(lèi)型的列表。

  • 定義測(cè)試客服端

此處則是通過(guò)appsetting.json 文件獲取配置

public static IEnumerable<Client> GetClients(IConfiguration configuration) { var clients = new List<Client>(); foreach (var child in configuration.GetSection("IdentityServer:Clients").GetChildren()) { clients.Add(new Client { ClientId = child["ClientId"], ClientName = child["ClientName"], AllowedGrantTypes = child.GetSection("AllowedGrantTypes").GetChildren().Select(c => c.Value).ToArray(), RequireConsent = bool.Parse(child["RequireConsent"] ?? "false"), AllowOfflineAccess = bool.Parse(child["AllowOfflineAccess"] ?? "false"), ClientSecrets = child.GetSection("ClientSecrets").GetChildren().Select(secret => new Secret(secret["Value"].Sha256())).ToArray(), AllowedScopes = child.GetSection("AllowedScopes").GetChildren().Select(c => c.Value).ToArray(), RedirectUris = child.GetSection("RedirectUris").GetChildren().Select(c => c.Value).ToArray(), PostLogoutRedirectUris = child.GetSection("PostLogoutRedirectUris").GetChildren().Select(c => c.Value).ToArray(), }); } return clients; }


配置Startup
  • ConfigureServices

這里只是用作測(cè)試,所以沒(méi)有在數(shù)據(jù)庫(kù)中讀取配置,而是在內(nèi)存中獲取。相應(yīng)的數(shù)據(jù)庫(kù)讀取方法也有說(shuō)明。

public void ConfigureServices(IServiceCollection services) { //var connectionString = Configuration.GetConnectionString("Default"); //services.AddDbContext<MagicodesAdminContext>(options => options.UseSqlServer(connectionString)); //services.AddIdentity<AbpUsers, AbpRoles>() // .AddEntityFrameworkStores<MagicodesAdminContext>() // .AddDefaultTokenProviders(); services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryPersistedGrants() .AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources()) .AddInMemoryApiResources(IdentityServerConfig.GetApiResources()) .AddInMemoryClients(IdentityServerConfig.GetClients(Configuration)) //.AddAspNetIdentity<AbpUsers>() //從數(shù)據(jù)庫(kù)讀取配置等內(nèi)容(clients, resources) //.AddConfigurationStore(options => //{ // options.ConfigureDbContext = b => // b.UseSqlServer(connectionString); //}) // this adds the operational data from DB (codes, tokens, consents) //.AddOperationalStore(options => //{ // options.ConfigureDbContext = b => // b.UseSqlServer(connectionString); // options.PersistedGrants.Name = "AbpPersistedGrants"; // //options.DeviceFlowCodes.Name = // // this enables automatic token cleanup. this is optional. // options.EnableTokenCleanup = true; //}); //.AddAspNetIdentity() //.AddAbpPersistedGrants<AdminDbContext>() //.AddAbpIdentityServer<User>(); ; }


  • Configure

public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseIdentityServer(); }


啟動(dòng)結(jié)果

就這樣可以啟動(dòng)服務(wù)了,瀏覽器啟動(dòng)會(huì)顯示如下頁(yè)面,因?yàn)闆](méi)有任何頁(yè)面啟動(dòng),所為顯示為404。

但無(wú)妨,我們可以使用PostMan 訪(fǎng)問(wèn):

http://localhost:13004/.well-known/openid-configuration

你會(huì)看到官方所謂的發(fā)現(xiàn)文檔??蛻?hù)端和API將使用它來(lái)下載必要的配置數(shù)據(jù)。到此為止IdentityServer服務(wù)已經(jīng)搭建成功!

首次啟動(dòng)時(shí),IdentityServer將為您創(chuàng)建一個(gè)開(kāi)發(fā)人員簽名密鑰,它是一個(gè)名為的文件。您不必將該文件檢入源代碼管理中,如果該文件不存在,將重新創(chuàng)建該文件。tempkey.rsa


配置ApiGateway網(wǎng)關(guān)項(xiàng)目

在前面Ocelot章節(jié)中,配置了ocelot.json,這里繼續(xù)修改ocelot.json文件,啟用權(quán)限認(rèn)證

{ "UpstreamPathTemplate": "/gateway/1/{url}", "UpstreamHttpMethod": [ "Get", "Post", "Delete", "Put" ], "DownstreamPathTemplate": "/api1/{url}", "DownstreamScheme": "http", "ServiceName": "API1", "UseServiceDiscovery": true, "LoadBalancer": "RoundRobin", "DownstreamHostAndPorts": [ { "Host": "119.29.50.115", "Port": 80 }, { "Host": "localhost", "Port": 13001 } ], "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 3, "DurationOfBreak": 10, "TimeoutValue": 5000 } //啟用權(quán)限認(rèn)證 "AuthenticationOptions": { "AuthenticationProviderKey": "IdentityBearer", "AllowedScopes": [ ] } }

然后還需要在A(yíng)piGateway項(xiàng)目中修改appsetting.json文件,添加IdentityService服務(wù)配置。

"IdentityService": { "Uri": "http://localhost:13004",//認(rèn)證服務(wù)IP "DefaultScheme": "IdentityBearer", "UseHttps": false, "ApiName": "default-api", "ApiSecret": "def2edf7-5d42-4edc-a84a-30136c340e13" }

接下來(lái)就是配置 ApiGateway項(xiàng)目 Startup文件了。

需要引入Nuget包:IdentityServer4.AccessTokenValidation

public void ConfigureServices(IServiceCollection services) { //Identity Server Bearer Tokens Action<IdentityServerAuthenticationOptions> isaOpt = option => { option.Authority = Configuration["IdentityService:Uri"]; option.RequireHttpsMetadata = Convert.ToBoolean(Configuration["IdentityService:UseHttps"]); option.ApiName = Configuration["IdentityService:ApiName"]; option.ApiSecret = Configuration["IdentityService:ApiSecret"]; option.SupportedTokens = SupportedTokens.Both; }; services.AddAuthentication().AddIdentityServerAuthentication(Configuration["IdentityService:DefaultScheme"], isaOpt); services .AddOcelot(Configuration) //啟用緩存 .AddCacheManager(x => { x.WithDictionaryHandle(); }) .AddPolly() services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); ; services.AddSwaggerGen(options => { options.SwaggerDoc(Configuration["Swagger:Name"], new Info { Title = Configuration["Swagger:Title"], Version = Configuration["Swagger:Version"] }); }); }

配置完成后啟用Service.Test1、Service.Test2、ApiGateway、IdentityService項(xiàng)目。使用SwaggerUI請(qǐng)求會(huì)提示401
Unauthorized,這個(gè)時(shí)候IdentityService就起到作用了。

使用PostMan去請(qǐng)求IdentityService獲取token

使用token訪(fǎng)問(wèn)接口,數(shù)據(jù)返回正常


調(diào)用Ocelot管理API

通過(guò)IdentityServer 身份驗(yàn)證來(lái)調(diào)用Ocelot 管理接口。

首先需要做的是引入相關(guān)的NuGet包:Install-Package Ocelot.Administration

修改 ApiGateway項(xiàng)目 Startup文件

添加代碼.AddAdministration(“/administration”, isaOpt);路徑名稱(chēng)可自取。

public void ConfigureServices(IServiceCollection services) { //Identity Server Bearer Tokens Action<IdentityServerAuthenticationOptions> isaOpt = option => { option.Authority = Configuration["IdentityService:Uri"]; option.RequireHttpsMetadata = Convert.ToBoolean(Configuration["IdentityService:UseHttps"]); option.ApiName = Configuration["IdentityService:ApiName"]; option.ApiSecret = Configuration["IdentityService:ApiSecret"]; option.SupportedTokens = SupportedTokens.Both; }; services.AddAuthentication().AddIdentityServerAuthentication(Configuration["IdentityService:DefaultScheme"], isaOpt); services .AddOcelot(Configuration) //啟用緩存 .AddCacheManager(x => { x.WithDictionaryHandle(); }) .AddPolly() .AddAdministration("/administration", isaOpt); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); ; services.AddSwaggerGen(options => { options.SwaggerDoc(Configuration["Swagger:Name"], new Info { Title = Configuration["Swagger:Title"], Version = Configuration["Swagger:Version"] }); }); }


API方法

POST {adminPath} / connect / token

獲取token

請(qǐng)求的主體是表單數(shù)據(jù),如下所示

client_id?設(shè)為管理員

client_secret?設(shè)置為設(shè)置管理服務(wù)時(shí)使用的任何內(nèi)容。

scope?設(shè)為管理員

grant_type?設(shè)置為client_credentials

獲取{adminPath} /configuration

獲得當(dāng)前的Ocelot配置。

POST {adminPath} / configuration

這會(huì)覆蓋現(xiàn)有配置。

請(qǐng)求的主體是JSON,它與我們用于在文件系統(tǒng)上設(shè)置Ocelot.json格式相同。

如果要使用此API,則運(yùn)行Ocelot的進(jìn)程必須具有寫(xiě)入ocelot.json或ocelot.{environment}
.json所在磁盤(pán)的權(quán)限。這是因?yàn)镺celot會(huì)在保存時(shí)覆蓋它們。

刪除{adminPath} / outputcache / {region}

清除所有緩存區(qū)域


Consul(服務(wù)發(fā)現(xiàn))

官網(wǎng)地址:https://www.consul.io/

Consul包含多個(gè)組件,但是作為一個(gè)整體,提供服務(wù)發(fā)現(xiàn)和服務(wù)配置的工具。

主要特性:

  • 服務(wù)發(fā)現(xiàn)
    組件記錄了分布式系統(tǒng)中所有服務(wù)的信息,其它服務(wù)可以據(jù)此找到這些服務(wù)。

  • 健康檢查?Consul 客戶(hù)端可用提供任意數(shù)量的健康檢查。

  • Key/Value存儲(chǔ)?應(yīng)用程序可用根據(jù)自己的需要使用 Consul 的層級(jí)的 Key/Value
    存儲(chǔ)。

  • 多數(shù)據(jù)中心
    Consul支持開(kāi)箱即用的多數(shù)據(jù)中心。這意味著用戶(hù)不需要擔(dān)心需要建立額外的抽象層讓業(yè)務(wù)擴(kuò)展到多個(gè)區(qū)域。

這里框架主要介紹服務(wù)發(fā)現(xiàn)和健康檢查。


本地部署

下載相應(yīng)版本consul
軟件包,下載地址:
https://www.consul.io/downloads.html,以下內(nèi)容為windows講解。承接上面的網(wǎng)關(guān)項(xiàng)目,整合Consul。

  • 安裝

解壓完成,只有一個(gè)consul.exe,別慌,確實(shí)就只有一個(gè)文件。

管理員運(yùn)行CMD ,CD 到consul 文件夾,直接運(yùn)行?consul
命令,出現(xiàn)如下頁(yè)面,則配置成功

  • 添加服務(wù)配置

添加服務(wù)注冊(cè)配置文件,在consul.exe同級(jí)目錄下添加config
(名字可自取)文件夾,在config
文件夾中創(chuàng)建service.json(名字可自取)文件,用來(lái)注冊(cè)服務(wù)和服務(wù)檢查配置。如圖所示:

配置service.json,代碼如下:

{ "services": [ { "id": "API1",//唯一標(biāo)識(shí) "name": "API1",//服務(wù)名稱(chēng) "tags": [ "API1" ],//服務(wù)標(biāo)簽 "address": "172.0.0.1",//我隨便配的IP,注意配置服務(wù)的真實(shí)IP和port "port": 80 }, { "id": "API2", "name": "API2", "tags": [ "API2" ], "address": "172.0.0.1",//我隨便配的IP,注意配置服務(wù)的真實(shí)IP和port "port": 81 } ] }

這樣服務(wù)注冊(cè)配置就OK了,接下來(lái)使用配置啟動(dòng)Consul,下面是幾種形式啟動(dòng)consul,詳細(xì)的命令參數(shù)可以移步到官方文檔查看。

  • 以開(kāi)發(fā)模式啟動(dòng)?consul agent -dev -config-dir=./config

  • 以服務(wù)方式啟動(dòng)?consul agent -server -bootstrap-expect 2 -data-dir
    ./tmp/consul -node=n1 -bind=192.168.109.241 -ui-dir ./dist -dc=dc1

  • 以客戶(hù)端方式啟動(dòng)?consul agent -data-dir ./tmp/consul -ui-dir ./dist
    -bind=192.168.109.204 -dc=dc1

開(kāi)發(fā)模式啟動(dòng)如下,在輸出窗口中可以看到consul ui HTTP 啟動(dòng)路徑為
127.0.0.1:8500?,注冊(cè)了API 和 API2 兩個(gè)服務(wù)。

瀏覽器訪(fǎng)問(wèn) 127.0.0.1:8500 ,可以看到Consul UI頁(yè)面

  • 添加檢查配置

需要查看服務(wù)的運(yùn)行狀態(tài)是否健康,就需要配置檢查。具體檢查配置移步官方文檔。

檢查定義有一下幾種:

腳本檢查:

{ "check": { "id": "mem-util", "name": "Memory utilization", "args": ["/usr/local/bin/check_mem.py", "-limit", "256MB"], "interval": "10s", "timeout": "1s" } }

HTTP檢查:

{ "check": { "id": "api", "name": "HTTP API on port 5000", "http": "https://localhost:5000/health", "tls_skip_verify": false, "method": "POST", "header": {"x-foo":["bar", "baz"]}, "interval": "10s", "timeout": "1s" } }

TCP檢查:

{ "check": { "id": "ssh", "name": "SSH TCP on port 22", "tcp": "localhost:22", "interval": "10s", "timeout": "1s" } }

TTL檢查:

{ "check": { "id": "web-app", "name": "Web App Status", "notes": "Web app does a curl internally every 10 seconds", "ttl": "30s" } }

Docker檢查:

{ "check": { "id": "mem-util", "name": "Memory utilization", "docker_container_id": "f972c95ebf0e", "shell": "/bin/bash", "args": ["/usr/local/bin/check_mem.py"], "interval": "10s" } }

gRPC檢查:

{ "check": { "id": "mem-util", "name": "Service health status", "grpc": "127.0.0.1:12345", "grpc_use_tls": true, "interval": "10s" } }

本地服務(wù)的別名檢查:

{ "check": { "id": "web-alias", "alias_service": "web" } }

我這邊簡(jiǎn)單使用了TCP檢查, 繼續(xù)修改service.json文件,檢測(cè) tcp為
“172.0.0.1:80”的服務(wù),修改為如下代碼:

{ "services": [ { "id": "API1",//唯一標(biāo)識(shí) "name": "API1",//服務(wù)名稱(chēng) "tags": [ "API1" ],//服務(wù)標(biāo)簽 "address": "172.0.0.1",//我隨便配的IP,注意配置服務(wù)的真實(shí)IP和port "port": 80 }, { "id": "API2", "name": "API2", "tags": [ "API2" ], "address": "172.0.0.1",//我隨便配的IP,注意配置服務(wù)的真實(shí)IP和port "port": 81 } ], "check": [ { "id": "APICheck", "name": "APICheck", "tcp": "119.29.50.115:80", "interval": "10s", "timeout": "1s" } ] }

check
定義為service同級(jí)節(jié)點(diǎn)則是為所有服務(wù)使用同一個(gè)檢查規(guī)則,定義在services節(jié)點(diǎn)內(nèi)則是具體為某一個(gè)服務(wù)定義檢查規(guī)則

啟動(dòng)如下圖,很明顯多了一個(gè)名叫APICheck 的代理。

啟動(dòng)頁(yè)面也有不同,checks 為2了,說(shuō)明check
配置成功了。點(diǎn)擊某個(gè)服務(wù)進(jìn)去可以查看詳細(xì)信息


docker部署(騰訊云)

前面說(shuō)的是本地部署,現(xiàn)在說(shuō)一下基于騰訊云docker
部署。首先拉去docker鏡像創(chuàng)建服務(wù)。

Docker Hub(鏡像文件庫(kù))?里包含Consul
的鏡像文件,只需要在Docker創(chuàng)建服務(wù)使用鏡像就可以了。

設(shè)置容器端口為8500,服務(wù)端口為80,通過(guò)Ingress進(jìn)行路由轉(zhuǎn)發(fā)。

訪(fǎng)問(wèn)服務(wù)外網(wǎng),結(jié)果如下,配置成功

配置Ocelot 網(wǎng)關(guān)

首先修改前面的網(wǎng)關(guān)項(xiàng)目ApiGateway Startup.cs 文件里的 ConfigureServices方法,添加
.AddConsul()方法代碼如下:

public void ConfigureServices(IServiceCollection services) { //Identity Server Bearer Tokens Action<IdentityServerAuthenticationOptions> isaOpt = option => { option.Authority = Configuration["IdentityService:Uri"]; option.RequireHttpsMetadata = Convert.ToBoolean(Configuration["IdentityService:UseHttps"]); option.ApiName = Configuration["IdentityService:ApiName"]; option.ApiSecret = Configuration["IdentityService:ApiSecret"]; option.SupportedTokens = SupportedTokens.Both; }; services.AddAuthentication().AddIdentityServerAuthentication(Configuration["IdentityService:DefaultScheme"], isaOpt); services .AddOcelot(Configuration) .AddConsul() //啟用緩存 .AddCacheManager(x => { x.WithDictionaryHandle(); }) .AddPolly() .AddAdministration("/administration", isaOpt); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); ; services.AddSwaggerGen(options => { options.SwaggerDoc(Configuration["Swagger:Name"], new Info { Title = Configuration["Swagger:Title"], Version = Configuration["Swagger:Version"] }); }); }

接下來(lái)配置ocelot.json 文件,在GlobalConfiguration
節(jié)點(diǎn)下添加服務(wù)發(fā)現(xiàn)提供程序配置

//服務(wù)發(fā)現(xiàn)提供程序 "ServiceDiscoveryProvider": { "Host": "111.230.118.59", "Port": 80, "Type": "PollConsul", "PollingInterval": 1000 }

項(xiàng)目上游配置添加ServiceName?和?UseServiceDiscovery屬性,代碼如下:

{ "UpstreamPathTemplate": "/gateway/2/{url}", "UpstreamHttpMethod": [ "Get", "Post", "Delete", "Put" ], "DownstreamPathTemplate": "/api2/{url}", "DownstreamScheme": "http", "ServiceName": "API2", "UseServiceDiscovery": true, "LoadBalancer": "RoundRobin", "DownstreamHostAndPorts": [ { "Host": "111.230.160.62", "Port": 80 }, { "Host": "localhost", "Port": 13002 } ], "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 3, "DurationOfBreak": 10, "TimeoutValue": 5000 } "AuthenticationOptions": { "AuthenticationProviderKey": "IdentityBearer", "AllowedScopes": [ ] } }

啟動(dòng)OcelotGateway,API001,API002項(xiàng)目,通過(guò)

http://localhost:13000/gateway/1/values

http://localhost:13000/gateway/2/values訪(fǎng)問(wèn);因?yàn)镺celot配置了Consul的服務(wù)治理,所以可以通過(guò)配置的服務(wù)名稱(chēng)和GlobalConfiguratin的Consul
http
api接口查找到對(duì)應(yīng)服務(wù)的地址,進(jìn)行訪(fǎng)問(wèn),這些都是Ocelot幫我們做,這點(diǎn)很容易證明,可以修改Consul配置文件中服務(wù)的address為錯(cuò)誤IP,就會(huì)發(fā)現(xiàn)通過(guò)13000端口訪(fǎng)問(wèn)不成功。


集成消息隊(duì)列——CAP


簡(jiǎn)介

CAP 是一個(gè)基于 .NET Standard 的 C#
庫(kù),它是一種處理分布式事務(wù)的解決方案,同樣具有 EventBus
的功能,它具有輕量級(jí)、易使用、高性能等特點(diǎn)。

微服務(wù)系統(tǒng)的過(guò)程中,通常需要使用事件來(lái)對(duì)各個(gè)服務(wù)進(jìn)行集成,在這過(guò)程中簡(jiǎn)單的使用消息隊(duì)列并不能保證數(shù)據(jù)的最終一致性,
CAP
采用的是和當(dāng)前數(shù)據(jù)庫(kù)集成的本地消息表的方案來(lái)解決在分布式系統(tǒng)互相調(diào)用的各個(gè)環(huán)節(jié)可能出現(xiàn)的異常,它能夠保證任何情況下事件消息都是不會(huì)丟失的。

Github 地址:https://github.com/dotnetcore/CAP

支持消息隊(duì)列:

  • Kafka

  • RabbitMQ

  • AzureServiceBus

數(shù)據(jù)庫(kù)存儲(chǔ):

  • Sql Server

  • MySql

  • PostgreSQL

  • MongoDB


環(huán)境準(zhǔn)備

我們以RabbitMQ 與Sql Server來(lái)講解。

首先我們需要安裝RabbitMQ 服務(wù),很簡(jiǎn)單,官方下載最新的安裝包。

但是在安裝RabbitMQ
時(shí)會(huì)提示安裝Erlang,Erlang是一種通用的面向并發(fā)的編程語(yǔ)言,Erlang來(lái)編寫(xiě)分布式應(yīng)用要簡(jiǎn)單的多。RabbitMQ是用Erlang實(shí)現(xiàn)的一個(gè)高并發(fā)高可靠AMQP消息隊(duì)列服務(wù)器。

官方下載對(duì)應(yīng)的Erlang 安裝程序,建議RabbitMQ和Erlang都安裝最新版本

安裝完成之后,會(huì)多了以下幾個(gè)程序,安裝包幫我生成了start、remove、stop等命令程序。我們拿來(lái)直接用就可以了,當(dāng)然你也可以配置環(huán)境變量,使用命令啟動(dòng)。先運(yùn)行start
程序運(yùn)行起來(lái)。


.Net Core 集成 CAP

Nuget 包下載:

  • DotNetCore.CAP 核心包

  • DotNetCore.CAP.RabbitMQ CAP RabbitMQ 包

  • DotNetCore.CAP.SqlServer CAP Sql Server 擴(kuò)展包

繼續(xù)修改測(cè)試項(xiàng)目Service.Test1項(xiàng)目,使用CodeFirst生成數(shù)據(jù)庫(kù):

新建測(cè)試類(lèi)Test:

public class Test { public int Id { get; set; } public string Name { get; set; } public string Title { get; set; } }

添加AppDbContext?數(shù)據(jù)庫(kù)上下文 文件,代碼如下:

public class AppDbContext:DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } public virtual DbSet<Test> Tests { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); } }

配置數(shù)據(jù)庫(kù)連接字符串:

"ConnectionStrings": { "Default": "Server=(localdb)\\MSSQLLocalDB; Database=Service_test1; Trusted_Connection=True;" }

Program.cs?文件配置讀取appsettings.json文件。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables(); }) .UseStartup<Startup>();

Startup.cs?文件ConfigureServices添加數(shù)據(jù)訪(fǎng)問(wèn)配置

services.AddDbContext<AppDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Default"))); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

到這里正常的CodeFirst
項(xiàng)目配置已經(jīng)完成了,直接運(yùn)行數(shù)據(jù)遷移命令就可以創(chuàng)建數(shù)據(jù)庫(kù)了。

但是我這里需要集成CAP,肯定這樣是不行的。需要進(jìn)行CAP的配置,繼續(xù)在ConfigureServices
添加如下代碼:

services.AddDbContext<AppDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Default"))); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); Action<CapOptions> capOptions = option => { option.UseEntityFramework<AppDbContext>(); option.UseSqlServer(Configuration.GetConnectionString("Default")); option.UseRabbitMQ("localhost");//UseRabbitMQ 服務(wù)器地址配置,支持配置IP地址和密碼 option.UseDashboard();//CAP2.X版本以后官方提供了Dashboard頁(yè)面訪(fǎng)問(wèn)。 if (Convert.ToBoolean(Configuration["Cap:UseConsul"])) { option.UseDiscovery(discovery => { discovery.DiscoveryServerHostName = Configuration["Cap:DiscoveryServerHostName"]; discovery.DiscoveryServerPort = Convert.ToInt32(Configuration["Cap:DiscoveryServerPort"]); discovery.CurrentNodeHostName = Configuration["Cap:CurrentNodeHostName"]; discovery.CurrentNodePort = Convert.ToInt32(Configuration["Cap:CurrentNodePort"]); discovery.NodeId = Convert.ToInt32(Configuration["Cap:NodeId"]); discovery.NodeName = Configuration["Cap:NodeName"]; discovery.MatchPath = Configuration["Cap:MatchPath"]; }); } }; services.AddCap(capOptions);

RabbitMQ 也是支持配置options

option.UseRabbitMQ(cfg => { cfg.HostName = Configuration["MQ:Host"]; cfg.VirtualHost = Configuration["MQ:VirtualHost"]; cfg.Port = Convert.ToInt32(Configuration["MQ:Port"]); cfg.UserName = Configuration["MQ:UserName"]; cfg.Password = Configuration["MQ:Password"]; });

CAP 內(nèi)置集成了Consul
服務(wù)注冊(cè),注冊(cè)的同時(shí)默認(rèn)攜帶了簡(jiǎn)況檢查,但是只支持HTTP檢查,所以我們需要在接口中定義health
路徑提供給檢查訪(fǎng)問(wèn)。

在appsetting.json 文件中添加相應(yīng)的配置節(jié)點(diǎn):

"Cap": { "UseConsul": true,//是否開(kāi)啟 "CurrentNodeHostName": "localhost",//當(dāng)前節(jié)點(diǎn)IP "CurrentNodePort": 13001,//當(dāng)前節(jié)點(diǎn)Port "DiscoveryServerHostName": "127.0.0.1",//發(fā)現(xiàn)服務(wù)主機(jī)IP "DiscoveryServerPort": 8500,//發(fā)現(xiàn)服務(wù)主機(jī)Port "NodeId": 1,//節(jié)點(diǎn)標(biāo)識(shí) "NodeName": "CAP_API1",//節(jié)點(diǎn)名稱(chēng) "MatchPath": "/api1/TestOnes"//健康檢查根路勁 最終的路徑為api1/TestOnes/health }

進(jìn)行數(shù)據(jù)遷移創(chuàng)建數(shù)據(jù)庫(kù),表結(jié)構(gòu)如下:

  • Cap 發(fā)布

接下來(lái)就是去使用Cap 發(fā)布了,修改Controller代碼

public class TestOnesController : ControllerBase { private readonly ICapPublisher _capBus; public TestOnesController(ICapPublisher capPublisher) { _capBus = capPublisher; } [HttpGet] public ActionResult<IEnumerable<string>> Get() { _capBus.Publish("services.test1.show.time", DateTime.Now); return new string[] { "TestOnes_value1", "TestOnes_value2" }; } //定義路由為health提供給服務(wù)檢查使用 [HttpGet] [Route("health")] public ActionResult<string> Health() { return "Health!!!!!"; } }

因?yàn)閱⒂玫腃onsul ,所以要按照前面說(shuō)過(guò)的consul 教程來(lái)啟動(dòng)consul

訪(fǎng)問(wèn)http://127.0.0.1:8500,頁(yè)面如下

接下來(lái)啟動(dòng)項(xiàng)目,還是老樣子直接看到如下頁(yè)面。

但是我們集成了CAP,所以可以訪(fǎng)問(wèn)呢http://localhost:13001/cap?訪(fǎng)問(wèn)cap
Dashboard頁(yè)面查看詳細(xì)

這里一般啟動(dòng)的話(huà)發(fā)出的時(shí)不存在,也是因?yàn)榍懊嬗袦y(cè)試過(guò),數(shù)據(jù)庫(kù)里存在了。我們調(diào)用api1/TestOnes方法
發(fā)出消息。

請(qǐng)求成功,在來(lái)看看數(shù)據(jù)庫(kù)。數(shù)據(jù)庫(kù)多了兩張表,以張是接收數(shù)據(jù)表,一張是發(fā)布數(shù)據(jù)表。

再來(lái)看看里面的數(shù)據(jù),也是就是發(fā)布的消息,因?yàn)橹罢?qǐng)求過(guò)四次,我這邊就多了四條數(shù)據(jù)。

cap Dashboard也能看到一些統(tǒng)計(jì)和數(shù)據(jù)列表

再來(lái)看看consul 頁(yè)面,一個(gè)CAP_API1 的服務(wù)已經(jīng)被注冊(cè)進(jìn)來(lái)了

如果前面?MatchPath
路徑?jīng)]有配置對(duì)的話(huà),就會(huì)出現(xiàn)下面的情況,導(dǎo)致無(wú)法通過(guò)健康檢查。

  • Cap 訂閱(接收)

使用API訂閱消息,為了方便,使用同一個(gè)項(xiàng)目的另一個(gè)接口實(shí)現(xiàn)訂閱

[Route("api1/[controller]")] [ApiController] public class ValuesController : ControllerBase { [HttpGet("Received")] [CapSubscribe("services.test1.show.time")]//配置發(fā)布時(shí)填寫(xiě)的Name public ActionResult<string> GetReceivedMessage(DateTime datetime) { Console.WriteLine("訂閱:"+datetime); return "訂閱:" + datetime; } }

這樣就OK了,但是如果你時(shí)在不同的項(xiàng)目,還是需要像前面一樣配置CAP。

啟動(dòng)項(xiàng)目請(qǐng)求一次CAP發(fā)布接口,查看http://localhost:13001/cap
可以看到接收的里面有1條數(shù)據(jù)

訂閱列表中也有了一條數(shù)據(jù)

在來(lái)看數(shù)據(jù)庫(kù)也添加一條數(shù)據(jù)


最后——附上總體代碼

整個(gè)實(shí)踐代碼已托管到Github,具體如下所示:

https://github.com/magicodes/Magicodes.Simple.Services


總結(jié)

以上是生活随笔為你收集整理的构建简单的微服务架构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。