.NET Core Consul

隨着微服務的流行,為微服務提供支持的各種組件也日益豐富,而Consul就是其中一款常用的服務註冊和發現工具。.NET Core Consul是一套基於.NET Core的API,提供了對Consul註冊中心的簡便訪問,使用.NET Core Consul可以輕鬆地實現服務的註冊、發現和負載均衡等操作。

一、Consul基礎概念介紹

在使用.NET Core Consul前,先對Consul的基礎概念做簡單介紹:

  • 服務註冊:在Consul上註冊服務,Consul會使用心跳機制檢查服務是否健康。
  • 服務發現:通過Consul的服務發現功能,可以實現輕鬆發現和訪問已註冊的服務。
  • 健康檢查:在服務註冊時需要提供服務的健康檢查地址,Consul會通過該地址定時發送檢查請求,以檢查服務的健康狀況。
  • 分布式鎖:Consul提供了分布式鎖,用於處理在分布式環境下的並發操作。
  • 事件處理:Consul提供了事件處理機制,可以在特定的事件觸發時執行預定的操作。

二、與.NET Core集成

使用.NET Core Consul需要先安裝其依賴包——ConsulSharp。

dotnet add package ConsulSharp

然後在Startup.cs文件中進行配置:

services.AddSingleton<ConsulService>();
services.Configure<ConsulConfig>(Configuration.GetSection("ConsulConfig"));

這其中,ConsulConfig用於配置Consul的相關參數,可以在appsettings.json文件中定義:

{
  "ConsulConfig": {
    "Address": "http://localhost:8500",
    "Datacenter": "dc1",
    "Token": ""
  }
}

三、服務註冊

首先定義一個用於服務註冊的接口:

public interface IServiceRegistry
{
    Task<bool> RegisterService(ServiceRegistration registration);
}

其中,ServiceRegistration就是服務註冊的相關信息,包括服務名稱、IP、端口、健康檢查地址等。下面是IServiceRegistry的具體實現:

public class ConsulServiceRegistry : IServiceRegistry
{
    private readonly IConsulClient _consul;
    private readonly ConsulConfig _consulConfig;

    public ConsulServiceRegistry(IOptions<ConsulConfig> consulConfig, IConsulClient consul)
    {
        _consul = consul;
        _consulConfig = consulConfig.Value;
    }

    public async Task<bool> RegisterService(ServiceRegistration registration)
    {
        var registrationRequest = new AgentServiceRegistration
        {
            Name = registration.Name,
            ID = registration.ID,
            Address = registration.Address,
            Port = registration.Port,
            Check = new AgentServiceCheck
            {
                HTTP = registration.HealthCheckURL,
                Interval = TimeSpan.FromSeconds(registration.HealthCheckIntervalSeconds),
                Timeout = TimeSpan.FromSeconds(registration.HealthCheckTimeoutSeconds)
            }
        };
        var result = await _consul.Agent.ServiceRegister(registrationRequest);
        return result.StatusCode == HttpStatusCode.OK;
    }
}

使用IServiceRegistry進行服務註冊:

var registration = new ServiceRegistration
{
    Name = "serviceName",
    ID = "serviceId",
    Address = "localhost",
    Port = 5000,
    HealthCheckIntervalSeconds = 10,
    HealthCheckTimeoutSeconds = 5,
    HealthCheckURL = "http://localhost:5000/health"
};
await _serviceRegistry.RegisterService(registration);

四、服務發現

Consul提供三種服務發現機制:DNS、HTTP和gRPC,其中HTTP方式最為常用,下面以此為例講解。

定義IServiceDiscovery接口:

public interface IServiceDiscovery
{
    Task<List<Uri>> DiscoverServiceUri(string serviceName);
}

ConsulServiceDiscovery的實現:

public class ConsulServiceDiscovery : IServiceDiscovery
{
    private readonly IConsulClient _consul;
    private readonly ConsulConfig _consulConfig;

    public ConsulServiceDiscovery(IOptions<ConsulConfig> consulConfig, IConsulClient consul)
    {
        _consul = consul;
        _consulConfig = consulConfig.Value;
    }

    public async Task<List<Uri>> DiscoverServiceUri(string serviceName)
    {
        var queryResult = await _consul.Catalog.Service(serviceName);
        return queryResult.Response.Select(service => new Uri($"http://{service.ServiceAddress}:{service.ServicePort}/")).ToList();
    }
}

使用IServiceDiscovery進行服務發現:

var serviceUris = await _serviceDiscovery.DiscoverServiceUri("serviceName");

五、負載均衡

對於服務集群,常常需要進行負載均衡,.NET Core Consul提供了兩種負載均衡方式:隨機模式和輪詢模式。

定義IServiceLoadBalancer接口:

public interface IServiceLoadBalancer
{
    Task<Uri> ChooseServer(List<Uri> servers);
}

ConsulServiceLoadBalancer的實現:

public class ConsulServiceLoadBalancer : IServiceLoadBalancer
{
    private readonly ConcurrentDictionary<string, int> _indexDictionary = new ConcurrentDictionary<string, int>();

    public async Task<Uri> ChooseServer(List<Uri> servers)
    {
        var serviceName = servers.First().AbsolutePath.Split('/')[1];
        var index = _indexDictionary.AddOrUpdate(serviceName, 0, (_, i) => (i + 1) % servers.Count);
        return servers[index];
    }
}

使用IServiceLoadBalancer進行負載均衡:

var chosenServer = await _serviceLoadBalancer.ChooseServer(serviceUris);

六、完整示例代碼

以下是一個演示.NET Core Consul的完整示例代碼:

using Consul;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;

namespace Sample
{
    public class ConsulServiceRegistry : IServiceRegistry
    {
        private readonly IConsulClient _consul;
        private readonly ConsulConfig _consulConfig;

        public ConsulServiceRegistry(IOptions<ConsulConfig> consulConfig, IConsulClient consul)
        {
            _consul = consul;
            _consulConfig = consulConfig.Value;
        }

        public async Task<bool> RegisterService(ServiceRegistration registration)
        {
            var registrationRequest = new AgentServiceRegistration
            {
                Name = registration.Name,
                ID = registration.ID,
                Address = registration.Address,
                Port = registration.Port,
                Check = new AgentServiceCheck
                {
                    HTTP = registration.HealthCheckURL,
                    Interval = TimeSpan.FromSeconds(registration.HealthCheckIntervalSeconds),
                    Timeout = TimeSpan.FromSeconds(registration.HealthCheckTimeoutSeconds)
                }
            };
            var result = await _consul.Agent.ServiceRegister(registrationRequest);
            return result.StatusCode == HttpStatusCode.OK;
        }
    }

    public class ConsulServiceDiscovery : IServiceDiscovery
    {
        private readonly IConsulClient _consul;
        private readonly ConsulConfig _consulConfig;

        public ConsulServiceDiscovery(IOptions<ConsulConfig> consulConfig, IConsulClient consul)
        {
            _consul = consul;
            _consulConfig = consulConfig.Value;
        }

        public async Task<List<Uri>> DiscoverServiceUri(string serviceName)
        {
            var queryResult = await _consul.Catalog.Service(serviceName);
            return queryResult.Response.Select(service => new Uri($"http://{service.ServiceAddress}:{service.ServicePort}/")).ToList();
        }
    }

    public class ConsulServiceLoadBalancer : IServiceLoadBalancer
    {
        private readonly ConcurrentDictionary<string, int> _indexDictionary = new ConcurrentDictionary<string, int>();

        public async Task<Uri> ChooseServer(List<Uri> servers)
        {
            var serviceName = servers.First().AbsolutePath.Split('/')[1];
            var index = _indexDictionary.AddOrUpdate(serviceName, 0, (_, i) => (i + 1) % servers.Count);
            return servers[index];
        }
    }

    public interface IServiceRegistry
    {
        Task<bool> RegisterService(ServiceRegistration registration);
    }

    public interface IServiceDiscovery
    {
        Task<List<Uri>> DiscoverServiceUri(string serviceName);
    }

    public interface IServiceLoadBalancer
    {
        Task<Uri> ChooseServer(List<Uri> servers);
    }

    public class ServiceRegistration
    {
        public string ID { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        public int Port { get; set; }
        public string HealthCheckURL { get; set; }
        public int HealthCheckIntervalSeconds { get; set; } = 10;
        public int HealthCheckTimeoutSeconds { get; set; } = 5;
    }

    public class ConsulConfig
    {
        public string Address { get; set; }
        public string Datacenter { get; set; }
        public string Token { get; set; }
    }

    public class ConsulService
    {
        private readonly IServiceRegistry _serviceRegistry;
        private readonly IServiceDiscovery _serviceDiscovery;
        private readonly IServiceLoadBalancer _serviceLoadBalancer;

        public ConsulService(IServiceRegistry serviceRegistry, IServiceDiscovery serviceDiscovery, IServiceLoadBalancer serviceLoadBalancer)
        {
            _serviceRegistry = serviceRegistry;
            _serviceDiscovery = serviceDiscovery;
            _serviceLoadBalancer = serviceLoadBalancer;
        }

        public async Task RegisterService(ServiceRegistration registration)
        {
            await _serviceRegistry.RegisterService(registration);
        }

        public async Task<Uri> GetServiceUri(string serviceName)
        {
            var serviceUris = await _serviceDiscovery.DiscoverServiceUri(serviceName);
            var chosenServer = await _serviceLoadBalancer.ChooseServer(serviceUris);
            return chosenServer;
        }
    }

    class Program
    {
        static async Task Main(string[] args)
        {
            var consulConfig = new ConsulConfig
            {
                Address = "http://localhost:8500",
                Datacenter = "dc1",
                Token = ""
            };

            using var consul = new ConsulClient(config =>
            {
                config.Address = new Uri(consulConfig.Address);
            });

            var serviceRegistry = new ConsulServiceRegistry(Options.Create(consulConfig), consul);
            var serviceDiscovery = new ConsulServiceDiscovery(Options.Create(consulConfig), consul);
            var serviceLoadBalancer = new ConsulServiceLoadBalancer();

            var consulService = new ConsulService(serviceRegistry, serviceDiscovery, serviceLoadBalancer);

            var registration = new ServiceRegistration
            {
                Name = "serviceName",
                ID = "serviceId",
                Address = "localhost",
                Port = 5000,
                HealthCheckIntervalSeconds = 10,
                HealthCheckTimeoutSeconds = 5,
                HealthCheckURL = "http://localhost:5000/health"
            };
            await consulService.RegisterService(registration);

            var serviceUri = await consulService.GetServiceUri("serviceName");
            Console.WriteLine(serviceUri);
        }
    }
}

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/305097.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2025-01-01 11:06
下一篇 2025-01-01 11:06

相關推薦

  • 解決.net 6.0運行閃退的方法

    如果你正在使用.net 6.0開發應用程序,可能會遇到程序閃退的情況。這篇文章將從多個方面為你解決這個問題。 一、代碼問題 代碼問題是導致.net 6.0程序閃退的主要原因之一。首…

    編程 2025-04-29
  • MyBatis.NET

    MyBatis.NET是一個優秀的.NET ORM框架,它將對象映射成為數據庫中的記錄,不需要編寫SQL語句,並具有良好的性能和靈活性。 一、簡介 MyBatis.NET集成了面向…

    編程 2025-04-23
  • system.net.webexception異常詳解

    一、webException的概念 System.Net.WebException類表示的是發生與http協議相關的錯誤時.NET Framework的異常。在.NET編程中,we…

    編程 2025-04-23
  • Windows10無法安裝.NET Framework 3.5 & 2.0 & 3.0

    在Windows10中安裝.NET Framework 3.5、2.0和3.0時,您可能會遇到一些問題,例如無法安裝或安裝過程中出現錯誤。以下內容將從幾個方面來詳細闡述這些問題。 …

    編程 2025-04-23
  • ZZZJST.NET:一個全面的編程學習平台

    一、簡介 www.zzzjst.net是一個全能編程開發工程師的學習平台。它提供高質量的編程課程,為技術人員和程序員開展技術能力的提升提供了不可替代的資源。 該網站以前端技術、後端…

    編程 2025-04-23
  • .NET框架:微軟推出的跨平台編程框架

    一、介紹 Microsoft .NET Framework(簡稱.NET)是由微軟公司一個跨平台的開發框架,它支持多種操作系統和開發語言,為創建面向 Windows 和 Web 的…

    編程 2025-04-22
  • Ubuntu安裝Net-tools詳解

    一、Net-tools介紹 Net-tools是一個Linux下常用的網絡工具集,包含了一系列用來管理和診斷網絡的應用程序,如ifconfig、route、arp、netstat等…

    編程 2025-04-02
  • Java.net詳解

    Java.net是Java平台提供的用於網絡編程的API集合。它提供了在Java應用程序中實現網絡連接和通信所需的基本組件和類。Java.net包含了一系列類,如Socket、Se…

    編程 2025-02-25
  • .NET 5.0詳解

    一、新特性 .NET 5.0是微軟推出的一個全新版本的.NET Framework,該版本在各個方面都有着令人驚喜的增強和改進。本章我們將討論.NET 5.0的新功能和特性,讓您對…

    編程 2025-02-17
  • Corei312100還值得入手嗎

    前幾個月,紅米發布了一款499元的智能手機在坊間引發熱議,各種質疑嘲笑之聲不絕於耳。事實上,用戶的需求是多層次立體的,並非所有的手機都都是用來當主力機的,拿來接電話,聽音樂,聽評書…

    2025-02-11

發表回復

登錄後才能評論