在 C# 中使用 Consul 客户端库实现服务发现

在 C# 中使用 Consul 客户端库实现服务发现,主要通过查询 Consul 服务器获取指定服务的健康实例列表。以下是详细的实现步骤和代码示例:

实现步骤

  1. 安装 Consul 客户端库(已安装可跳过):

    复制代码
    dotnet add package Consul
  2. 核心逻辑

    • 创建 Consul 客户端连接
    • 调用 Consul API 查询指定服务的健康实例
    • 处理返回结果,提取可用服务地址

完整代码实现

cs 复制代码
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; }       // 服务唯一ID
    public 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}");
    }
}

关键说明

  1. 健康实例筛选passingOnly: true 参数确保只返回通过健康检查的服务实例,避免调用故障节点。

  2. 高可用配置:通过传入多个 Consul 服务器地址,可实现客户端的高可用(当一个服务器不可用时自动切换到其他服务器)。

  3. 负载均衡:示例中使用了简单的随机选择策略,实际项目中可根据需求实现轮询、权重、哈希等更复杂的负载均衡算法。

  4. 服务标签 :可通过 tag 参数筛选特定标签的服务实例(例如:只发现 version=v2 的服务)。

  5. 异常处理:代码包含了异常捕获逻辑,可根据实际需求扩展(如重试机制、降级策略等)。

通过这种方式,C# 应用可以动态发现并调用 Consul 中注册的服务,适配服务的动态扩缩容和故障转移场景。

相关代码

consul.demo资源-CSDN下载

相关推荐
熙客2 天前
SpringCloud概述
java·spring cloud·微服务
阿里云云原生3 天前
HiMarket 正式开源,为企业落地开箱即用的 AI 开放平台
微服务
眠りたいです3 天前
基于脚手架微服务的视频点播系统-数据管理与网络通信部分的预备工作
c++·qt·ui·微服务·云原生·架构·媒体
码农小伙3 天前
单体到微服务拆分方案
微服务·架构
mask哥4 天前
详解mcp以及agen架构设计与实现
java·微服务·flink·大模型·ai agent·springai·mcp
好多174 天前
《微服务事务管理》
java·微服务·架构
hzzzzzo04 天前
微服务保护全攻略:从雪崩到 Sentinel 实战
数据库·微服务·sentinel
APItesterCris5 天前
构建分布式京东商品数据采集系统:基于 API 的微服务实现方案
分布式·微服务·架构
hzzzzzo05 天前
微服务网关全解析:从入门到实践
java·开发语言·微服务
Angelyb5 天前
微服务保护和分布式事务
java·微服务·架构