热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Consul学习笔记—服务发现

前言:上一篇文章简单实用Consul试下服务注册,本篇继续学习Consul中的另外特性:服


前言:

  上一篇文章简单实用Consul试下服务注册,本篇继续学习Consul中的另外特性:服务发现、KV操作 ;以及对上篇文章中存在的问题进行解决


问题解决

 在上一篇文章中,注册服务提示检查失败。


  通过排查发现为在docker 中运行的容器中配置的心跳检查api地址配置错误:

“Consul”: {
“Address”: “http://host.docker.internal:8500”,
“HealthCheck”: “/api/healthcheck”,//心跳检查api地址
“Name”: “czapigoods”,
“Ip”: “host.docker.internal”,
“Port”: “5602” //未指定成当前docker运行对于端口
}

“Consul”: {
“Address”: “http://host.docker.internal:8500”,
“HealthCheck”: “/api/healthcheck”,//心跳检查api地址
“Name”: “czapigoods”,
“Ip”: “host.docker.internal”,
“Port”: “5602” //未指定成当前docker运行对于端口
}

 解决方法(docker修改配置方式):修改docker中配置文件appsettings.json:

进入docker命令行:docker exec -it 容器id /bin/bash  例如:docker exec -it f38a7a2ddfba /bin/bash

更新软件列表:apt-get update 

安装vim命令:apt-get install vim

进入appsettings.json 修改:vim appsettings.json

修改appsettings中Consul.Port节点为对于docker映射端口

按Esc键,并输入:wq命令(退出保存修改)

重启对于容器效果如下


  Ps:Doker相关操作后面单独详细


服务发现

  服务注册问题解决了,接下来我们了解下服务如何发现;首先创建一个web项目Consul.Client并添加Consul包引用

Install-Package Consul

Install-Package Consul

 1、添加一个服务调用接口ICallService.cs用于调用我们添加的服务

public interface ICallService
{
///


/// 获取 Goods Service 返回数据
///

///
Task GetGoodsService();
///
/// 获取 Order Service 返回数据
///

///
Task GetOrderService();
///
/// 初始化服务
///

void InitServices();
}

public interface ICallService
{
///


/// 获取 Goods Service 返回数据
///

///
Task GetGoodsService();
///
/// 获取 Order Service 返回数据
///

///
Task GetOrderService();
///
/// 初始化服务
///

void InitServices();
}

 

 2、实现该接口CallService.cs调用Goods、Order的api方法  

public class CallService : ICallService
{
private readonly IConfiguration _configuration;
private readonly ConsulClient _consulClient;
private ConcurrentBag _serviceAUrls;
private ConcurrentBag _serviceBUrls;
private IHttpClientFactory _httpClient;
public CallService(IConfiguration configuration, IHttpClientFactory httpClient)
{
_cOnfiguration= configuration;
_cOnsulClient= new ConsulClient(optiOns=>
{
options.Address = new Uri(_configuration[“Consul:Address”]);
});
_httpClient = httpClient;
}
public async Task GetGoodsService()
{
if (_serviceAUrls == null)
return await Task.FromResult(“Goods Service Initializing…”);
using var httpClient = _httpClient.CreateClient();
//随机获取一个服务地址调用
var serviceUrl = _serviceAUrls.ElementAt(new Random().Next(_serviceAUrls.Count()));
Console.WriteLine(“Goods Service:” + serviceUrl);
var result = await httpClient.GetStringAsync($”{serviceUrl}/goods”);
return result;
}
public async Task GetOrderService()
{
if (_serviceBUrls == null)
return await Task.FromResult(“Order Service Initializing…”);
using var httpClient = _httpClient.CreateClient();
//随机获取一个服务地址调用
var serviceUrl = _serviceBUrls.ElementAt(new Random().Next(_serviceBUrls.Count()));
Console.WriteLine(“Order Service:” + serviceUrl);
var result = await httpClient.GetStringAsync($”{serviceUrl}/order”);
return result;
}
public void InitServiceList()
{
var serviceNames = new string[] { “czapigoods”, “czapiorder” };
foreach (var item in serviceNames)
{
Task.Run(async () =>
{
var queryOptiOns= new QueryOptions
{
WaitTime = TimeSpan.FromMinutes(5)
};
while (true)
{
await InitServicesAsync(queryOptions, item);
}
});
}
}
private async Task InitServicesAsync(QueryOptions queryOptions, string serviceName)
{
//获取心跳检查服务
var result = await _consulClient.Health.Service(serviceName, null, true, queryOptions);
if (queryOptions.WaitIndex != result.LastIndex)
{
queryOptions.WaitIndex = result.LastIndex;
var services = result.Response.Select(x => $”http://{x.Service.Address}:{x.Service.Port}”);
if (serviceName == “czapigoods”)
{
_serviceAUrls = new ConcurrentBag(services);
}
else if (serviceName == “czapiorder”)
{
_serviceBUrls = new ConcurrentBag(services);
}
}
}
}

public class CallService : ICallService
{
private readonly IConfiguration _configuration;
private readonly ConsulClient _consulClient;
private ConcurrentBag _serviceAUrls;
private ConcurrentBag _serviceBUrls;
private IHttpClientFactory _httpClient;
public CallService(IConfiguration configuration, IHttpClientFactory httpClient)
{
_cOnfiguration= configuration;
_cOnsulClient= new ConsulClient(optiOns=>
{
options.Address = new Uri(_configuration[“Consul:Address”]);
});
_httpClient = httpClient;
}
public async Task GetGoodsService()
{
if (_serviceAUrls == null)
return await Task.FromResult(“Goods Service Initializing…”);
using var httpClient = _httpClient.CreateClient();
//随机获取一个服务地址调用
var serviceUrl = _serviceAUrls.ElementAt(new Random().Next(_serviceAUrls.Count()));
Console.WriteLine(“Goods Service:” + serviceUrl);
var result = await httpClient.GetStringAsync($”{serviceUrl}/goods”);
return result;
}
public async Task GetOrderService()
{
if (_serviceBUrls == null)
return await Task.FromResult(“Order Service Initializing…”);
using var httpClient = _httpClient.CreateClient();
//随机获取一个服务地址调用
var serviceUrl = _serviceBUrls.ElementAt(new Random().Next(_serviceBUrls.Count()));
Console.WriteLine(“Order Service:” + serviceUrl);
var result = await httpClient.GetStringAsync($”{serviceUrl}/order”);
return result;
}
public void InitServiceList()
{
var serviceNames = new string[] { “czapigoods”, “czapiorder” };
foreach (var item in serviceNames)
{
Task.Run(async () =>
{
var queryOptiOns= new QueryOptions
{
WaitTime = TimeSpan.FromMinutes(5)
};
while (true)
{
await InitServicesAsync(queryOptions, item);
}
});
}
}
private async Task InitServicesAsync(QueryOptions queryOptions, string serviceName)
{
//获取心跳检查服务
var result = await _consulClient.Health.Service(serviceName, null, true, queryOptions);
if (queryOptions.WaitIndex != result.LastIndex)
{
queryOptions.WaitIndex = result.LastIndex;
var services = result.Response.Select(x => $”http://{x.Service.Address}:{x.Service.Port}”);
if (serviceName == “czapigoods”)
{
_serviceAUrls = new ConcurrentBag(services);
}
else if (serviceName == “czapiorder”)
{
_serviceBUrls = new ConcurrentBag(services);
}
}
}
}

 3、接下来添加接口依赖注入、以及服务初始化调用  

public class Startup
{
public Startup(IConfiguration configuration)
{
COnfiguration= configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddHttpClient();
     //依赖注入CallService
services.AddSingleton();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ICallService service)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
     //初始化服务列表调用
service.InitServiceList();
}
}  

public class Startup
{
public Startup(IConfiguration configuration)
{
COnfiguration= configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddHttpClient();
     //依赖注入CallService
services.AddSingleton();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ICallService service)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
     //初始化服务列表调用
service.InitServiceList();
}
}  

 4、使用Postman测试调用


  

KV操作

 除了提供服务发现和健康检查的集成.Consul提供了一个易用的键/值存储.这可以用来保持动态配置,协助服务协调,领袖选举,做开发者可以想到的任何事情.

 1、创建/修改

命令方式:consul kv put key val 如:consul kv put port 9000 –添加key为port值为9000

Http方式:


 2、查询  

命令方式:consul kv get key 如:consul kv get port –查询key为port的KV

Http方式:value为baisc


 3、删除

命令方式:consul kv delete key 如:consul kv delete port –删除key为port的KV

Http方式:



 其他

 网上找了下:常用服务发现框架consul、zookeeper及etcd比较:


参考:

consul手册:https://blog.csdn.net/liuzhuchen/article/details/81913562 

https://www.consul.io/docs

https://www.consul.io/api/kv.html

github:

https://github.com/cwsheng/Consul.Demo.git



推荐阅读
  • Python 实战:异步爬虫(协程技术)与分布式爬虫(多进程应用)深入解析
    本文将深入探讨 Python 异步爬虫和分布式爬虫的技术细节,重点介绍协程技术和多进程应用在爬虫开发中的实际应用。通过对比多进程和协程的工作原理,帮助读者理解两者在性能和资源利用上的差异,从而在实际项目中做出更合适的选择。文章还将结合具体案例,展示如何高效地实现异步和分布式爬虫,以提升数据抓取的效率和稳定性。 ... [详细]
  • 利用树莓派畅享落网电台音乐体验
    最近重新拾起了闲置已久的树莓派,这台小巧的开发板已经沉寂了半年多。上个月闲暇时间较多,我决定将其重新启用。恰逢落网电台进行了改版,回忆起之前在树莓派论坛上看到有人用它来播放豆瓣音乐,便萌生了同样的想法。通过一番调试,终于实现了在树莓派上流畅播放落网电台音乐的功能,带来了全新的音乐享受体验。 ... [详细]
  • FastDFS Nginx 扩展模块的源代码解析与技术剖析
    FastDFS Nginx 扩展模块的源代码解析与技术剖析 ... [详细]
  • 本文深入探讨了 hCalendar 微格式在事件与时间、地点相关活动标记中的应用。作为微格式系列文章的第四篇,前文已分别介绍了 rel 属性用于定义链接关系、XFN 微格式增强链接的人际关系描述以及 hCard 微格式对个人和组织信息的描述。本次将重点解析 hCalendar 如何通过结构化数据标记,提高事件信息的可读性和互操作性。 ... [详细]
  • 本文深入探讨了数据库性能优化与管理策略,通过实例分析和理论研究,详细阐述了如何有效提升数据库系统的响应速度和处理能力。文章首先介绍了数据库性能优化的基本原则和常用技术,包括索引优化、查询优化和存储管理等。接着,结合实际应用场景,讨论了如何利用容器化技术(如Docker)来部署和管理数据库,以提高系统的可扩展性和稳定性。最后,文章还提供了具体的配置示例和最佳实践,帮助读者在实际工作中更好地应用这些策略。 ... [详细]
  • RancherOS 是由 Rancher Labs 开发的一款专为 Docker 设计的轻量级 Linux 发行版,提供了一个全面的 Docker 运行环境。其引导镜像仅 20MB,非常适合在资源受限的环境中部署。本文将详细介绍如何在 ESXi 虚拟化平台上安装和配置 RancherOS,帮助用户快速搭建高效、稳定的容器化应用环境。 ... [详细]
  • 在 Kubernetes 中,Pod 的调度通常由集群的自动调度策略决定,这些策略主要关注资源充足性和负载均衡。然而,在某些场景下,用户可能需要更精细地控制 Pod 的调度行为,例如将特定的服务(如 GitLab)部署到特定节点上,以提高性能或满足特定需求。本文深入解析了 Kubernetes 的亲和性调度机制,并探讨了多种优化策略,帮助用户实现更高效、更灵活的资源管理。 ... [详细]
  • 设计实战 | 10个Kotlin项目深度解析:首页模块开发详解
    设计实战 | 10个Kotlin项目深度解析:首页模块开发详解 ... [详细]
  • Redis哈希数据结构入门指南
    Redis的哈希数据结构与Java中的HashMap类似,采用数组加链表的方式实现。数组用于存储哈希值的位置,而链表则用于处理哈希冲突的情况。此外,Redis的哈希数据结构还支持高效的字段操作和内存优化,适用于多种应用场景,如缓存和会话管理。 ... [详细]
  • PHP 数组逆序排列方法及常用排序函数详解 ... [详细]
  • MongoVUE基础操作指南:轻松上手数据库管理
    本文介绍了MongoVUE的基础操作,旨在帮助用户轻松掌握数据库管理技巧。MongoVUE是一款功能强大的MongoDB客户端工具,虽然需要注册,但其用户友好的界面和丰富的功能使其成为许多开发者的首选。文中详细解释了安装步骤、基本配置以及常见操作方法,并对一些常见的问题进行了修正和补充,确保用户能够快速上手并高效使用MongoVUE进行数据库管理。 ... [详细]
  • 利用Flask框架进行高效Web应用开发
    本文探讨了如何利用Flask框架高效开发Web应用,以满足特定业务需求。具体案例中,一家餐厅希望每天推出不同的特色菜,并通过网站向顾客展示当天的特色菜。此外,还增加了一个介绍页面,在bios路径下详细展示了餐厅主人、厨师和服务员的背景和简介。通过Flask框架的灵活配置和简洁代码,实现了这一功能,提升了用户体验和餐厅的管理水平。 ... [详细]
  • 如何高效启动大数据应用之旅?
    在前一篇文章中,我探讨了大数据的定义及其与数据挖掘的区别。本文将重点介绍如何高效启动大数据应用项目,涵盖关键步骤和最佳实践,帮助读者快速踏上大数据之旅。 ... [详细]
  • 《精通 jQuery》第六章:深入解析与实战应用
    《精通 jQuery》第六章:深入解析与实战应用本章详细探讨了 Ajax 技术的核心机制及其实际应用。Ajax 通过 XMLHttpRequest 对象实现客户端与服务器之间的异步数据交换,从而在不重新加载整个页面的情况下更新部分内容。这种技术不仅提升了用户体验,还提高了应用的响应速度和效率。此外,本章还介绍了如何利用 jQuery 简化 Ajax 操作,并提供了多个实战案例,帮助读者更好地理解和掌握这一重要技术。 ... [详细]
  • 本文详细解析了JSONP(JSON with Padding)的跨域机制及其工作原理。JSONP是一种通过动态创建``标签来实现跨域请求的技术,其核心在于利用了浏览器对``标签的宽松同源策略。文章不仅介绍了JSONP的产生背景,还深入探讨了其具体实现过程,包括如何构造请求、服务器端如何响应以及客户端如何处理返回的数据。此外,还分析了JSONP的优势和局限性,帮助读者全面理解这一技术在现代Web开发中的应用。 ... [详细]
author-avatar
只想活得快乐的魔羯
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有