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/"
    }

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

  • 相关阅读:
    Tribonacci UVA 12470 (简单的斐波拉契数列)(矩阵快速幂)
    P1091 合唱队形
    P1481 魔族密码 (LIS)
    xiaowuga poj3735—Training little cats(特殊操作转化为矩阵操作)
    P2665 [USACO08FEB]连线游戏Game of Lines
    1875 丢手绢 (模拟+打表)
    Recurrences UVA 10870 (斐波拉契的一般形式推广)
    Choosing number ZOJ 3690 (矩阵快速幂)
    根据屏幕文件生成RPG代码的思路
    基于配置文件的查询,xml文件sample
  • 原文地址:https://www.cnblogs.com/skychen1218/p/9330870.html
Copyright © 2011-2022 走看看