Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。 Consul是分布式的、高可用的、可横向扩展的。它具备以下特性 :
服务发现:consul通过DNS或者HTTP接口使服务注册和服务发现变的很容易,一些外部服务,例如saas提供的也可以一样注册。
健康检查:健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。
键/值存储:一个用来存储动态配置的系统。提供简单的HTTP接口,可以在任何地方操作。
多数据中心:无需复杂的配置,即可支持任意数量的区域。
Install | Consul | HashiCorp DeveloperExplore Consul product documentation, tutorials, and examples.https://developer.hashicorp.com/consul/downloads
下载完成后目录下cmd运行 consul agent -dev 启动consul
启动成功后可见可见客户端本地端口 8500,去浏览器访问 http://127.0.0.1:8500
可见已经有一个服务,那是consul自己的服务。如何启用自己的服务,需要结合代码在程序启动时注册(net6)
在微服务实例项目中执行一下步骤
一、Nuget添加 Consul 包
二、新建辅助类
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";
});
string ip = string.IsNullOrWhiteSpace(configuration["ip"]) ? "127.0.0.1" : 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(),//唯一
Name = "MyService",//组名称-Group
Address = ip,//其实应该写ip地址
Port = port,//不同实例
Tags = new string[] { weight.ToString() },//标签,权重策略
Check = new AgentServiceCheck()//心跳检测
{
Interval = TimeSpan.FromSeconds(12),//间隔12s一次
HTTP = $"http://{ip}:{port}/Api/User/Index",
Timeout = TimeSpan.FromSeconds(5),//检测等待时间
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(20)//失败后多久移除
}
});
//命令行参数获取
Console.WriteLine($"{ip}:{port}--weight:{weight}");
}
}
三、在program.cs添加代码,最好是放在var app = builder.Build();上面
builder.Configuration.ConsulRegist();
四、添加心跳回执检测接口,与心跳检测出代码
HTTP = $"http://{ip}:{port}/Api/User/Index",
对应,没有他心跳检测会失败,consul会主动退出服务
[HttpGet]
[Route("Index")]
public ActionResult Index()
{
return Ok();
}
启动多个微服务实例,命令
dotnet run --urls="http://*:5726" --ip=127.0.0.1 --port=5726 --weight=1
dotnet run --urls="http://*:5727" --ip=127.0.0.1 --port=5727 --weight=2
dotnet run --urls="http://*:5728" --ip=127.0.0.1 --port=5728 --weight=5
再去consul客户端查看,可以看出多了三个服务实例
服务注册弄好了,怎么调用实现负载均衡
在微服务客户端项目中执行一下步骤
一、nuget下载包 Consul
二、调用,仅作实例,实际运用可能需要修改或封装参数
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
private readonly ILogger<UserController> _logger;
private readonly RequestHelper _request = null;
public UserController(ILogger<UserController> logger, RequestHelper request)
{
_logger = logger;
_request = request;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("Get")]
public async Task<string> Get()
{
简单分布式
//var url = $"http://localhost:5726/api/User/All";
//return await _request.HttpGet(url);
负载均衡,有nginx解决
//var url = $"http://localhost:8080/api/User/All";
//return await _request.HttpGet(url);
#region Consul
//相对Nginx好像变麻烦了,需要手动写代码实现负载均衡
//可以靠网关或者手动封装就好
ConsulClient client = new ConsulClient(c =>
{
c.Address = new Uri("http://127.0.0.1:8500/");
c.Datacenter = "dc1";
});
var response = client.Agent.Services().Result.Response;
//有了consul 程序需要知道哪些信息,才能调用服务?
string url = null;
url = "http://MyService/api/user/all";//consul提供的是ip+port
Uri uri = new Uri(url);
string groupName = uri.Host;
AgentService agentService = null;
var serviceDictionary = response.Where(s => s.Value.Service.Equals(groupName, StringComparison.OrdinalIgnoreCase)).ToArray();//找到的全部服务--4个
{
agentService = serviceDictionary[0].Value;//直接拿的第一个
//这里有三个服务或者服务实例,只需要选择一个调用,那么这个选择的方案,就叫 负载均衡策略
}
//{
// //轮询策略 也是平均,但是太僵硬了
// agentService = serviceDictionary[iIndex++ % serviceDictionary.Length].Value;
//}
//{
// //平均策略--随机获取索引--相对就平均
// agentService = serviceDictionary[new Random(iIndex++).Next(0, serviceDictionary.Length)].Value;
//}
//{
// //权重策略--能给不同的实例分配不同的压力---注册时提供权重
// List<KeyValuePair<string, AgentService>> pairsList = new List<KeyValuePair<string, AgentService>>();
// foreach (var pair in serviceDictionary)
// {
// 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}";
Console.WriteLine($"This is {url} Invoke");
return await _request.HttpGet(url);
#endregion
}
//private static int iIndex = 0;//暂不考虑线程安全
}
运行当前客户端项目
成功访问