net 6 使用 consul 做服务注册与服务发现(下)

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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用RestTemplate通过服务发现,基于注册中心完成远程调用时,可以按照以下流程进行操作: 1. 注册中心:启动一个注册中心,例如使用Eureka或Consul等。在注册中心上注册发现服务。 2. 服务提供者注册:将服务提供者注册注册中心,以便其他服务能够发现并调用该服务服务提供者需要在启动时向注册中心注册自己的服务信息,包括服务名称、IP地址、端口等。 3. 服务消费者发现:启动一个服务消费者应用程序,该应用程序需要从注册中心获取服务提供者的信息。在这个步骤中,通常会使用服务发现客户端库(例如Eureka Client或Consul Client)来与注册中心进行通信,获取可用的服务实例列表。 4. 远程调用:使用RestTemplate发送请求到服务提供者的实例。通过调用RestTemplate的方法(如`getForObject()`或`postForObject()`)来发起远程调用。在这一步骤中,需要指定要调用的服务名称和路径。 5. 负载均衡:通过负载均衡算法选择一个合适的服务提供者实例进行调用。负载均衡算法可以根据实际需求选择合适的算法,例如轮询、随机等。 6. 返回结果:服务提供者处理请求并返回响应结果。服务消费者接收到响应后,可以根据需要对结果进行处理或展示。 需要注意的是,以上流程是一个简化版本的远程调用流程,实际情况可能会因具体的注册中心和服务发现框架而有所不同。同时,使用RestTemplate进行远程调用已经被标记为过时,推荐使用Spring Cloud的WebClient或Feign等更为先进的方式进行远程调用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值