快速启动一个consul集群可以参考:使用docker快速部署一个consul集群

  .net core集成使用consul是通过consul提供出来api接口来实现的,可以分成两个部分来说明:配置集成、服务注册。

  代码比较多,已上传到gitee上了,地址见:https://gitee.com/shanfeng1000/dotnetcore-demo/tree/master/Consul

  这是一个Demo项目,介绍.net core集成使用rabbitmq消息队列,使用的.net core 3.1,这里简单介绍:

  集成使用Consul的kv store(配置服务)

  .net core从consul的kv stroe中获取配置很容易,但是实现kv store的热加载有三种方式:

  方式一:阻塞式查询(长轮询)(推荐)

  有关阻塞式查询的介绍,可以参考官网:https://www.consul.io/api-docs/features/blocking

  不过这里可以简单的将阻塞式查询理解为,consul为请求资源设置了一个index(可以理解为版本号),当资源更新时,consul会将版本号增加,而当使用api请求时可以携带一个index参数(起始版本)和wait参数(等待时间),当在wait时间内,存在index大于请求的index参数时(如果本就存在,那就不用等待了),会返回一个响应,响应会携带一个X-Consul-Index的Header,表示新的index,否则会在wait时间后超时返回响应,表示没有新的index。

  在上面gitee的Demo中的AspNetCore.WebApi.Client中的Program中集成使用:  

    public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>(); ...

}).UseConsul(options =>
{
options.Address = "http://192.168.209.128:18401";
options.Datacenter = "dc1";
options.Token = "245d0a09";
options.Prefix = "Root/Consul"; //使用阻塞式查询实现热更新
options.Mode = WatchMode.Poll;
options.Interval = TimeSpan.FromMinutes(3);
});

  现在consul中的kv store中Root/Consul节点下的所有kv都将被集成到.net core中的IConfiguration中去了,修改此节点下的任意kv都会自动更新IConfiguration,这是最简单的一种热更新方式。

  方式二:consul watch

  有关consul watch的介绍,可以参考官网:https://www.consul.io/docs/dynamic-app-config/watches

  consul watch是一种监听机制,可以监听kv、service、node等信息,当它们发生改变时,触发某些handle,而这些handle包括执行shell脚本,发送http请求等。

  事实上,consul watch是基于阻塞式查询的一种实现,但是遗憾的是,目前consul watch并没有提供出来api接口出来注册handle,所以在集成时,我们的项目需要提供出接口来公consul watch通知调用。

  在上面gitee的Demo中的AspNetCore.WebApi.Server中的Program中集成使用:  

    public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
... webBuilder.ConfigureAppConfiguration(builder =>
{
builder.AddConsul(options =>
{
options.Address = "http://192.168.209.128:18401";
options.Datacenter = "dc1";
options.Token = "245d0a09";
options.Prefix = "Root/Consul"; //使用consul-template或者watch来实现热更新,需要在Configure中使用UseConsulWatch拦截更新配置请求
options.Mode = WatchMode.Watch;
options.ReloadName = "demo";
});
});
});

  这样,项目启动后,可以从consul的kv store中读取配置,我们还需要提供一个回调的接口,可以在Startup的Configure方法时使用中间件UseConsulWatch来拦截:  

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseConsulWatch(); ...
}

  默认情况下,这个接口是POST请求,地址是http://host:port/consul?name=reloadName,这里的reloadName就是在Program中配置的那个ReloadName,表示收到更新后,只会重新加载指定name名称的这个IConfigurationProvider,多个name之间使用逗号分隔。reloadName为空则表示重新加载所有的IConfigurationProvider,有了接口,接下来我们需要执行consul watch来启动监听:  

    # 执行consul watch
consul watch -http-addr=192.168.209.128:18402 -datacenter=dc1 -prefix=Root/Consul -type=keyprefix "curl -X POST http://192.168.28.212:16001/consul -d ''" 说明:
-http-addr:表示连接的consul地址,默认是127.0.0.1:8500
-datacenter:数据中心
-type:表示监听的类型,可选的有key, keyprefix, services, nodes, service, checks, event,这里是配置,所以选择keyprefix,表示具有这个前缀的所有kv(key表示单个的kv)
-prefix:kv的前缀
curl -X POST http://192.168.28.212:16001/consul -d '':这是kv更新后需要执行的命令,可以是shell脚本,也可以是普通的命令,这里是调用项目接口来更新项目配置实现热更新

  现在,更新kv store,会发现程序已经实现了热加载

  方式三:consul-template

  有关consul-template相关的介绍可以参考:https://github.com/hashicorp/consul-template

  consul-template的下载地址:https://releases.hashicorp.com/consul-template/

  consul-template是基于consul watch的一套模板工具,可以这么理解consul-template,首先你需要提供一个模板,一般是一个ctmpl文件(语法类似于go template,具体可以参考这里)。接着,需要指定consul地址,及认证等信息,这样,consul-template连接到consul,然后会根据模板中需要的参数对consul进行监听,当对应的参数更新后会重新渲染模板。模板渲染更新后,我们可以使用这个新模板,一般我们先要将模板输出成文件才能使用(一般是配置文件),所以我们还需要指定一个输出文件路径。输出文件之后,我们还能需要执行一些脚本,命令等等。一般为了方便管理,这些配置都是写在一个config.hcl文件中。

  .net core使用与上面consul watch一样,只是监听不在是使用consul watch,所以上面监听部分换成consul-template可以写成:

  首先创建一个config.hcl文件:  

  consul {
address = "192.168.209.128:18402",
token = "245d0a09"
} template {
contents = "{{ tree \"Root/Consul\" | explode | toJSONPretty }}",
command = "curl -X POST http://192.168.28.212:16001/consul -d ''"
}

  上面的contents及模板内容,这里的意思是以json格式输出Root/Consul下的kv,当Root/Consul下的kv更新时,会重新渲染这个模板,当然,contents的内容也可以写在一个ctmpl文件中,然后将contents换成source用于指定这个ctmpl文件的位置。command表示在模板渲染完成之后需要执行的命令,这里是使用curl发出一个http请求。更多配置说明参考:https://github.com/hashicorp/consul-template/blob/master/docs/configuration.md#configuration-file

  现在可以使用consul-template来启动监控了:  

    # 启动
consul-template -config config.hcl -dry 说明:
-config:指定配置文件
-dry:表示渲染后的模板输出到标准输出中,而不是输出到一个文件中,如果没有这个参数,则需要在上面config.hcl中的temlate节点中添加一个destination节点,用于指明模板渲染后的输出文件路径,这里因为没使用到渲染后的文件,不需要使用文件,所以使用-dry输出即可

  现在,更新kv store,会发现程序也已经实现了热加载。

  注:

  consul-template是一个很灵活的模板工具,我们可以将consul、consul-template、nginx一起使用,组合成一套服务自动发现功能:nginx使用consul-template生成conf文件,而consul-template监控consul中已经注册的服务,当有新实例加入或者已有实例退出时,consul-template会重新渲染生成新的conf文件,渲染完成后执行命令或者脚本让nginx重新加载即可。这种方式常常用在分布式系统的场景,因为如果我们的项目采用了分布式部署,难道要为分布式中的每个节点都手动的用consul watch?特别是容器化的应用,consul watch就不太现实了,这个时候可以使用consul-template来实现:

  首先我们先创建一个ctmpl文件(如:demo.ctmpl):  

    #!/bin/bash

    #这行代码用于添加kv的监控
#{{ tree "Root/Consul" }} #输出server服务的所有实例,并请求重新加载配置
{{range service "server@dc1"}}
curl -X POST http://{{.Address}}:{{.Port}}/consul -d ''
{{end}}

  接着创建一个demo.hcl文件:  

  consul {
address = "192.168.209.128:18402",
token = "245d0a09"
} template {
source = "./demo.ctmpl",
destination = "demo.sh",
command = "/bin/bash demo.sh"
}

  然后启动:  

    # 启动,因为有输出文件,不能使用-dry
consul-template -config demo.hcl

  这是,当名称为server的服务有多个实例时,kv 的更新会通知到所有的实例。(当然,这个例子中,配置加载采用这种方式也有缺点,因为新实例加入或者已有实例退出也会触发热加载)

  

  使用Consul作为服务注册中心

  consul是一款很优秀的服务治理工具,在这个demo项目中,我简单的做了一个封装,方便集成使用,如AspNetCore.WebApi.Client的Startup中的服务注册:

    public void ConfigureServices(IServiceCollection services)
{
... //consul服务注册
services.AddConsulClient("consul", options =>
{
options.Address = "http://192.168.209.128:18401";
options.Datacenter = "dc1";
//options.Token = "token";//如果有token
}).AddService(options =>
{
options.Host = ip;
options.Port = port;
options.Id = $"client_{ip}_{port}";
options.Name = "client";
options.Tags = new[] { "client" };
options.HealthCheckPath = "Health";
}); ...
}

  通过AddConsulClient方法创建一个Consul的客户端,通过AddService使用这个客户端添加服务,其中服务的健康检查支持简单的http和grpc两种方式,如果采用grpc方式,那么需要提供一个标准的grpc服务,官方给出的health.proto如下:  

    syntax = "proto3";
package grpc.health.v1; message HealthCheckRequest {
string service = 1;
} message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
SERVICE_UNKNOWN = 3;
}
ServingStatus status = 1;
} service Health {
rpc Check(HealthCheckRequest) returns (HealthCheckResponse); rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}

  注:此文件是官方标准,不要做任何改动,否则可能导致健康检查失败

  Grpc方式的使用如AspNetCore.WebApi.Server的Startup中的服务注册:  

    public void ConfigureServices(IServiceCollection services)
{
... //consul服务注册
services.AddConsulClient(options =>
{
options.Address = "http://192.168.209.128:18405";
options.Datacenter = "dc1";
//options.Token = "token";//如果有token
}).AddService(options =>
{
//http服务
options.Host = ip;
options.Port = port;
options.Id = $"server_{ip}_{port}";
options.Name = "server";
options.Tags = new[] { "server" };
options.HealthCheckPath = "Health";
}).AddService(options =>
{
//grpc服务
options.Host = ip;
options.Port = grpcPort;
options.Id = $"server_grpc_{ip}_{grpcPort}";
options.Name = "server_grpc";
options.Tags = new[] { "server" };
//options.HealthCheckUrl = $"http://{ip}:{port}/Health";//使用http的健康检测 //使用grpc做健康检查
options.HealthCheckUseGrpc = true;
options.HealthCheckUrl = $"{ip}:{grpcPort}";//依赖health.proto
}); ...
}

  AspNetCore.WebApi.Server的Startup中注册了两个服务,一个用于提供http服务,一个用于提供grpc服务,添加的服务,最终使用IHostedService来完成注册。

  服务之间的通信通常采用http方式和grpc方式,如AspNetCore.WebApi.Client使用http和grpc两种方式调用AspNetCore.WebApi.Server服务,在AspNetCore.WebApi.Client的Startup中添加HttpClient和GrpcClient的客户端:  

    public void ConfigureServices(IServiceCollection services)
{
... //http client
services.AddHttpClient("http", client =>
{
client.BaseAddress = new Uri("http://server");//server是Server的http服务注册进Consul的服务名
}).AddServiceDiscovery("consul", LoadBalancerMode.RoundRobin);//添加服务发现机制 //grpc client
services.AddGrpcClient<WebApiServer.WebApiServerClient>("grpc", options =>
{
options.Address = new Uri("http://server_grpc");//server_grpc是Server的grpc服务注册进Consul的服务名
})
.AddServiceDiscoveryPolling(options =>//添加服务发现机制
{
options.Address = "http://192.168.209.128:18406";
options.Datacenter = "dc1";
//options.Token = "token";//如果有token
}); ...
}

  AddHttpClient和AddGrpcClient就是你熟悉的那种调用方式,只是还添加了一个尾巴:AddServiceDiscovery和AddServiceDiscoveryPolling

  AddServiceDiscovery:添加服务发现机制,服务名即请求地址中的host部分(不能携带端口),通知指定使用的consul客户端(如果是名称,则是使用AddConsulClient添加的客户端,也可以指定具体的consul信息),LoadBalancerMode是均衡模式,也就是说,当发起一个请求时,会将host部分作为服务名,使用指定的这个consul客户端去获取所有这个服务的实例,然后采用LoadBalancerMode指定的模式从这些实例中获得一个可用的实例,然后转而请求这个实例的资源。

  AddServiceDiscoveryPolling:作用同AddServiceDiscovery,只是不在是每次请求都是使用consul客户端去获取服务实例,而是从实例缓存去获取可用的实例,这背后有一个定时器定时的去获取服务实例,然后刷新实例缓存,这样可以提高性能,但是不保证服务实例的可用性。

  调用方式只需像原来的HttpClient和GrpcClient的方式去调用就可以了,如AspNetCore.WebApi.Client的RemoteController中的使用:  

    /// <summary>
/// 使用Http方式调用远程接口
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
public async Task<object> Http(string name)
{
var httpClientFactory = HttpContext.RequestServices.GetRequiredService<IHttpClientFactory>();
var httpClient = httpClientFactory.CreateClient("http");//http是Startup中注册的http client名称
var response = await httpClient.GetAsync($"/Remote?name={name}");
return await response.Content.ReadAsStringAsync();
}
/// <summary>
/// 使用Grpc方式调用远程接口
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
public async Task<object> Grpc(string name)
{
var grpcClientFactory = HttpContext.RequestServices.GetRequiredService<GrpcClientFactory>();
var grpcClient = grpcClientFactory.CreateClient<WebApiServer.WebApiServerClient>("grpc");//grpc是Startup中注册的grpc client名称
var data = await grpcClient.SayAsync(new DataRequest() { Name = name });
return data.Message;
}

.net core集成使用consul的更多相关文章

  1. [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置

    [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置 原文: USING CONSUL FOR STORING THE CONFIGURATION IN ASP.NET COR ...

  2. NET Core + Ocelot + IdentityServer4 + Consul

    .NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现 先决条件 关于 Ocelot 针对使用 .NET 开发微服务架构或者面向服务架构提供一个统一访 ...

  3. asp.net core集成CAP(分布式事务总线)

    一.前言 感谢杨晓东大佬为社区贡献的CAP开源项目,传送门在此:.NET Core 事件总线,分布式事务解决方案:CAP 以及 如何在你的项目中集成 CAP[手把手视频教程],之前也在工作中遇到分布式 ...

  4. net core集成CAP

    net core集成CAP https://www.cnblogs.com/guolianyu/p/9756941.html 一.前言 感谢杨晓东大佬为社区贡献的CAP开源项目,传送门在此:.NET ...

  5. Net Core 中使用 Consul 来存储配置

    Net Core 中使用 Consul 来存储配置 https://www.cnblogs.com/Rwing/p/consul-configuration-aspnet-core.html 原文: ...

  6. 【转】.NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现

    作者:Zhang_Xiang 原文地址:.NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现 先决条件 关于 Ocelot 针对使用 .NET 开发 ...

  7. ABP官方文档翻译 6.2.1 ASP.NET Core集成

    ASP.NET Core 介绍 迁移到ASP.NET Core? 启动模板 配置 启动类 模块配置 控制器 应用服务作为控制器 过滤器 授权过滤器 审计Action过滤器 校验过滤器 工作单元Acti ...

  8. asp.net core 集成 log4net 日志框架

    asp.net core 集成 log4net 日志框架 Intro 在 asp.net core 中有些日志我们可能想输出到数据库或文件或elasticsearch等,如果不自己去实现一个 Logg ...

  9. [Abp 源码分析]十七、ASP.NET Core 集成

    0. 简介 整个 Abp 框架最为核心的除了 Abp 库之外,其次就是 Abp.AspNetCore 库了.虽然 Abp 本身是可以用于控制台程序的,不过那样的话 Abp 就基本没什么用,还是需要集合 ...

随机推荐

  1. Function overloading and return type

    In C++ and Java, functions can not be overloaded if they differ only in the return type. For example ...

  2. 【Linux】【Services】【Configuration】puppet

    1. 简介 1.1. 官方网站:https://docs.puppet.com/ 1.2. puppet是IT基础设施自动化管理工具,他的整个生命周期包括:provisioning,configura ...

  3. 登录界面.jsp

    <!DOCTYPE html><html lang="zh-CN"> <head> <meta charset="utf-8&q ...

  4. 强化学习实战 | 表格型Q-Learning玩井子棋(三)优化,优化

    在 强化学习实战 | 表格型Q-Learning玩井字棋(二)开始训练!中,我们让agent"简陋地"训练了起来,经过了耗费时间的10万局游戏过后,却效果平平,尤其是初始状态的数值 ...

  5. centos k3s部署

    目录 一.k3s介绍 二.在线安装 三.离线安装 四.高可用安装 五.配置k3s镜像仓库 六.Kubernetes 仪表盘 七.常用命令 八.参考 一.k3s介绍 1.k3s是一个轻量级的 Kuber ...

  6. 玩转 Mockjs,前端也能跑的很溜

    ​ mockjs作用就是,生成随机模拟数据,拦截 ajax 请求,可以对数据进行增删改查.在生成数据时,我们就需要能够熟练使用 mock.js 的语法. Mockjs 的语法规范包括两部分:数据模板定 ...

  7. Abp Vnext 替换Redis的实现为csredis

    Host项目安装csredis的nuget包和data protect包并 移除 Microsoft.Extensions.Caching.StackExchangeRedis Microsoft.A ...

  8. 自定义 UITableViewCell 的 accessory 样式

    对于 UITableViewCell 而言,其 accessoryType属性有4种取值: UITableViewCellAccessoryNone, UITableViewCellAccessory ...

  9. nodejs+koa+uniapp实现微信小程序登陆获取用户手机号及openId

    nodejs+koa+uniapp实现微信小程序登陆获取用户手机号及openId 前言: 我准备用nodejs+koa+uniapp实现一款餐饮点单小程序,以及nodejs+koa+vue实现后端管理 ...

  10. JAVA删除某个文件夹(递归删除文件夹的所有文件)

    /** * 递归删除文件夹下所有内容 最后删除该文件夹 * @param filePath 要删除的文件夹路径 * @return */ public boolean deleteFiles(Stri ...