在 C# 中使用 Consul 客户端库实现服务发现
在 C# 中使用 Consul 客户端库实现服务发现,主要通过查询 Consul 服务器获取指定服务的健康实例列表。以下是详细的实现步骤和代码示例:
实现步骤
-
安装 Consul 客户端库(已安装可跳过):
dotnet add package Consul
-
核心逻辑:
- 创建 Consul 客户端连接
- 调用 Consul API 查询指定服务的健康实例
- 处理返回结果,提取可用服务地址
完整代码实现
using Consul;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;/// <summary>
/// Consul 服务发现工具类
/// </summary>
public class ConsulServiceDiscoverer
{private readonly ConsulClient _consulClient;/// <summary>/// 初始化服务发现器/// </summary>/// <param name="consulServerAddresses">Consul 服务器地址列表(支持集群)</param>public ConsulServiceDiscoverer(params string[] consulServerAddresses){if (consulServerAddresses == null || !consulServerAddresses.Any()){// 默认连接本地 Consul 服务consulServerAddresses = new[] { "http://localhost:8500" };}_consulClient = new ConsulClient(config =>{config.Address = new Uri(consulServerAddresses.First());// 如需配置多个 Consul 服务器(高可用),可添加以下代码// config.SecondaryAddresses = consulServerAddresses.Skip(1).Select(uri => new Uri(uri)).ToList();});}/// <summary>/// 发现指定服务的所有健康实例/// </summary>/// <param name="serviceName">服务名称(必须与注册时一致)</param>/// <param name="tag">筛选标签(null 表示不筛选)</param>/// <returns>健康服务实例列表(地址+端口)</returns>public async Task<List<ServiceInstance>> DiscoverHealthyServicesAsync(string serviceName, string tag = null){try{// 调用 Consul API 查询健康服务实例var queryResult = await _consulClient.Health.Service(service: serviceName,tag: tag,passingOnly: true, // 只返回通过健康检查的实例queryOptions: new QueryOptions { WaitTime = TimeSpan.FromSeconds(10) });if (queryResult.Response == null || !queryResult.Response.Any()){throw new KeyNotFoundException($"未找到服务 {serviceName} 的健康实例");}// 转换为自定义服务实例对象return queryResult.Response.Select(s => new ServiceInstance{ServiceId = s.Service.ID,ServiceName = s.Service.Service,Address = s.Service.Address,Port = s.Service.Port,Tags = s.Service.Tags?.ToList() ?? new List<string>(),FullAddress = $"{s.Service.Address}:{s.Service.Port}"}).ToList();}catch (Exception ex){Console.WriteLine($"服务发现失败:{ex.Message}");throw;}}/// <summary>/// 从服务实例列表中随机选择一个(简单负载均衡)/// </summary>public ServiceInstance SelectRandomInstance(List<ServiceInstance> instances){if (instances == null || !instances.Any())return null;var random = new Random();return instances[random.Next(instances.Count)];}
}/// <summary>
/// 服务实例模型
/// </summary>
public class ServiceInstance
{public string ServiceId { get; set; } // 服务唯一IDpublic string ServiceName { get; set; } // 服务名称public string Address { get; set; } // 服务地址(IP或域名)public int Port { get; set; } // 服务端口public List<string> Tags { get; set; } // 服务标签(如版本、环境)public string FullAddress { get; set; } // 完整地址(地址:端口)
}
使用示例
// 1. 创建服务发现器(可指定多个 Consul 服务器地址)
var discoverer = new ConsulServiceDiscoverer("http://consul-server1:8500", "http://consul-server2:8500"
);// 2. 发现指定服务的健康实例(例如:发现支付服务)
var paymentServices = await discoverer.DiscoverHealthyServicesAsync("PaymentService");// 3. 从实例列表中选择一个进行调用(这里使用随机选择实现简单负载均衡)
var targetService = discoverer.SelectRandomInstance(paymentServices);if (targetService != null)
{Console.WriteLine($"选中的服务实例:{targetService.FullAddress}");// 4. 调用服务(示例:使用 HttpClient 调用)using (var httpClient = new HttpClient()){var response = await httpClient.GetAsync($"http://{targetService.FullAddress}/api/pay");var result = await response.Content.ReadAsStringAsync();Console.WriteLine($"服务响应:{result}");}
}
关键说明
-
健康实例筛选:
passingOnly: true
参数确保只返回通过健康检查的服务实例,避免调用故障节点。 -
高可用配置:通过传入多个 Consul 服务器地址,可实现客户端的高可用(当一个服务器不可用时自动切换到其他服务器)。
-
负载均衡:示例中使用了简单的随机选择策略,实际项目中可根据需求实现轮询、权重、哈希等更复杂的负载均衡算法。
-
服务标签:可通过
tag
参数筛选特定标签的服务实例(例如:只发现version=v2
的服务)。 -
异常处理:代码包含了异常捕获逻辑,可根据实际需求扩展(如重试机制、降级策略等)。
通过这种方式,C# 应用可以动态发现并调用 Consul 中注册的服务,适配服务的动态扩缩容和故障转移场景。
相关代码
consul.demo资源-CSDN下载