排名
6
文章
6
粉丝
16
评论
8
{{item.articleTitle}}
{{item.blogName}} : {{item.content}}
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2024TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术
分类:
.net core
前言
在consul 服务已经准备好的情况下,如何在代码中获取指定服务
服务发现
首先在代码中同样需要引入 consul 的nuget 包
我提供一个获取服务的接口IServiceHelper
public interface IServiceHelper { /// <summary> /// 获取订单数据 /// </summary> /// <returns></returns> Task<string> GetOrder(); }
代码实现为,这里我指定了获取 服务下 orders 控制器下的get 方法。可以根据自己代码替换成自己的api 路径
public class ServiceHelper: IServiceHelper { private readonly IConfiguration _configuration; public ServiceHelper(IConfiguration configuration) { _configuration = configuration; } public async Task<string> GetOrder() { var consulClient = new ConsulClient(c => { //consul地址 c.Address = new Uri(_configuration["ConsulSetting:ConsulAddress"]); }); //获取健康的服务 var services = consulClient.Health.Service("OrderService", null, true, null).Result.Response; //地址列表组装 string[] serviceUrls = services.Select(p => $"http://{p.Service.Address + ":" + p.Service.Port}").ToArray(); if (!serviceUrls.Any()) { return await Task.FromResult("【订单服务】服务列表为空"); } //每次随机访问一个服务实例 var Client = new RestClient(serviceUrls[new Random().Next(0, serviceUrls.Length)]); var request = new RestRequest("/orders", Method.Get); var response = await Client.ExecuteAsync(request); return response.Content; } }
appsettings.json如下(地址替换成自己的)
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "ConsulSetting": { "ConsulAddress": "http://192.168.1.3:8500" } }
接下来我使用该接接口,获取consul 中的服务 ,并获取到指定api 返回的值
private readonly ILogger<HomeController> _logger; private readonly IServiceHelper _serviceHelper; public HomeController(ILogger<HomeController> logger, IServiceHelper serviceHelper) { _logger = logger; _serviceHelper = serviceHelper; } public async Task<IActionResult> Index() { ViewBag.OrderData = await _serviceHelper.GetOrder(); return View(); }
前端是这样
<div class="text-center"> <h1 class="display-4">Welcome</h1> <p> @ViewBag.OrderData </p> </div>
现在来运行看一下,下边端口在不停变换,那么证明,随机访问端口成功,也正确获取到了consul 中的服务
这样虽然成功了,但是新的问题又出现了,在我请求一个接口时,我都会先去consul 获取请求地址,然后再发送请求,这样请求就变得啰嗦了,而且增加了请求耗时
可以使用Consul提供的解决方案:——Blocking Queries (阻塞的请求)
在接口中新增一个服务列表的方法
public interface IServiceHelper { /// <summary> /// 获取订单数据 /// </summary> /// <returns></returns> Task<string> GetOrder(); /// <summary> /// 获取服务列表 /// </summary> void GetServices(); }
实现如下,GetService 方法主要就是实现,将服务地址放进一个数组中,当consul 的版本号发生变化,那么才会重新到consul 去取一次健康的地址,这样大大的避免了每个请求都会先去consul 找地址
public class ServiceHelper: IServiceHelper { private readonly IConfiguration _configuration; private readonly ConsulClient _consulClient; private ConcurrentBag<string> _orderServiceUrls; public ServiceHelper(IConfiguration configuration) { _configuration = configuration; _consulClient = new ConsulClient(c => { //consul地址 c.Address = new Uri(_configuration["ConsulSetting:ConsulAddress"]); }); } public async Task<string> GetOrder() { if (_productServiceUrls == null) return await Task.FromResult("【订单服务】正在初始化服务列表..."); //每次随机访问一个服务实例(从_orderServiceUrls 中获取) var Client = new RestClient(_orderServiceUrls.ElementAt(new Random().Next(0, _orderServiceUrls.Count()))); var request = new RestRequest("/orders", Method.Get); var response = await Client.ExecuteAsync(request); return response.Content; } public void GetServices() { var serviceNames = new string[] { "OrderService" }; Array.ForEach(serviceNames, p => { Task.Run(() => { //WaitTime默认为5分钟 var queryOptions = new QueryOptions { WaitTime = TimeSpan.FromMinutes(10) }; while (true) { GetServices(queryOptions, p); } }); }); } private void GetServices(QueryOptions queryOptions, string serviceName) { var res = _consulClient.Health.Service(serviceName, null, true, queryOptions).Result; //控制台打印一下获取服务列表的响应时间等信息 Console.WriteLine($"{DateTime.Now}获取{serviceName}:queryOptions.WaitIndex:{queryOptions.WaitIndex} LastIndex:{res.LastIndex}"); //版本号不一致 说明服务列表发生了变化 if (queryOptions.WaitIndex != res.LastIndex) { queryOptions.WaitIndex = res.LastIndex; //服务地址列表 var serviceUrls = res.Response.Select(p => $"http://{p.Service.Address + ":" + p.Service.Port}").ToArray(); if (serviceName == "OrderService") _orderServiceUrls = new ConcurrentBag<string>(serviceUrls); } } }
然后再在管道中初始化一下,第一次的请求列表
接下来运行再试试,发现快了很多
现在我来停止一个服务试试,发现cunsul 与控制台几乎同时更新
这就是consul 的服务发现,
评价