热门标签 | 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



推荐阅读
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • (九)Docker常用安装
    一、总体步骤1、搜索镜像2、拉取镜像3、查看镜像4、启动镜像5、停止镜像6、移除镜像二、安装tomcat1、dockerhub上面查找tomcat镜像 dockersearchto ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
  • {moduleinfo:{card_count:[{count_phone:1,count:1}],search_count:[{count_phone:4 ... [详细]
  • Summarize function is doing alignment without timezone ?
    Hi.Imtryingtogetsummarizefrom00:00otfirstdayofthismonthametric, ... [详细]
  • 大坑|左上角_pycharm连接服务器同步写代码(图文详细过程)
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了pycharm连接服务器同步写代码(图文详细过程)相关的知识,希望对你有一定的参考价值。pycharm连接服务 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了markdown[软件代理设置]相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 现在比较流行使用静态网站生成器来搭建网站,博客产品着陆页微信转发页面等。但每次都需要对服务器进行配置,也是一个重复但繁琐的工作。使用DockerWeb,只需5分钟就能搭建一个基于D ... [详细]
  • 随着我司的应用都开始容器化,相应的ETL流程也需要迁移到容器中。常规的SQL和shell脚本迁移之后执行基本没有问题,主要的问题在于数据接入使用kettle的场景下,kettle启 ... [详细]
  • docker容器的数据管理一:数据卷实现数据的永久化,完全独立于容 ... [详细]
  • systemd-nspawn可以创建最轻量级的容器(ns的意思就是namespace),本文的实验平台是Ubuntu16.04,x86_64机器。本文的目的是:在Ubuntu中用syst ... [详细]
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社区 版权所有