使用Consul搭建负载均衡

发布时间 2023-09-24 18:34:58作者: 江渔湖

一、Consul服务注册发现

  1.启动Consul :consul agent -dev

    2.打开Consul地址,默认8500端口:8500

    3.封装静态类,注册Consul服务的方法:

    using Consul;
    using Microsoft.Extensions.Configuration;
    using System;


    public static class ConsulHelper
    {
      /// <summary>
      /// Consul注册
      /// </summary>
      /// <param name="configuration"></param>
      public static void ConsulRegist(this IConfiguration configuration)
      {
        ConsulClient client = new ConsulClient(c =>
        {
          c.Address = new Uri("http://localhost:8500/");
          c.Datacenter = "dc1";
        });//找到consul
        string ip = string.IsNullOrWhiteSpace(configuration["ip"]) ? "192.168.3.230" : configuration["ip"];
        int port = int.Parse(configuration["port"]);//命令行参数必须传入
        int weight = string.IsNullOrWhiteSpace(configuration["weight"]) ? 1 : int.Parse(configuration["weight"]);
        client.Agent.ServiceRegister(new AgentServiceRegistration()
        {
          ID = "service" + Guid.NewGuid(),//注册的服务ID
          Name = "TestService",//Group--分组
          Address = ip,//
          Port = port,//
          Tags = new string[] { weight.ToString() },//标签  每个服务所占的权重

 

          //设置健康检测,动态伸缩,当服务不可用时删掉该服务,服务可用增加
          Check = new AgentServiceCheck()
          {
            Interval = TimeSpan.FromSeconds(12),//间隔12s一次
            HTTP = $"http://{ip}:{port}/Api/Health/Index",//控制器
            Timeout = TimeSpan.FromSeconds(5),//检测等待时间
            DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(120)//失败后多久移除
          }
        });
        //命令行参数获取
        Console.WriteLine($"注册成功:{ip}:{port}--weight:{weight}");
      }
    }

  4.在Startup.cs文件或者Program.cs文件总注册服务:   

    //初始化一次
    app.Configuration.ConsulRegist();

  5.设置健康检测的控制服务  

    app.MapWhen(context => context.Request.Path.Equals("/Api/Health/Index"),
    applicationBuilder => applicationBuilder.Run(async context =>
    {
      Console.WriteLine($"This is Health Check");
      context.Response.StatusCode = (int)HttpStatusCode.OK;
      await context.Response.WriteAsync("OK");
    }));

 

二、前端服务的发现与调用

    private static int iIndex = 0;//暂不考虑线程安全

 

 

    #region Consul服务注册发现
    //consul获取服务--得知道Consul服务中的服务组名和API函数名
    string url = null;
    url = "http://ZhaoxiService/api/users/all";//Consul服务中的服务组名和API函数名

 

    ConsulClient client = new ConsulClient(c =>
    {
      c.Address = new Uri("http://localhost:8500/");
      c.Datacenter = "dc1";
    });//找到consul--像DNS
    var response = client.Agent.Services().Result.Response;//获取服务清单

 

 

    Uri uri = new Uri(url);
    string groupName = uri.Host;
    AgentService agentService = null;
    var dictionary = response.Where(s => s.Value.Service.Equals(groupName, StringComparison.OrdinalIgnoreCase)).ToArray();

    

    ////默认使用第一个注册的服务,无意义
    {
      //agentService = dictionary[0].Value;  
    }

 

    ////轮询策略 也是平均,但是太僵硬了
     {
      //agentService = dictionary[iIndex++ % dictionary.Length].Value;
    }

 

    ////平均策略--随机获取索引--相对就平均
    {
      //agentService = dictionary[new Random(iIndex++).Next(0, dictionary.Length)].Value;
    }

 

    //权重:3个实例能力不同,承担的压力也要不同
    {
      List<KeyValuePair<string, AgentService>> pairsList = new List<KeyValuePair<string, AgentService>>();
      foreach (var pair in dictionary)
      {
        int count = int.Parse(pair.Value.Tags?[0]);//1 5 10
         for (int i = 0; i < count; i++)
        {
          pairsList.Add(pair);
        }
      }
      //16个
      agentService = pairsList.ToArray()[new Random(iIndex++).Next(0, pairsList.Count())].Value;
    }

 


    url = $"{uri.Scheme}://{agentService.Address}:{agentService.Port}{uri.PathAndQuery}";
    string content = InvokeApi(url);
    base.ViewBag.Users = JsonConvert.DeserializeObject<IEnumerable<User>>(content);
    Console.WriteLine($"This is {url} Invoke");
    #endregion