Ocelot(三)- 服务发现

作者:markjiang7m2

原文地址:https://www.cnblogs.com/markjiang7m2/p/10907856.html

源码地址:https://gitee.com/Sevenm2/OcelotDemo

本文是我关于Ocelot系列文章的第三篇,主要是给大家介绍Ocelot的另一功能。与其说是给大家介绍,不如说是我们一起来共同探讨,因为我也是在一边学习实践的过程中,顺便把学习的过程记录下来罢了。

正如本文要介绍的服务发现,在Ocelot中本该是一个较小的功能,但也许大家也注意到,这篇文章距离我的上一篇文章也有一个星期了。主要是因为Ocelot的服务发现支持提供程序Consul,而我对Consul并不怎么了解,因此花了比较长的时间去倒弄Consul。因为这个是关于Ocelot的系列文章,所以我暂时也不打算在本文中详细介绍Consul的功能以及搭建过程了,可能会在完成Ocelot系列文章后,再整理一篇关于Consul的文章。

关于更多的Ocelot功能介绍,可以查看我的系列文章

本文中涉及案例的完整代码都可以从我的代码仓库进行下载。

Ocelot接口更新:进阶请求聚合

好了,也许大家有疑问,为什么在这里又会重提请求聚合的内容?

在上一篇文章Ocelot(二)- 请求聚合与负载均衡中,我曾说到进阶请求聚合中,由于Aggregate方法中提供的参数类型只有List<DownstreamResponse>,但DownstreamResponse中并没有关于ReRouteKeys的信息,所以处理返回结果时,并没有像Ocelot内部返回结果一样使用路由的Key作为属性。

然后,今天我注意到了Ocelot有新版本发布,于是我做了更新,从13.5.0更新到了13.5.1,然后居然是有意外惊喜。

接口方法Aggregate更新如下:

13.5.0

public interface IDefinedAggregator
{
Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses);
}

13.5.1

public interface IDefinedAggregator
{
Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses);
}

参数类型从List<DownstreamResponse>更改为List<DownstreamContext>。我们再来看看DownstreamContext

public class DownstreamContext
{
public DownstreamContext(HttpContext httpContext); public List<PlaceholderNameAndValue> TemplatePlaceholderNameAndValues { get; set; }
public HttpContext HttpContext { get; }
public DownstreamReRoute DownstreamReRoute { get; set; }
public DownstreamRequest DownstreamRequest { get; set; }
public DownstreamResponse DownstreamResponse { get; set; }
public List<Error> Errors { get; }
public IInternalConfiguration Configuration { get; set; }
public bool IsError { get; }
}

事实上,如果你有看过Ocelot内部处理请求聚合部分的代码,就会发现它使用的就是DownstreamContext,而如今Ocelot已经将这些路由,配置,请求,响应,错误等信息都开放出来了。哈哈,当然,GitHub上面的realease note,人家主要是为了让开发者能够捕获处理下游服务发生的错误,更多信息可以查看issue#892issue#890

既然如此,那我就按照它内部的输出结果来一遍,当然我这里没有严格按照官方处理过程,只是简单的输出。

public async Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses)
{
List<string> results = new List<string>();
var contentBuilder = new StringBuilder(); contentBuilder.Append("{"); foreach (var down in responses)
{
string content = await down.DownstreamResponse.Content.ReadAsStringAsync();
results.Add($"\"{down.DownstreamReRoute.Key}\":{content}");
}
//来自leader的声音
results.Add($"\"leader\":{{comment:\"我是leader,我组织了他们两个进行调查\"}}"); contentBuilder.Append(string.Join(",", results));
contentBuilder.Append("}"); var stringContent = new StringContent(contentBuilder.ToString())
{
Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
}; var headers = responses.SelectMany(x => x.DownstreamResponse.Headers).ToList();
return new DownstreamResponse(stringContent, HttpStatusCode.OK, headers, "some reason");
}

输出结果:

官方开放了这么多信息,相信开发者还可以使用进阶请求聚合做更多的东西,欢迎大家继续研究探讨,我这里就暂时介绍到这里了。

案例四 服务发现

终于到我们今天的正题——服务发现。关于服务发现,我的个人理解是在这个微服务时代,当下游服务太多的时候,我们就需要找一个专门的工具记录这些服务的地址和端口等信息,这样会更加便于对服务的管理,而当上游服务向这个专门记录的工具查询某个服务信息的过程,就是服务发现。

举个例子,以前我要找的人也就只有Willing和Jack,所以我只要自己用本子(数据库)记住他们两个的位置就可以了,那随着公司发展,部门的人越来越多,他们经常会调换位置,还有入职离职的人员,这就导致我本子记录的信息没有更新,所以我找来了HR部门(Consul)帮忙统一管理,所有人有信息更新都要到HR部门那里进行登记(服务注册),然后当我(上游服务)想找人做某件事情(发出请求)的时候,我先到HR那里查询可以帮我完成这个任务的人员在哪里(服务发现),得到这些人员的位置信息,我也就可以选中某一个人帮我完成任务了。

这里会涉及到的记录工具,就是Consul。流程图如下:

当然了,在上面这个例子中好像没有Ocelot什么事,但是这样就需要我每次要找人的时候,都必须先跑到Consul那里查询一次位置信息,然后再根据位置信息去找对应的人。而其实这个过程我们是可以交给Ocelot来完成的。这样,每个下游服务都不需要单独跑一趟了,只专注于完成自己的任务就可以了。流程图如下:

通常当服务在10个以上的时候可以考虑使用服务发现。

关于Consul的介绍跟使用说明,网上已经有很多相关资料,所以我这里是基于大家都了解Consul的情况下的介绍。

官方建议每个Consul Cluster至少有3个或以上的运行在Server Mode的Agent,Client节点不限。由于我就这么一台机子,又不想搞虚拟机,所以我就直接用了Docker来部署使用Consul。

(可能这里又涉及到了一个Docker的知识点,我这里暂时也不展开细说了。)

因为我电脑的系统是Windows的,所以安装的Docker for Windows。

拉取镜像

Docker安装好之后,就用Windows自带的PowerShell运行下面的命令,拉取官方的Consul镜像。

docker pull consul

启动Consul

节点1

docker run -d -p 8500:8500 --name markserver1 consul agent -server -node marknode1 -bootstrap-expect 3 -data-dir=/tmp/consul -client="0.0.0.0" -ui

-ui 启用 WEB UI,因为Consul节点启动默认占用8500端口,因此8500:8500将节点容器内部的8500端口映射到外部8500,可以方便通过Web的方式查看Consul集群的状态。默认数据中心为dc1。

查看markserver1的IP

docker inspect -f '{{.NetworkSettings.IPAddress}}' markserver1

假设你们跟我一样,获取到的IP地址也是172.17.0.2

节点2

docker run -d --name markserver2 consul agent -server -node marknode2 -join 172.17.0.2

启动节点markserver2,并且将该节点加入到markserver1中(-join 172.17.0.2)

节点3

docker run -d --name markserver3 consul agent -server -node marknode3 -join 172.17.0.2

节点4以Client模式

docker run -d --name markclient1 consul agent -node marknode4 -join 172.17.0.2

没有-server参数,就会新建一个Client节点。

这个时候可以查看一下数据中心dc1的节点

docker exec markserver1 consul members

同时也可以在浏览器查看集群的状态。因为我在节点1中启动了WEB UI,而且映射到外部端口8500,所以我在浏览器直接访问http://localhost:8500/

OK,这样我们就已经启动了Consul,接下来就是将我们的下游服务注册到Consul中。

服务注册

为了能让本案例看到不一样的效果,我特意新建了一个下游服务方法。在OcelotDownAPI项目中的Controller添加

// GET api/ocelot/consulWilling
[HttpGet("consulWilling")]
public async Task<IActionResult> ConsulWilling(int id)
{
var result = await Task.Run(() =>
{
ResponseResult response = new ResponseResult()
{ Comment = $"我是Willing,你可以在Consul那里找到我的信息, host: {HttpContext.Request.Host.Value}, path: {HttpContext.Request.Path}" };
return response;
});
return Ok(result);
}

然后重新发布到本机上的8001和8002端口。

准备好下游服务后,就可以进行注册了。在PowerShell执行下面的命令:

<YourIP>为我本机的IP地址,大家使用时注意替换。这里需要使用IP,而不能直接用localhost或者127.0.0.1,因为我的Consul是部署在Docker里面的,所以当Consul进行HealthCheck时,就无法通过localhost访问到我本机了。

curl http://localhost:8500/v1/agent/service/register -Method PUT -ContentType 'application/json' -Body '{
"ID": "ocelotService1",
"Name": "ocelotService",
"Tags": [
"primary",
"v1"
],
"Address": "localhost",
"Port": 8001,
"EnableTagOverride": false,
"Check": {
"DeregisterCriticalServiceAfter": "90m",
"HTTP": "http://<YourIP>:8001/api/ocelot/5",
"Interval": "10s"
}
}'

我为了后面能实现负载均衡的效果,因此,也将8002端口的服务也一并注册进来,命令跟上面一样,只是要将端口号更换为8002就可以了。

多说一句,关于这个命令行,其实就是用命令行的方式调用Consul服务注册的接口,所以在实际项目中,可以将这个注册接口调用放在下游服务的Startup.cs中,当下游服务运行即注册,还有注销接口调用也是一样的道理。

服务发现

直接通过浏览器或者PowerShell命令行都可以进行服务发现过程。

浏览器访问http://localhost:8500/v1/catalog/service/ocelotService

或者命令行curl http://localhost:8500/v1/catalog/service/ocelotService

Ocelot添加Consul支持

OcelotDemo项目中安装Consul支持,命令行或者直接使用Nuget搜索安装

Install-Package Ocelot.Provider.Consul

在Startup.cs的ConfigureServices方法中

services
.AddOcelot()
.AddConsul()
.AddSingletonDefinedAggregator<LeaderAdvancedAggregator>();

Ocelot路由配置

首先在ReRoutes中添加一组路由

{
"DownstreamPathTemplate": "/api/ocelot/consulWilling",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/ocelot/consulWilling",
"UpstreamHttpMethod": [ "Get" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"ServiceName": "ocelotService",
"Priority": 2
}

可以发现这一组路由相对其它路由,少了DownstreamHostAndPorts,多了ServiceName,也就是这一组路由的下游服务,不是由Ocelot直接指定,而是通过Consul查询得到。

GlobalConfiguration添加ServiceDiscoveryProvider,指定服务发现支持程序为Consul。

"GlobalConfiguration": {
"BaseUrl": "http://localhost:4727",
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": 8500,
"Type": "Consul"
}
}

运行OcelotDemo,并在浏览器中访问http://localhost:4727/ocelot/consulWilling

因为我们在这组路由中配置了使用轮询的方式进行负载均衡,所以可以看到我们的访问结果中,是分别从8001和8002中轮询访问的。

除了支持Consul,Ocelot还支持Eureka,我这里暂时就不另外做案例了。

动态路由

当使用服务发现提供程序时,Ocelot支持使用动态路由。

上游服务请求Url模板:<Scheme>

Ocelot(三)- 服务发现的更多相关文章

  1. asp.net core系列 61 Ocelot 构建服务发现简单示例

    一.概述 Ocelot允许指定服务发现提供程序,如Consul或Eureka. 这二个中间件是用来实现:服务治理或秒服务发现,服务发现查找Ocelot正在转发请求的下游服务的主机和端口.目前Ocelo ...

  2. c# 微服务Ocelot网关服务发现

    前面提到微服务方案,介绍了该东西,推荐一篇介绍博文https://www.cnblogs.com/jesse2013/p/net-core-apigateway-ocelot-docs.html 我要 ...

  3. Ocelot + Consul + Registrator 基于Docker 实现服务发现、服务自动注册

    目录 1. Consul集群搭建 1.1 F&Q Consul官方推荐的host网络模式运行 2. Registrator服务注册工具 2.1 F&Q Registrator悬挂服务 ...

  4. .net core Ocelot Consul 实现API网关 服务注册 服务发现 负载均衡

    大神张善友 分享过一篇 <.NET Core 在腾讯财付通的企业级应用开发实践>里面就是用.net core 和 Ocelot搭建的可扩展的高性能Api网关. Ocelot(http:// ...

  5. .net5+nacos+ocelot 配置中心和服务发现实现

    最近一段时间 因公司业务需要,需要使用.net5做一套微服务的接口,使用nacos 做注册中心和配置中心,ocelot做网关. 因为ocelot 支持的是consol和eureka,如果使用nacos ...

  6. .net core使用ocelot---第七篇 服务发现

    简介 .net core使用ocelot---第一篇 简单使用   .net core使用ocelot---第二篇 身份验证使用  .net core使用ocelot---第三篇 日志记录  .net ...

  7. 服务发现和注册和Eureka

    一 Spring Cloud特点 # 约定优于配置 # 开箱即用,快速启动 # 适用于各种环境,可以部署在PC server或者 云环境 # 轻量级的组件 # 组件的支持很丰富,功能齐全 # 选型中立 ...

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

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

  9. Ocelot简易教程(四)之请求聚合以及服务发现

    上篇文章给大家讲解了Ocelot的一些特性并对路由进行了详细的介绍,今天呢就大家一起来学习下Ocelot的请求聚合以及服务发现功能.希望能对大家有所帮助. 作者:依乐祝 原文地址:https://ww ...

随机推荐

  1. 是否可以重定向到 WEB-INFO 下的页面?

    redirect的路径一定不能在WEB-INF路径下,因为redirect是相当于用户直接访问了路径,而用户不能访问WEB-INF目录下的文件,只有程序内部转发的时候才能转发到WEB-INF下的JSP ...

  2. django-pagination分页

    1. 将该APP安装至Django项目中.(settings.py) INSTALLED_APPS = ( # ... 'pagination', ) 2. 在Django项目的middleware中 ...

  3. PostgreSQL正则及模糊查询优化

    1.带前缀的模糊查询  ~'^abc' 可以使用btree索引优化 create index idx_info on table_name(info) 2.带后缀的模糊查询  ~'abc$' 可以使用 ...

  4. html中Meta属性

    <!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --> <html lang="zh-cmn-Hans"&g ...

  5. loj517 计算几何瞎暴力

    在序列上维护4个操作 1.在序列的尾端添加x 2.输出Al~Ar的和 3.将所有数异或x 4.将序列从小到大排序 第一眼看上去是Splay于是头铁硬刚了一发 后来发现splay没法异或 去百度“维护异 ...

  6. bzoj 2084: Antisymmetry 回文自动机

    题目: Description 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作"反对称"字符串.比如00001111和010101就是反对称的 ...

  7. nginx uwsgi wsgi django 这些东西究竟是什么关系

    有太多的文章告诉我们nginx uwsgi django 这些东西怎么用了,太多的人知道这些东西的怎么使用,怎么配置,怎么优化,但是还是有一部分人比如我这种水货不知道这些东西到底是啥,为啥一个项目的发 ...

  8. JS图表工具 ---- Highcharts

    Highcharts 是一个用纯 JavaScript编写的一个图表库, 能够很简单便捷的在web网站或是 web 应用程序添加有交互性的图表,并且免费提供给个人学习.个人网站和非商业用途使用. Hi ...

  9. VBA中的函数Timer用法

    第1.40例 Timer 函数一.题目: 要求编写一段代码,运用 Timer 函数来计算本代码运行所化的时间.二.代码:Sub 示例_1_040()    Dim t, i&, a    t ...

  10. Linux下eclipse及mysql安装,c++访问mysql数据库

    这两天在学习linux下用c++访问mysql,碰到一堆问题,记录一下. 1.mysql安装: 公司的电脑是64位的,安装的是64为的RHEL4,安装如下三个包: MySQL-client-5.1.4 ...