架构师_程序员

查看: 84|回复: 0
打印 上一主题 下一主题

[资料] 【架构篇】ASP.NET Core 基于 Consul 之服务高可用

[复制链接]
跳转到指定楼层
楼主
发表于 2020-10-16 18:33:07 | 只看该作者
在开发互联网项目中,需要各项服务之间进行数据交互、用户从服务器中获取数据,服务接口高可用显得尤为重要,尤其在电商、支付系统中,高可用也衡量着系统是否健壮。集群的情况下,众多的服务也难以维护。

Consul 回顾

Consul 是HashiCorp公司推出的使用go语言开发的开源工具,用于实现分布式系统的服务发现与配置,内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案,使用起来较为简单。

【架构篇】.net/c# 基于 Consul 实现分布式配置之Key/Value存储
https://www.itsvse.com/thread-9420-1-1.html

【架构篇】ASP.NET Core 基于 Consul 动态配置热更新
https://www.itsvse.com/thread-9421-1-1.html


Consul 服务发现

Consul服务发现的使用方法:

  • 在每台电脑上都以Client Mode的方式运行一个Consul代理, 这个代理只负责与Consul Cluster高效地交换最新注册信息(不参与Leader的选举)
  • 每台电脑上的服务Service都向本机的consul代理注册 服务名称和提供服务的url
  • 当Computer1上部署的程序ServiceA需要调用服务ServiceB时, 程序ServiceA直接从本机的Consul Agent通过服务名称获取ServiceB的访问地址, 然后直接向ServiceB的url发出请求。




代码如下:

  1. using Consul;
  2. using Microsoft.AspNetCore.Builder;
  3. using Microsoft.AspNetCore.Hosting;
  4. using Microsoft.Extensions.Configuration;
  5. using Microsoft.Extensions.Hosting;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Threading.Tasks;

  10. namespace WebApplication1
  11. {
  12.     public static class RegisterConsulExtension
  13.     {
  14.         public static void RegisterToConsul(this IApplicationBuilder app, IHostApplicationLifetime lifetime, IConfiguration configuration)
  15.         {
  16.             var listenUrls = app.ServerFeatures.Get<Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature>().Addresses;
  17.             var consulUrl = configuration["Consul_Url"];
  18.             var healthUrl = configuration["Health_Url"];
  19.             TryGetServiceUrl(listenUrls, out string a, out string b, out int c);
  20.             //注册服务
  21.             lifetime.ApplicationStarted.Register(() =>
  22.             {
  23.                 var consulClient = new ConsulClient(ConsulClientConfiguration => ConsulClientConfiguration.Address = new Uri(consulUrl));

  24.                 var httpCheck = new AgentServiceCheck()
  25.                 {
  26.                     DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(10),//服务启动多久后注册
  27.                     Interval = TimeSpan.FromSeconds(10),
  28.                     HTTP = $"{a}://{b}:{c}{healthUrl}",
  29.                     Timeout = TimeSpan.FromSeconds(3)
  30.                 };

  31.                 // 生成注册请求
  32.                 var registration = new AgentServiceRegistration()
  33.                 {
  34.                     Checks = new[] { httpCheck },
  35.                     ID = Guid.NewGuid().ToString(),
  36.                     Name = "test.itsvse",
  37.                     Address = b,
  38.                     Port = c,
  39.                     Tags = new string[] { "test", "itsvse" }
  40.                 };
  41.                 consulClient.Agent.ServiceRegister(registration).Wait();
  42.                 //服务停止时, 主动发出注销
  43.                 lifetime.ApplicationStopping.Register(() =>
  44.                 {
  45.                     try
  46.                     {
  47.                         consulClient.Agent.ServiceDeregister(registration.ID).Wait();
  48.                     }
  49.                     catch
  50.                     { }
  51.                 });
  52.             });

  53.         }

  54.         private static void TryGetServiceUrl(ICollection<string> listenUrls,out string scheme,out string host,out int port)
  55.         {
  56.             if (listenUrls == null || listenUrls.Count == 0) throw new Exception("Could not get listening port");
  57.             Uri uri = new Uri(listenUrls.ToArray()[0]);
  58.             scheme = uri.Scheme;
  59.             host = uri.Host;
  60.             port = uri.Port;
  61.         }
  62.     }
  63. }
复制代码


在 Startup 类中调用如下:

  1. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime)
  2.         {
  3.         ...
  4.                 app.RegisterToConsul(lifetime, Configuration);
  5. }
复制代码


健康检查

consul 需要向服务定时发送请求,确保服务在正常运行状态,健康检查接口只需要向 consul 返回 200 状态码即可,代码如下:

  1. app.UseHealthChecks(Configuration["Health_Url"], new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions()
  2.             {
  3.                 ResultStatusCodes =
  4.                 {
  5.                     [Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus.Healthy] = Microsoft.AspNetCore.Http.StatusCodes.Status200OK,
  6.                     [Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus.Degraded] = Microsoft.AspNetCore.Http.StatusCodes.Status503ServiceUnavailable,
  7.                     [Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus.Unhealthy] = Microsoft.AspNetCore.Http.StatusCodes.Status503ServiceUnavailable
  8.                 }
  9.             });
复制代码


启动项目,注册服务

控制器随便定义一个 test 方法,如下:

  1. using Microsoft.AspNetCore.Mvc;
  2. using Microsoft.Extensions.Configuration;
  3. using Microsoft.Extensions.Logging;

  4. namespace WebApplication1.Controllers
  5. {
  6.     public class HomeController : Controller
  7.     {
  8.         private readonly ILogger<HomeController> _logger;

  9.         public readonly IConfiguration _configuration;

  10.         public HomeController(ILogger<HomeController> logger, IConfiguration configuration)
  11.         {
  12.             _logger = logger;
  13.             _configuration = configuration;
  14.         }

  15.         public IActionResult Index()
  16.         {
  17.             return View();
  18.         }

  19.         public IActionResult Test()
  20.         {
  21.             return Ok(_configuration["key1"]);
  22.         }
  23.     }
  24. }
复制代码


我们进入到项目的bin目录下面,通过命令行启动,代码如下:

  1. dotnet WebApplication1.dll --urls="http://127.0.0.1:8082" --key1="value 1"
  2. dotnet WebApplication1.dll --urls="http://127.0.0.1:8083" --key1="value 2"
复制代码




通过浏览器查看链接:

http://127.0.0.1:8500/ui/dc1/services/test.itsvse



http://127.0.0.1:8500/v1/catalog/service/test.itsvse

json数据如下:

[
    {
        "ID": "bb644359-6b2a-a27e-7a0a-a1950b8e515f",
        "Node": "DESKTOP-EB7B69D",
        "Address": "127.0.0.1",
        "Datacenter": "dc1",
        "TaggedAddresses": {
            "lan": "127.0.0.1",
            "wan": "127.0.0.1"
        },
        "NodeMeta": {
            "consul-network-segment": ""
        },
        "ServiceKind": "",
        "ServiceID": "507338bf-a5a6-4013-9675-c43a40a2c1a0",
        "ServiceName": "test.itsvse",
        "ServiceTags": [
            "test",
            "itsvse"
        ],
        "ServiceAddress": "127.0.0.1",
        "ServiceWeights": {
            "Passing": 1,
            "Warning": 1
        },
        "ServiceMeta": {},
        "ServicePort": 8083,
        "ServiceEnableTagOverride": false,
        "ServiceProxy": {
            "MeshGateway": {},
            "Expose": {}
        },
        "ServiceConnect": {},
        "CreateIndex": 1317,
        "ModifyIndex": 1317
    },
    {
        "ID": "bb644359-6b2a-a27e-7a0a-a1950b8e515f",
        "Node": "DESKTOP-EB7B69D",
        "Address": "127.0.0.1",
        "Datacenter": "dc1",
        "TaggedAddresses": {
            "lan": "127.0.0.1",
            "wan": "127.0.0.1"
        },
        "NodeMeta": {
            "consul-network-segment": ""
        },
        "ServiceKind": "",
        "ServiceID": "bb21f150-7219-4eda-bc91-54686a750228",
        "ServiceName": "test.itsvse",
        "ServiceTags": [
            "test",
            "itsvse"
        ],
        "ServiceAddress": "127.0.0.1",
        "ServiceWeights": {
            "Passing": 1,
            "Warning": 1
        },
        "ServiceMeta": {},
        "ServicePort": 8082,
        "ServiceEnableTagOverride": false,
        "ServiceProxy": {
            "MeshGateway": {},
            "Expose": {}
        },
        "ServiceConnect": {},
        "CreateIndex": 1314,
        "ModifyIndex": 1314
    }
]


Consul 服务调用

新建一个 .net core 控制台项目,代码如下:

  1. using Consul;
  2. using System;
  3. using System.Linq;
  4. using System.Net.Http;

  5. namespace Consul_Service
  6. {
  7.     class Program
  8.     {
  9.         static void Main(string[] args)
  10.         {
  11.             var consulClient = new ConsulClient(x => x.Address = new Uri($"http://127.0.0.1:8500"));//请求注册的 Consul 地址
  12.             var ret = consulClient.Agent.Services();

  13.             var client = new HttpClient();
  14.             for (int i = 0; i < 20; i++)
  15.             {
  16.                 var allServer = ret.GetAwaiter().GetResult();
  17.                 //这个是个dictionary的返回值,他的key是string类型,就是8500/ui上services的instance的id
  18.                 var allServerDic = allServer.Response;

  19.                 var server = allServerDic.Values.OrderBy(x => Guid.NewGuid()).FirstOrDefault(x => x.Service == "test.itsvse");
  20.                 if (server != null)
  21.                 {
  22.                     Console.WriteLine($"serverName:{server.Service}==serverAddress:{server.Address}==serverPort{server.Port}");
  23.                     var value = client.GetStringAsync("http://" + server.Address + ":" + server.Port + "/home/test").Result;
  24.                     Console.WriteLine(value);
  25.                 }
  26.             }
  27.             Console.ReadKey();
  28.         }
  29.     }
  30. }
复制代码


我是随机调用注册的 test.itsvse 服务,执行结果如下:



最后,源码下载:

游客,如果您要查看本帖隐藏内容请回复




上一篇:【架构篇】ASP.NET Core 基于 Consul 动态配置热更新
下一篇:dmp文件导入异常
帖子永久地址: 

架构师_程序员 - 论坛版权1、本主题所有言论和图片纯属会员个人意见,与本论坛立场无关
2、本站所有主题由该帖子作者发表,该帖子作者与架构师_程序员享有帖子相关版权
3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和架构师_程序员的同意
4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
7、架构师_程序员管理员和版主有权不事先通知发贴者而删除本文

码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

免责声明:
码农网所发布的一切软件、编程资料或者文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:help@itsvse.com

QQ|手机版|小黑屋|架构师 ( 鲁ICP备14021824号-2 )|网站地图

GMT+8, 2020-10-28 19:31

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表