前言:
上一篇文章簡單實用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運行對於端口 }
解決方法(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 => $"http://{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手冊: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