Ocelot 网关 和 consul 服务发现
服务发现 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 服务发现的更多相关文章
- 微服务(入门三):netcore ocelot api网关结合consul服务发现
简介 api网关是提供给外部调用的统一入口,类似于dns,所有的请求统一先到api网关,由api网关进行指定内网链接. ocelot是基于netcore开发的开源API网关项目,功能强大,使用方便,它 ...
- 微服务之:从零搭建ocelot网关和consul集群
介绍 微服务中有关键的几项技术,其中网关和服务服务发现,服务注册相辅相成. 首先解释几个本次教程中需要的术语 网关 Gateway(API GW / API 网关),顾名思义,是企业 IT 在系统边界 ...
- Ocelot(三)- 服务发现
Ocelot(三)- 服务发现 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/10907856.html 源码地址:https ...
- 基于Docker的Consul服务发现集群搭建
在去年的.NET Core微服务系列文章中,初步学习了一下Consul服务发现,总结了两篇文章.本次基于Docker部署的方式,以一个Demo示例来搭建一个Consul的示例集群,最后给出一个HA的架 ...
- Ocelot中文文档-服务发现
Ocelot允许您指定服务发现提供程序,并使用它来查找Ocelot正在将请求转发给下游服务的主机和端口.目前,这仅在GlobalConfiguration部分中受支持,这意味着所有ReRoute将使用 ...
- Ocelot(十一)- 服务发现
Ocelot允许您指定服务发现提供程序,并使用它来查找Ocelot正在将请求转发给下游服务的主机和端口.目前,这仅在GlobalConfiguration部分中受支持,这意味着所有ReRoute将使用 ...
- 学习搭建 Consul 服务发现与服务网格-有丰富的示例和图片
目录 第一部分:Consul 基础 1,Consul 介绍 2,安装 Consul Ubuntu/Debian 系统 Centos/RHEL 系统 检查安装 3,运行 Consul Agent 启动 ...
- Redola.Rpc 集成 Consul 服务发现
Redola.Rpc 解决了什么问题? Redola.Rpc 是一个使用 C# 开发的 RPC 框架,代码开源在 GitHub 上.目前版本仅支持 .NET Framework 4.6 以上版本,未来 ...
- .NET Core微服务实施之Consul服务发现与治理
.NET Core微服务实施之Consul服务发现与治理 Consul官网:https://www.consul.io Consul下载地址:https://www.consul.io/downl ...
随机推荐
- 一篇文章彻底搞懂异步,同步,setTimeout,Promise,async
之前翻看别的大佬的博客看到了关于setTimeout,promise还有async执行顺序的文章.观看了几篇之后还是没有怎么看懂,于是自己开始分析代码,并整理了此文章,我相信通过此文章朋友们能对异步同 ...
- php 环境搭建问题
项目过程中需要用到 PHP环境 https://www.cnblogs.com/cyrfr/p/6483529.html APACHE无法启动:THE REQUEST OPERATION HAS FA ...
- Django rest-framework框架-组件之视图
视图: a. django class Test(View): ... b. rest_framework class Test(APIView): ... c. GenericAPIView 一般不 ...
- nodejs入门API之fs模块
fs模块下的类与FS常量 fs模块下的主要方法 fs的Promise API与FileHandle类 一.fs模块下的类 1.1 fs.Dir:表示目录流的类,由 fs.opendir().fs.op ...
- Java 之 Hashtable 集合
Hashtable 集合 java.util.Hashtable<K,V>集合 implements Map<K,V>接口 Hashtable:底层也是一个哈希表,是一个线 ...
- char str = '1.2.';问题
偶然看到群里老哥问道这个问题 #include <iostream> using namespace std; int main() { char str = '1.2.'; ; } 什么 ...
- vue v-cloak 指令 处理页面显示源码
有时候页面会先出现源码,再显示解析的内容.可以通过v-cloak解决 v-cloak 这个指令会作为元素的一个属性一直保持到vue实例编译结束,即解析后移除此指令. /* 含有v-cloak的html ...
- Image Processing and Analysis_15_Image Registration:a survey of image registration techniques——1992
此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...
- 【问题】bzip2 --version 2>&1 < /dev/null
https://unix.stackexchange.com/questions/230887/what-does-dev-null-mean https://stackoverflow.com/qu ...
- idou老师教你学Istio 28:istio-proxy check 的缓存
功能概述 istio-proxy主要的功能是连接istio的控制面组件和envoy之间的交互,其中check的功能是将envoy收集的attributes信息上报给mixer,在istio中有几十种a ...