.NET Core Consul服务发现
2024-09-08
15
.NET Core Consul服务注册 一文中讲述了安装Consul,注册服务。
本文讲述在.NET Core项目中的Consul服务发现。和注册一样,为了复用还是新建一个类库。
首先我们还是启动3个AspNetCore服务,注册到Consul,如何注册可以看.NET Core Consul服务注册一文中的介绍。
启动好以后在Consul的监视界面localhost:8500中可以看到3个服务了,如图所示
接下来开始在ConsulServiceDiscovery类库项目中编写代码。
服务提供IServiceProvider接口和ConsulServiceProvider类代码
namespace ConsulServiceDiscovery
{
public interface IServiceProvider
{
Task<IList<string>> GetServicesAsync(string serviceName);
}
}
namespace ConsulServiceDiscovery
{
public class ConsulServiceProvider : IServiceProvider
{
private readonly ConsulClient _consulClient;
public ConsulServiceProvider(Uri uri) {
_consulClient = new ConsulClient(consulConfig =>
{
consulConfig.Address = uri;
});
}
public async Task<IList<string>> GetServicesAsync(string serviceName)
{
// Health 当前consul里已注册的服务,健康检查的信息也拿过来
var queryResult = await _consulClient.Health.Service(serviceName, string.Empty, true);
var result = new List<string>();
foreach (var item in queryResult.Response) {
result.Add($"{item.Service.Address}:{item.Service.Port}");
}
return result;
}
}
}
服务创建IServiceBuilder接口和ServiceBuilder类代码
namespace ConsulServiceDiscovery.Builder
{
public interface IServiceBuilder
{
/// <summary>
/// 服务提供者
/// </summary>
IServiceProvider ServiceProvider { get; set; }
/// <summary>
/// 服务名称
/// </summary>
string ServiceName { get; set; }
/// <summary>
/// Uri方案
/// </summary>
string UriScheme { get; set; }
/// <summary>
/// 使用哪种策略
/// </summary>
ILoadBalancer LoadBalancer { get; set; }
Task<Uri> BuildAsync(string path);
}
}
namespace ConsulServiceDiscovery.Builder
{
public class ServiceBuilder : IServiceBuilder
{
public IServiceProvider ServiceProvider { get; set; }
public string ServiceName { get; set; }
public string UriScheme { get; set; }
public ILoadBalancer LoadBalancer { get; set; }
public ServiceBuilder(IServiceProvider serviceProvider) {
ServiceProvider = serviceProvider;
}
public async Task<Uri> BuildAsync(string path)
{
var serviceList = await ServiceProvider.GetServicesAsync(ServiceName);
var service = LoadBalancer.Resolve(serviceList);
var baseUri = new Uri($"{UriScheme}://{service}");
var uri = new Uri(baseUri, path);
return uri;
}
}
}
负载方式,这里列举随机和轮询两种负载方式,ILoadBalancer接口,RandomLoadBalancer实现类,RoundRobinLoadBalancer实现类,TypeLoadBalancer静态类代码
namespace ConsulServiceDiscovery.LoadBalancer
{
public interface ILoadBalancer
{
string Resolve(IList<string> services);
}
}
namespace ConsulServiceDiscovery.LoadBalancer
{
public class RandomLoadBalancer : ILoadBalancer
{
private readonly Random _random = new Random();
public string Resolve(IList<string> services)
{
var index = _random.Next(services.Count);
return services[index];
}
}
}
namespace ConsulServiceDiscovery.LoadBalancer
{
public class RoundRobinLoadBalancer : ILoadBalancer
{
private readonly object _lock = new object();
private int _index = 0;
public string Resolve(IList<string> services)
{
lock (_lock) {
if (_index >= services.Count) {
_index = 0;
}
return services[_index++];
}
}
}
}
namespace ConsulServiceDiscovery.LoadBalancer
{
public static class TypeLoadBalancer
{
// 单例
public static ILoadBalancer RandomLoad = new RandomLoadBalancer();
public static ILoadBalancer RoundRobinLoad = new RoundRobinLoadBalancer();
}
}
扩展方法创建ServiceBuilder
namespace ConsulServiceDiscovery
{
public static class ServiceProviderExtension
{
public static IServiceBuilder CreateServiceBuilder(this IServiceProvider serviceProvider, Action<IServiceBuilder> config) {
var builder = new ServiceBuilder(serviceProvider);
config(builder);
return builder;
}
}
}
这样,服务发现的代码就完成了。
下面是调用测试代码,创建一个控制台项目,在Program.cs里使用轮询的方式代码如下
namespace ConsulTest
{
class Program
{
static void Main(string[] args)
{
var serviceProvider = new ConsulServiceProvider(new Uri("http://localhost:8500"));
var aspNetCoreService = serviceProvider.CreateServiceBuilder(builder => {
builder.ServiceName = "AspNetCore";
builder.LoadBalancer = TypeLoadBalancer.RoundRobinLoad;//可选RandomLoad
builder.UriScheme = Uri.UriSchemeHttp;
});
var httpClient = new HttpClient();
for (int i = 0; i < 100; i++) {
Console.WriteLine($"----------第{i}次请求-----------");
try
{
var uri = aspNetCoreService.BuildAsync("/Health").Result;
Console.WriteLine($"{DateTime.Now} - 正在调用:{uri}");
var content = httpClient.GetStringAsync(uri).Result;
Console.WriteLine($"返回结果:{content}");
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
Task.Delay(500).Wait();
}
Console.ReadLine();
}
}
}
执行效果
可以看到,轮询方式会轮流请求1234,1235,1236端口的三个服务地址。
更新于:8天前赞一波!
相关文章
- 2023年.NET常见面试题和答案
- 企业项目选择.NET6还是.NET8?
- 本机AOT与ASP.NET Core配合使用的优势
- .Net8 AOT有什么新特性
- 什么是.NET全家桶?
- .NET性能分析工具MiniProfiler使用示例
- .NET中运行Java代码
- .NET Core判断发起请求的设备
- .NET8 IExceptionHandler用法
- 使用IKVM.NET在.NET中运行Java代码
- .NET Core判断浏览器类型
- .NET官方日志库Microsoft.Extensions.Logging用法
- .NET MVC和Razor Page对比
- .NET图像处理库ImageSharp使用示例
- .NET MQTT框架MQTTnet使用方法
- .NET邮件发送开源库FluentEmail
- .NET8拦截器Interceptors用法
- .NET JWT库的使用示例
- .NET中Task和ValueTask的区别
- .Net测试模拟库FakeItEasy用法示例
文章评论
全部评论