Consul 学习笔记—服务发现
前言:
上一篇文章简单实用Consul试下服务注册,本篇继续学习Consul中的另外特性:服务发现、KV操作 ;以及对上篇文章中存在的问题进行解决
问题解决
在上一篇文章中,注册服务提示检查失败。
通过排查发现为在docker 中运行的容器中配置的心跳检查api地址配置错误:
"Consul": { "Address": "//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
1、添加一个服务调用接口ICallService.cs用于调用我们添加的服务
public interface ICallService { /// <summary> /// 获取 Goods Service 返回数据 /// </summary> /// <returns></returns> Task<string> GetGoodsService(); /// <summary> /// 获取 Order Service 返回数据 /// </summary> /// <returns></returns> Task<string> GetOrderService(); /// <summary> /// 初始化服务 /// </summary> void InitServices(); }
2、实现该接口CallService.cs调用Goods、Order的api方法
public class CallService : ICallService { private readonly IConfiguration _configuration; private readonly ConsulClient _consulClient; private ConcurrentBag<string> _serviceAUrls; private ConcurrentBag<string> _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<string> 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<string> 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 => $"//{x.Service.Address}:{x.Service.Port}"); if (serviceName == "czapigoods") { _serviceAUrls = new ConcurrentBag<string>(services); } else if (serviceName == "czapiorder") { _serviceBUrls = new ConcurrentBag<string>(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<ICallService, CallService>(); } // 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手册://blog.csdn.net/liuzhuchen/article/details/81913562
//www.consul.io/docs
//www.consul.io/api/kv.html
github:
//github.com/cwsheng/Consul.Demo.git