本文已参与「新人创作礼」活动.一起开启掘金创作之路。
netcore 集成 consul集群
分两步 第一步是服务内部集成consul,这个相对简单 第二步是ocelot集成consul网关,这个相对麻烦一点
1、内部微服务集成consul集群
需要的配置
public class ConsulConfig
{
public string IP { get; set; } //程序的本机地址 默认是本机的所有地址
public int port { get; set; }//程序的本机端口 注册中心使用
public string consulAddress { get; set; } //consul 地址
public string serviceId { get; set; } //程序的服务id 唯一值
public string serviceName { get; set; } //服务的名称
public string checkUrl { get; set; } //服务的名称
public int checkInterval { get; set; } //服务检查间隔
public string dataCenter { get; set; } //数据中心名称 默认的是dc1
public string enable { get; set; } //是否启用
}
配置:"Consul": {
//单节点
//"Address": "http://xxxx:8500",
//"Address": "http://xxxx:8500",
"CheckUrl": "/Heath/check",
"CheckInterval": 60, //检查间隔(单位:秒)
"DataCenter": "", //为空则是默认的 dc1
"enable": "1", //是否启用 默认是不启用 1启用 其他不启用
"ignoreNetwork": ".*Sangfor.*,.*Microsoft.*,.*TAP-Windows.*,.*VMware.*,.*VirtualBox.*,.*vEthernet.*,.*Virtual.*,.*Hyper-V.*" //忽略的网卡, //"Address": "http://xxxx:8500",
"enable": "0", //是否启用 默认是不启用 1启用 其他不启用
//集群模式
"Address": "http://xxxx:8500,http://xxxx:8500,http://xxxx:8500",
"DataCenter": "zz"
},
集成方法
/// <summary>
/// 添加consul客户端
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddConsulClient(this IServiceCollection services)
{
ConsulConfig consulConfig = getConfig(services);
if (consulConfig.enable != "1")
{
//因为其他服务注入了 IConsulClient 当不启用consul是会报错 这里注入一个空的consul
services.AddConsul(options =>
{
options.Datacenter = consulConfig.dataCenter;
options.Address = new Uri("http://localhost:8500");
//options.Token = token1;
options.WaitTime = TimeSpan.FromSeconds(consulConfig.checkInterval);
});
return services;
}
foreach (string url in consulConfig.consulAddress.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
{
services.AddConsul(options =>
{
options.Datacenter = consulConfig.dataCenter;
options.Address = new Uri(url);
//options.Token = token1;
options.WaitTime = TimeSpan.FromSeconds(consulConfig.checkInterval);
});
}
//覆盖原来的ConsulClientFactory工厂
services.RemoveAll(typeof(IConsulClientFactory));
services.TryAddSingleton<IConsulClientFactory, MyConsulClientFactory>();
return services;
}
/// <summary>
/// 添加客户端以及注册到注册中心
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddConsulClientAndRegistration(this IServiceCollection services)
{
ConsulConfig consulConfig = getConfig(services);
services.AddConsulClient();
if (consulConfig.enable != "1")
{
return services;
}
services.AddConsulServiceRegistration(options =>
{
options.Checks = new[]
{
new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromMilliseconds(1), //服务停止后多久注销
Interval = TimeSpan.FromSeconds(10), //服务健康检查间隔
Timeout = TimeSpan.FromSeconds(10), //检查超时的时间
HTTP = consulConfig.checkUrl //检查的地址
}
};
options.Address = consulConfig.IP; //本程序的IP地址
options.ID = consulConfig.serviceId; //服务编号,不可重复
options.Name = consulConfig.serviceName; //服务名称
options.Port = consulConfig.port;
});
return services;
}
替换原来的ConsulClientFactory 默认的ConsulClientFactory不支持配置多个consul客户端public class MyConsulClientFactory : IConsulClientFactory
{
private readonly IOptionsMonitor<ConsulClientConfiguration> _optionsMonitor;
public MyConsulClientFactory(IOptionsMonitor<ConsulClientConfiguration> optionsMonitor)
{
this._optionsMonitor = optionsMonitor;
}
public IConsulClient CreateClient()
{
return this.CreateClient(RegisterToConsulExtension.currentUseConsulName);
}
public IConsulClient CreateClient(string name)
{
return (IConsulClient)new ConsulClient(this._optionsMonitor.Get(name));
}
}
注意 需要在健康检查中或者定时任务中设置可用的consul客户端 调用如下的方法,如果某个consul客户端挂掉了可以切换到其他的consul服务(需要定义两个变量,用于维护目前使用的是哪个consul客户端)
//保存所有的consul客户端名称
public static List<String> consulNames = new List<string>();
//当前使用的consul客户端名字
public static string currentUseConsulName = "ConsulClient0";
\
/// <summary>
/// 设置可用的consul客户端
/// 检查当前的consul客户端是否可用 不可用时会找一个可用的consul客户端
/// </summary>
/// <param name="consulClientFactory"></param>
public static void SetCurrentConsulClient(IConsulClientFactory consulClientFactory)
{
IConsulClient consulClient = consulClientFactory.CreateClient();
try
{
string result = consulClient.Agent.GetNodeName().Result;
}
catch (Exception e)
{
List<String> badConsulNames = new List<string>()
{RegisterToConsulExtension.currentUseConsulName};
Random random = new Random();
while (true)
{
List<string> okConsulNames = RegisterToConsulExtension.consulNames.FindAll(o => !badConsulNames.Contains(o));
if (okConsulNames.Count == 0)
{
break;
}
int next = random.Next(0, okConsulNames.Count);
String consulName = okConsulNames[next];
try
{
consulClient = consulClientFactory.CreateClient(consulName);
//如果这里异常这说明这个consul客户端不能用
string result = consulClient.Agent.GetNodeName().Result;
RegisterToConsulExtension.currentUseConsulName = consulName;
break;
}
catch (Exception exception)
{
badConsulNames.Add(consulName);
}
}
}
LogUtils.Info($"当前使用的consul:{RegisterToConsulExtension.currentUseConsulName}");
}
\
\
//注册到consul
services.AddConsulClientAndRegistration();
2、ocelot 集成consul (ocelot 默认不支持consul集群(也可能是我没找到),需要重写部分方法)
除了上面要调用 services.AddConsulClientAndRegistration(); 外还需要修改ocelot注入
该方法参照 ocelot的 AddConsul 并且需要注入自定义的 MyConsulClientFactory ,重写get方法 覆盖原来的ConsulClientFactory
修改注入的方法
public static IServiceCollection AddOcelotConsul(this IServiceCollection services) {
//添加客户端以及注册到注册中心
services.AddConsulClientAndRegistration();
//注入ocelot需要的类
services.AddSingleton<ServiceDiscoveryFinderDelegate>(ConsulProviderFactory.Get);
services.RemoveAll(typeof(Ocelot.Provider.Consul.IConsulClientFactory));
services.AddSingleton<Ocelot.Provider.Consul.IConsulClientFactory, MyOcelotConsulClientFactory>();
services.RemoveAll(typeof(IFileConfigurationPollerOptions));
services.AddSingleton<IFileConfigurationPollerOptions, ConsulFileConfigurationPollerOption>();
return services;
}
自定义ConsulClientFactory 该工厂是ocelot里面的工厂不是 consul包里面的工厂public class MyOcelotConsulClientFactory: IConsulClientFactory
{
private Consul.AspNetCore.IConsulClientFactory consulClientFactory;
public MyConsulClientFactory(Consul.AspNetCore.IConsulClientFactory consulClientFactory)
{
this.consulClientFactory = consulClientFactory;
}
public IConsulClient Get(ConsulRegistryConfiguration config)
{
return consulClientFactory.CreateClient();
}
}
如何使用?
直接注入 private Consul.AspNetCore.IConsulClientFactory consulClientFactory;
`创建 consul客户端 consulClientFactory.CreateClient();```