Consul作用;
1.服务注册发现
2.服务健康检查
3.负载均衡
使用步骤:
1.下载并解压(得到一个exe文件)
2.在解压目录,cmd,使用命令 Consul.exe agent -dev
这样便启动了Consul服务,打开浏览器输入localhost:8500 (默认端口8500)
那么,怎么注册发现服务呢。需要在要调用的服务里面注册Consul的地址,并告知Consul自己的ip,端口号,服务名等(需要支持命令行参数)
代码如下:
public static void ConsulRegister(this IConfiguration configuration) { ConsulClient client = new ConsulClient(c => { c.Address = new Uri("http://localhost:8500/"); c.Datacenter = "dcl"; }); string ip = 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 = "AduService", 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(20) //失败后多久移除 } }); Console.WriteLine($"{ip}:{port}--weight:{weight}"); }
这些参数都是可以自定义的,要引用包Consul,
Consul地址也不一定要8500,
有一点需要注意,必须添加HealthController!写什么都好,不然Consul检查不到这些服务(困扰了我几天,噗)
代码加上
private readonly ILogger<HealthController> _logger; private readonly IConfiguration _configuration; public HealthController(ILogger<HealthController> logger, IConfiguration configuration) { _logger = logger; _configuration = configuration; } [HttpGet] [Route("Index")] public IActionResult Index() { _logger.LogWarning($"This is HealthController {_configuration["port"]}"); return Ok(); }
注意,需要在服务的StartUp.cs中的Configure方法中注册:
#region 注册Consul this.Configuration.ConsulRegister(); //启动时注册,且只注册一次 #endregion
在主项目中调用:
string url = "http://AduService/api/user/all"; ConsulClient client = new ConsulClient(c => { c.Address = new Uri("http://localhost:8500/"); c.Datacenter = "dcl"; });
var response = client.Agent.Services().Result.Response;
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(); agentService = serviceDictionary[0].Value; url = $"{uri.Scheme}://{agentService.Address}:{agentService.Port}{uri.PathAndQuery}";
通过向Consul的服务地址发送请求,遍历服务,找到和AduService同名的服务下面的实例,获取url,然后获取数据
上述代码是默认请求第一个服务实例。这显然不够,我想要动态改变请求实例,并按照权重的形式来访问》
需要将上面的
agentService = serviceDictionary[0].Value;
修改一下:
//权重,不同服务器的处理能力不同 List<KeyValuePair<string,AgentService >> pairsList = new List<KeyValuePair<string,AgentService>>(); foreach(var pair in serviceDictionary) { int count = int.Parse(pair.Value.Tags?[0]); for(int i = 0; i < count; i++) { pairsList.Add(pair); } } agentService = pairsList.ToArray()[new Random(iIndex++).Next(0, pairsList.Count())].Value;
其中iIndex是声明的全局变量:
private static int iIndex = 0;