服务发现 Consul

一、安装和启动

下载 [Consul](https://www.consul.io/downloads.html)

下载完成后,解压,只有一个consul.exe,把目录添加到环境变量的PATH,注意添加到系统变量,仅仅加入用户变量不起作用。打开cmd,输入

consul agen -dev  // 启动Consul服务

二、在aspnetcore中注册Consul

1. 定义配置项
/// <summary>
/// Consul配置
/// </summary>
public class ConsulOptions
{
/// <summary>
/// Consul服务器的地址
/// </summary>
public string HttpEndPoint { get; set; } /// <summary>
/// 数据中心名称
/// </summary>
public string DataCenter { get; set; } /// <summary>
/// Dns服务器端点
/// </summary>
public DnsEndPoint DnsEndPoint { get; set; }
}
/// <summary>
/// Dns节点
/// </summary>
public class DnsEndPoint
{
/// <summary>
/// 服务器地址
/// </summary>
public string Address { get; set; } /// <summary>
/// 端口
/// </summary>
public int Port { get; set; } /// <summary>
/// 转换为IpEndPoint
/// </summary>
/// <returns></returns>
public IPEndPoint ToIpEndPoint()
{
return new IPEndPoint(IPAddress.Parse(Address), Port);
}
}
public class ServiceDiscoveryOptions
{
/// <summary>
/// 服务名称
/// </summary>
public string ServiceName { get; set; } /// <summary>
/// Consul配置
/// </summary>
public ConsulOptions Consul { get; set; }
}
2. 在appsettings.json中添加配置
"ServiceDiscovery": {
"ServiceName": "webapi1",
"Consul": {
"DataCenter": "dc1",
"HttpEndPoint": "http://127.0.0.1:8500",
"DnsEndPoint": {
"Address": "127.0.0.1",
"Port": 8600
}
}
}
3. 在startup中注册配置项
services.Configure<ServiceDiscoveryOptions>(
Configuration.GetSection("ServiceDiscovery"));
4. 注册IConsulClient服务
services.AddSingleton<IConsulClient>(new ConsulClient(config =>
{
config.Address = new Uri(Configuration["ServiceDiscovery:Consul:HttpEndPoint"]);
config.Datacenter = Configuration["ServiceDiscovery:Consul:DataCenter"];
}));
5. 在Configure中将自身注册到Consul服务
ILifeTime的ApplicationStarted,程序启动时注册到Consul,
使用IApplicationBuilder的Feature获取当前启动的ip和端口,作为服务的ID
public static class ApplicationBuilderExtensions
{
/// <summary>
/// 获取当前启动应用绑定的IP和端口
/// </summary>
public static IEnumerable<Uri> GetAddress(this IApplicationBuilder app)
{
var features = app.Properties["server.Features"] as FeatureCollection;
return features?.Get<IServerAddressesFeature>()
.Addresses.Select(p => new Uri(p)) ?? new List<Uri>();
}
}
public void Configure(
IApplicationBuilder app, IHostingEnvironment env,
IApplicationLifetime lifetime, IConsulClient consul,
IOptions<ServiceDiscoveryOptions> serviceDiscoveryOptions)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} lifetime.ApplicationStarted.Register(() =>
{
var addresses = app.GetAddress();
foreach (var address in addresses)
{
var serviceId =
$"{serviceDiscoveryOptions.Value.ServiceName}_{address.Host}:{address.Port}"; consul.Agent.ServiceRegister(new AgentServiceRegistration
{
ID = serviceId,
Name = serviceDiscoveryOptions.Value.ServiceName,
Address = address.Host,
Port = address.Port,
Check = new AgentServiceCheck
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
Interval = TimeSpan.FromSeconds(5),
HTTP = new Uri(address, "api/Health/Check").OriginalString,
Timeout = TimeSpan.FromSeconds(5)
}
}).Wait(); lifetime.ApplicationStopped.Register(() =>
{
consul.Agent.ServiceDeregister(serviceId).Wait();
});
}
}); app.UseAuthentication(); app.UseMvc();
}

三、在项目中使用Consul

1、 定义一个接口
public interface IServiceDiscoveryManager
{
string GetApi(string serviceName);
}
2、 实现一个Consul的服务发现工具
public class ConsulServiceDiscoveryManager : IServiceDiscoveryManager
{
private readonly IConsulClient _client; private readonly ILogger<ConsulServiceDiscoveryManager> _logger; // 手动高亮,忽略大小写,这个很重要
private readonly ConcurrentDictionary<string, List<string>> _dict =
new ConcurrentDictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase); private DateTime _syncTime = DateTime.Now.AddMinutes(-11); private static object _lock = new object(); public ConsulServiceDiscoveryManager(IConsulClient client, ILogger<ConsulServiceDiscoveryManager> logger)
{
_client = client;
_logger = logger;
} private ConcurrentDictionary<string, List<string>> GetAllServices()
{
if (_syncTime < DateTime.Now.AddSeconds(-10) || !_dict.Keys.Any())
{
_dict.Clear();
var services = _client.Agent.Services().Result.Response.Select(s => s.Value).GroupBy(s => s.Service);
foreach (var service in services)
{
_dict.TryAdd(service.Key, service.Select(s => $"{s.Address}:{s.Port}").ToList());
}
_syncTime = DateTime.Now;
}
return _dict;
} public List<string> GetApis(string serviceName)
{
if(!GetAllServices().TryGetValue(serviceName, out var hosts))
{
return new List<string>();
}
return hosts;
} public string GetApi(string serviceName)
{
var hosts = GetApis(serviceName); var count = hosts.Count();
if(count == 0)
{
return string.Empty;
}
else if(count == 1)
{
return hosts.First();
} var ran = new Random().Next(0, count);
return hosts.ElementAt(ran);
}
}
3、 在ConfigureServices中注册IServiceDiscoveryManager。
捎带把 IHttpConlientFactory 也注册掉,
注意在 appsettings.json 里把之前的 ServiceDiscoverty 的配置项添加进去,
也可以只添加Consul的部分
services.AddSingleton<IConsulClient>(new ConsulClient(config =>
{
config.Address = new Uri(Configuration["ServiceDiscovery:Consul:HttpEndPoint"]);
config.Datacenter = Configuration["ServiceDiscovery:Consul:DataCenter"];
})); services.AddSingleton<IServiceDiscoveryManager, ConsulServiceDiscoveryManager>(); services.AddHttpClient();
4、 在Controller中使用,也可以封装一个Client,后面可以直接用。
public class TestController : Controller
{
private readonly ILogger<TestController> _logger;
private readonly IHttpClientFactory _clientFactory;
private readonly IServiceDiscoveryManager _serviceDiscoveryManager; public TestController(ILogger<TestController> logger,
IConsulClient consul,
IHttpClientFactory clientFactory,
IServiceDiscoveryManager serviceDiscoveryManager)
{
_logger = logger;
_clientFactory = clientFactory;
_serviceDiscoveryManager = serviceDiscoveryManager;
} public IActionResult Index()
{
var apiHost = _serviceDiscoveryManager.GetApi("WebApi1");
using(var client = _clientFactory.CreateClient())
{
var result = client.GetAsync($"http://{apiHost}/api/values").Result;
return Content(result.Content.ReadAsStringAsync().Result);
}
}
}

Ocelot 集成 Consul

一、 引入Nuget包
Ocelot
Ocelot.Provider.Consul
二、 在根目录下创建ocelog.json
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{url}",
"DownstreamScheme": "http",
"UseServiceDiscovery": true,
"ServiceName": "WebApi1",
"LoadBalancerOptions": {
"Type": "RoundRobin" //轮询
},
"UpstreamPathTemplate": "/WebApi1/{url}",
"UpstreamHttpMethod": [ "Get", "Post" ]
}
],
"GlobalConfiguration": {
"BaseUrl": "http://127.0.0.1:5010",
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": 8500,
"Type": "Consul"
}
}
}
三、 修改Program.cs,把刚刚创建好的ocelot.json添加到配置项
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(configuration =>
{
configuration.AddJsonFile("ocelot.json");
})
.UseUrls("http://localhost:5010")
.UseStartup<Startup>();
四、 修改Startup,注册服务,使用ocelot的中间件
public void ConfigureServices(IServiceCollection services)
{
services.AddOcelot().AddConsul();
} public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
} app.UseOcelot().Wait();
}
五、 一个比较全的配置项说明
{
"ReRoutes": [
{//官方文档ReRoutes全节点示例
//Upstream表示上游请求,即客户端请求到API Gateway的请求
"UpstreamPathTemplate": "/", //请求路径模板
"UpstreamHttpMethod": [ //请求方法数组
"Get"
], //Downstreamb表示下游请求,即API Gateway转发的目标服务地址
"DownstreamScheme": "http", //请求协议,目前应该是支持http和https
"DownstreamHost": "localhost", //请求服务地址,应该是可以是IP及域名
"DownstreamPort": 51779, //端口号
"DownstreamPathTemplate": "/", //下游请求地址模板
"RouteClaimsRequirement": { //标记该路由是否需要认证
"UserType": "registered" //示例,K/V形式,授权声明,授权token中会包含一些claim,如填写则会判断是否和token中的一致,不一致则不准访问
},
//以下三个是将access claims转为用户的Header Claims,QueryString,该功能只有认证后可用
"AddHeadersToRequest": { //
"UserType": "Claims[sub] > value[0] > |", //示例
"UserId": "Claims[sub] > value[1] > |"//示例
},
"AddClaimsToRequest": {},
"AddQueriesToRequest": {}, "RequestIdKey": "", //设置客户端的请求标识key,此key在请求header中,会转发到下游请求中
"FileCacheOptions": { //缓存设置
"TtlSeconds": 15, //ttl秒被设置为15,这意味着缓存将在15秒后过期。
"Region": "" //缓存region ,可以使用administrator API清除
},
"ReRouteIsCaseSensitive": false, //路由是否匹配大小写
"ServiceName": "", //服务名称,服务发现时必填 "QoSOptions": { //断路器配置,目前Ocelot使用的Polly
"ExceptionsAllowedBeforeBreaking": 0, //打开断路器之前允许的例外数量。
"DurationOfBreak": 0, //断路器复位之前,打开的时间(毫秒)
"TimeoutValue": 0 //请求超时时间(毫秒)
},
"LoadBalancerOptions": {
"type": "RoundRobin" // 负载均衡 RoundRobin(轮询)/LeastConnection(最少连接数)
},
"RateLimitOptions": { //官方文档未说明
"ClientWhitelist": [], // 白名单
"EnableRateLimiting": false, // 是否限流
"Period": "1m", // 1s,4m,1h,1d
"PeriodTimespan": 0, // 多少秒之后客户端可以充实
"Limit": 0 // 一个时间周期最多可以请求的次数
},
"AuthenticationOptions": { //认证配置
"AuthenticationProviderKey": "", //这个key对应的是代码中.AddJWTBreark中的Key
"AllowedScopes": []//使用范围
},
"HttpHandlerOptions": {
"AllowAutoRedirect": true, //指示请求是否应该遵循重定向响应。 如果请求应该自动遵循来自Downstream资源的重定向响应,则将其设置为true; 否则为假。 默认值是true。
"UseCookieContainer": true //该值指示处理程序是否使用CookieContainer属性来存储服务器Cookie,并在发送请求时使用这些Cookie。 默认值是true。
},
"UseServiceDiscovery": false //使用服务发现,目前Ocelot只支持Consul的服务发现
}
],
"GlobalConfiguration": {}
}
六、 再来一个简单的不使用Consul的配置项
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{url}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5001
},
{
"Host": "localhost",
"Port": 5002
}
],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"UpstreamPathTemplate": "/UserService/{url}",
"UpstreamHttpMethod": [ "Get", "Post" ]
}
]
}
七、熔断
引入Nuget包
Ocelot.Provider.Polly

Ocelot 网关 和 consul 服务发现的更多相关文章

  1. 微服务(入门三):netcore ocelot api网关结合consul服务发现

    简介 api网关是提供给外部调用的统一入口,类似于dns,所有的请求统一先到api网关,由api网关进行指定内网链接. ocelot是基于netcore开发的开源API网关项目,功能强大,使用方便,它 ...

  2. 微服务之:从零搭建ocelot网关和consul集群

    介绍 微服务中有关键的几项技术,其中网关和服务服务发现,服务注册相辅相成. 首先解释几个本次教程中需要的术语 网关 Gateway(API GW / API 网关),顾名思义,是企业 IT 在系统边界 ...

  3. Ocelot(三)- 服务发现

    Ocelot(三)- 服务发现 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/10907856.html 源码地址:https ...

  4. 基于Docker的Consul服务发现集群搭建

    在去年的.NET Core微服务系列文章中,初步学习了一下Consul服务发现,总结了两篇文章.本次基于Docker部署的方式,以一个Demo示例来搭建一个Consul的示例集群,最后给出一个HA的架 ...

  5. Ocelot中文文档-服务发现

    Ocelot允许您指定服务发现提供程序,并使用它来查找Ocelot正在将请求转发给下游服务的主机和端口.目前,这仅在GlobalConfiguration部分中受支持,这意味着所有ReRoute将使用 ...

  6. Ocelot(十一)- 服务发现

    Ocelot允许您指定服务发现提供程序,并使用它来查找Ocelot正在将请求转发给下游服务的主机和端口.目前,这仅在GlobalConfiguration部分中受支持,这意味着所有ReRoute将使用 ...

  7. 学习搭建 Consul 服务发现与服务网格-有丰富的示例和图片

    目录 第一部分:Consul 基础 1,Consul 介绍 2,安装 Consul Ubuntu/Debian 系统 Centos/RHEL 系统 检查安装 3,运行 Consul Agent 启动 ...

  8. Redola.Rpc 集成 Consul 服务发现

    Redola.Rpc 解决了什么问题? Redola.Rpc 是一个使用 C# 开发的 RPC 框架,代码开源在 GitHub 上.目前版本仅支持 .NET Framework 4.6 以上版本,未来 ...

  9. .NET Core微服务实施之Consul服务发现与治理

    .NET Core微服务实施之Consul服务发现与治理   Consul官网:https://www.consul.io Consul下载地址:https://www.consul.io/downl ...

随机推荐

  1. .net Core CLR

    .net Core CLR是开源的.大部分文件是C++写成.这样他就可以编译后再不同的平台运行. https://github.com/dotnet/coreclr

  2. java 框架-分布式服务框架1ZooKeeper

    https://www.cnblogs.com/felixzh/p/5869212.html Zookeeper的功能以及工作原理   1.ZooKeeper是什么?ZooKeeper是一个分布式的, ...

  3. iOS自定义一个仿网易左右滑动切换页面框架

    FSScrollContentView github:https://github.com/shunFSKi/FSScrollContentView 这是本人在整理项目时抽离了业务代码整理封装的一个通 ...

  4. stm32 RS485 SP3485

    RS485 是半双工通信(2 线制) SP3485芯片的DE与RE短接在一起连接在STM32F1芯片的PG3上,通过PG3管脚就可以控制 SP3485的收发,当PG3=0时,为接收模式,当PG3=1时 ...

  5. 常用的virsh管理命令

    常用的virsh管理命令 列出所有的虚拟机 [root@ubuntu ~]# virsh list --all 显示虚拟机信息 [root@ubuntu ~]# virsh dominfo CentO ...

  6. Eclipse安装windowsbuilder

    详见:https://www.cnblogs.com/plusplus/p/9864708.html https://www.cnblogs.com/lsy-blogs/p/7717036.html ...

  7. 【Hibernate】持久化对象状态及以及缓存

    一.持久化类状态 1.1 三种持久化对象的状态 1.2 区分三种状态 1.3 三种状态对象转换 1.瞬时态 2.持久态 3.脱管态 4.持久态对象有自动更新数据库的能力 一.持久化类状态 1.1 三种 ...

  8. PAT Advanced 1022 Digital Library (30 分)

    A Digital Library contains millions of books, stored according to their titles, authors, key words o ...

  9. 用js刷剑指offer(调整数组顺序使奇数位于偶数前面)

    题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 牛客网链接 js代码 ...

  10. Road to Cinema(贪心+二分)

    https://www.cnblogs.com/flipped/p/6083973.html       原博客转载 http://codeforces.com/group/1EzrFFyOc0/co ...