在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 与控制台几乎同时更新