zoukankan      html  css  js  c++  java
  • winserver的consul部署实践与.net core客户端使用(附demo源码)

    前言

    随着微服务兴起,服务的管理显得极其重要。都知道微服务就是”拆“,把臃肿的单块应用,拆分成多个轻量级的服务,每个服务可以在短周期内重构、迭代、交付。随着微服务的数量增多,因量变引起了质量,带来新的问题其中一个是服务的管理问题。随着业务发展微服务增多,可能技术负责人也无法清楚记着服务的部署情况,服务的健康也不能时刻关注着,因此服务治理系统的作用必不可少。

    本篇文章的源码:

    demo:https://github.com/SkyChenSky/Consul.Demo

    封装:https://github.com/SkyChenSky/Sikiro.Tookits.Consul

    Consul

    Consul是一款简单、易用、可伸缩性强的服务治理系统。

    主要核心功能有:

    1. 服务发现
    2. 健康检查
    3. 键值存储
    4. 多数据中心

    consul代理会每个一段时间对注册中心的服务节点进行访问,如果响应码为“20X"认为是健康。

    键值存储可以认为是一个简易的k/v数据库,因此可以用此来存放配置信息。

    服务发现

    服务发现分服务注册和服务查找。

    服务注册

    将服务节点信息(地址+端口)添加(删除)到注册表,注册表会记录着服务的节点信息和状态

    服务查找

    由其他的服务或者系统通过注册表查询到指定可用服务的节点信息。

    服务发现的方式

    服务发现的方式又分自主式和代理式。

    自主式

    由各个服务主动的将自己节点信息添加(删除)到注册中心。实现是通过统一封装或者程序库,由服务各个节点承担服务发现的功能,与代理式相比由各自节点分担的访问压力。

    代理式

    由一个系统(负载均衡系统)或者服务(API网关)来完成服务发现。因为由一个系统或者服务完成,随着注册服务的增加会带来性能瓶颈,因此需要对此做集群。

    Consul模式

    Consul有两种模式,Client和Server,无论各种模式都有一个consul agent。

    Client模式

    Client模式是一个轻量级的consul agent,只拥有注册服务、健康检查、转发查询等功能。

    Server模式

    Server模式与Client模式相比,除了拥有Client模式的功能还多出了数据存储,leader选举等。

    官方建议Server模式应保证3-5个,而且应该是奇数,为什么呢,因为少于3个无法保证高可用,多于5个又会给数据库同步的一致性带来压力,而Client数量控制则没有讲究。

    集群部署

    下载consul https://www.consul.io/downloads.html

    在服务器A,打开cmd,

    consul agent -server -bootstrap-expect=1 -bind=192.168.20.80 -client=192.168.20.80 -join=192.168.20.80 -datacenter=dc1 -data-dir=data -ui -node=consul-80

    在服务器B,打开cmd,

    consul agent -server -bind=192.168.20.81 -client=192.168.20.81 -join=192.168.20.80 -data-dir=data -node=consul-81 

    打开浏览器输入http://192.168.20.80:8500

    指令简析

    • -server
      • consul以server模式启动,不填则默认以client模式
    • -bootstrap-expect=1
      • 集群节点数,当集群节点数达到声明数量才会进行数据同步
    • -bind=192.168.20.80
      • 当前consul服务绑定地址
    • -client=192.168.20.80
      • http接口绑定地址,客户端调用需要
    • -join=192.168.20.80
      • 启动服务时加入目标集群
    • -node=consul-81
      • 服务节点名称
    • -ui
      • 启动web管理后台

    客户端实践

    安装Consul

    封装扩展

    只贴部分核心代码,具体可以查看demo源码。

    注入ConsulClient

    public static IServiceCollection AddConsul(this IServiceCollection serviceCollection, Action<ConsulConfiguration> optionAction)
            {
                _consulConfiguration = new ConsulConfiguration();
                optionAction(_consulConfiguration);
    
                var consulClient = new ConsulClient(x =>
                    x.Address = new Uri(_consulConfiguration.Host));
    
                serviceCollection.AddSingleton(consulClient);
    
                return serviceCollection;
            }

    把当前服务注册到Consul

    private static ConsulConfiguration _consulConfiguration;
    
            public static IApplicationBuilder UseConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, Action<ServerConfiguration> optionAction)
            {
                var consulClient = app.ApplicationServices.GetService<ConsulClient>();
                if (consulClient == null)
                    throw new Exception("please AddConsul first");
    
                var serverConfiguration = new ServerConfiguration();
                optionAction(serverConfiguration);
    
                var serviceRegistration = GetServiceRegistration(serverConfiguration);
    
                //添加注册
                consulClient.Agent.ServiceRegister(serviceRegistration).Wait();
    
                //取消注册
                lifetime.ApplicationStopping.Register(() =>
                {
                    consulClient.Agent.ServiceDeregister(serviceRegistration.ID).Wait();
                });
                return app;
            }
    private static Uri GetSelfUri(string uristring)
            {
                return new Uri(uristring);
            }
    
            private static AgentServiceRegistration GetServiceRegistration(ServerConfiguration serverConfiguration)
            {
                var localIp = GetSelfUri(serverConfiguration.SelfHost);
    
                var serviceRegistration = new AgentServiceRegistration
                {
                    Check = new AgentServiceCheck//健康检查
                    {
                        DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(60),
                        Interval = TimeSpan.FromSeconds(30),
                        HTTP = $"http://{localIp.Host}:{localIp.Port}/api/health",
                        Timeout = TimeSpan.FromSeconds(3)
                    },
                    ID = Guid.NewGuid().ToString("N"),
                    Name = serverConfiguration.ServerName,
                    Address = localIp.Host,
                    Port = localIp.Port,
                    Tags =
                        new[]
                        {
                            serverConfiguration.ServerName
                        }
                };
    
                return serviceRegistration;
            }

    添加健康检查接口

    与上述封装可以在同一个库,避免每个web服务都要写一个

    [Route("api/[Controller]")]
        public class HealthController : Controller
        {
            [HttpGet]
            public OkResult Get()
            {
                return Ok();
            }
        }

    在Startup.cs对Consul封装进行调用

    ConfigureServices

     public void ConfigureServices(IServiceCollection services)
     {
          services.AddOptions().AddConsul(option =>
          {
              option.WithHost(Configuration["ConsulConfiguration:Host"]);
          }).AddMvc();
     }

    Configure

    app.UseConsul(lifetime, option =>
    {
        option.WithSelfHost(Configuration["SelfHost"]);
        option.WithServerName(Configuration["ConsulConfiguration:ServerName"]);
    });

    K/V扩展

    只实现了put、get、delete,剩下可以自行按需添加

    public static class ConsulKyExtensions
        {
            public static async Task<bool> KvPutAsync(this ConsulClient consulClient, string key, string value)
            {
                var kvPair = new KVPair(key)
                {
                    Value = Encoding.UTF8.GetBytes(value)
                };
                var result = await consulClient.KV.Put(kvPair);
    
                if (result.StatusCode == HttpStatusCode.OK)
                    return result.Response;
    
                return false;
            }
    
            public static bool KvPut(this ConsulClient consulClient, string key, string value)
            {
                var kvPair = new KVPair(key)
                {
                    Value = Encoding.UTF8.GetBytes(value)
                };
                var result = consulClient.KV.Put(kvPair).ConfigureAwait(false).GetAwaiter().GetResult();
    
                if (result.StatusCode == HttpStatusCode.OK)
                    return result.Response;
    
                return false;
            }
    
            public static async Task<string> KvGetAsync(this ConsulClient consulClient, string key)
            {
                var result = await consulClient.KV.Get(key);
    
                return Encoding.UTF8.GetString(result.Response.Value);
            }
    
            public static string KvGet(this ConsulClient consulClient, string key)
            {
                var result = consulClient.KV.Get(key).ConfigureAwait(false).GetAwaiter().GetResult();
    
                return Encoding.UTF8.GetString(result.Response.Value);
            }
    
            public static async Task<bool> KvDeleteAsync(this ConsulClient consulClient, string key)
            {
                var result = await consulClient.KV.Delete(key);
    
                if (result.StatusCode == HttpStatusCode.OK)
                    return result.Response;
    
                return false;
            }
    
            public static bool KvDelete(this ConsulClient consulClient, string key)
            {
                var result = consulClient.KV.Delete(key).ConfigureAwait(false).GetAwaiter().GetResult();
    
                if (result.StatusCode == HttpStatusCode.OK)
                    return result.Response;
    
                return false;
            }
        }

    部署启动

    修改appsettings.json,填写目标consul地址和本服务地址

    {
      "Logging": {
        "IncludeScopes": false,
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "ConsulConfiguration": {
        "Host": "http://192.168.20.80:8500",
        "ServerName": "ConsulWebDemo",
        "Id": "20E2CFBB-95C0-496A-B70F-11111111"
      },
      "SelfHost": "http://localhost:1495/"
    }

    启动后,如果服务正常则可以显示下图效果。

  • 相关阅读:
    【数学】三分法
    【数学】【背包】【NOIP2018】P5020 货币系统
    【数学】【CF27E】 Number With The Given Amount Of Divisors
    【单调队列】【P3957】 跳房子
    【极值问题】【CF33C】 Wonderful Randomized Sum
    【DP】【CF31E】 TV Game
    【神仙题】【CF28D】 Don't fear, DravDe is kind
    【线段树】【CF19D】 Points
    【字符串】KMP字符串匹配
    【二维树状数组】【CF10D】 LCIS
  • 原文地址:https://www.cnblogs.com/skychen1218/p/9330870.html
Copyright © 2011-2022 走看看