服务发现 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. AngularJS视图 ng-view

    AngularJS支持通过在单个页面上的多个视图的单页应用.要做到这一点AngularJS提供ng-view 和 ng-template指令,以及 $routeProvider 服务. ng-view ...

  2. Apache ---- Solrl漏洞复现

    Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口.用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引:也可以通过Http Get操 ...

  3. 基于【 centos7】五 || GitLab环境搭建

    一.基于Docker部署GitLab环境搭建 1.下载镜像 docker pull beginor/gitlab-ce:11.0.1-ce.0 2.创建GitLab 的配置 (etc) . 日志 (l ...

  4. 两个重叠的div做前后翻转

    当需要做一个翻转卡片式的div时候,需要两个div的大小等大例如: 画出两个等大的div后,将他们重叠 图中的两个div做了重叠,做重叠时候用的属性是 position: absolute; 并且需要 ...

  5. main函数前后

    void f1(void)__attribute__((constructor)); void f2(void)__attribute__((destructor)); void f1(void) { ...

  6. List · leetcode-24. 交换相邻节点

    题面 Given a linked list, swap every two adjacent nodes and return its head. You may not modify the va ...

  7. 查看SVN当前登录用户

    一般用户登录svn并记住用户密码后,下次再登录的时候将不需要输入用户密码,导致电脑使用着登录的时候,不知道到底登录的是个用户,只能将数据清除,现在给出查看登录用户的方法. 记录svn登录用户的文件,存 ...

  8. STUN/TURN服务器搭建

    目录 STUN/TURN服务器搭建 编译安装 配置使用 添加用户 启动server 测试 开机启动 参考 STUN/TURN服务器搭建 编译安装 编译安装 OpenSSL: sudo apt-get ...

  9. 用python文件操作实现复制图片、视频

    图片复制 打开源图片: f_src = open('1.jpg','rb') 读取图片内容并存储到content变量 content = f_src.read() 打开复制后的图片,没有则创建 f_c ...

  10. 【2017-07-03】JS连续删除table中的选中的多行数据

    deleteRow() 连续删除多行 应用:删除表格选中的一行或多行.html代码如下: <table > <tr> <td >复选框</td> < ...