服务发现 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 发布部署问题

    运行环境      操作系统                  开发工具      frameworks     .Net Core SDK 版本             托管运行 本地        ...

  2. Form key length limit 2048 exceeded ,提交数据时,数据的键过长 或者是上传文件过大

    在ASP.NET Core MVC中,文件的key 默认最大为2048,文件上传的最大上传文件默认为20MB,如果我们想上传一些比较大的文件,就不知道怎么去设置了,没有了Web.Config我们应该如 ...

  3. 华为Python面试题

    最近在网上偶然看到此题: 有两个序列a,b,大小都为n,序列元素的值任意整形数,无序: 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小 经过一番思索,我试着用穷举法 ...

  4. IDEA安装及默认配置习惯配置(一)

    最新新转战IDEA,每次安装完需要做一些操作习惯的设置,在这里记录一下,下次安装可以快速上手用. 第一步,JAVA安装 JDK官方下载地址:https://www.oracle.com 下载JDK时根 ...

  5. 关于微信小程序获取多个formId的实现方法

    在此之前,很多人使用过form和button的多层嵌套来实现点击一次获取多个formId的目的,如下图所示,点击一次“提交”,可以获取到多个formId 但是在今年3月份,这个投机取巧的方法(算是微信 ...

  6. ccs编译.lib

    新建 New一个CCS Project Output type选择"Static Library" 添加源文件 右击工程 -> Add Files- 编译 编译生成的.lib ...

  7. css 布局方式

    布局方式 1 布局:设置元素在网页中的排列方式及显示效果 2 分类: 1 标准流布局(文档流,普通流,静态流) 是默认的布局方式 特点:将元素按照书写顺序及元素类型,从上至下,从左至右排列 2 浮动布 ...

  8. coding++ :MySQL函数——FIND_IN_SET()

    语法:FIND_IN_SET(str,strlist) 定义: 1). 假如字符串 str 在由N子链组成的字符串列表 strlist 中,则返回值的范围在1到N之间. 2). 一个字符串列表就是一个 ...

  9. nomn文件分析

    #encoding=gbk import os import re import math from os import path ''' 手动输入文件nmon文件路径,要截取的开始时间,结束时间 ' ...

  10. css中 禁止spa有点击状态

    <span class="an" onclick="selNum();"></span> var selNum = function() ...