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 - .Net Core开源网关

  • Ocelot(二)- 请求聚合与负载均衡

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

  • 仓库地址:https://gitee.com/Sevenm2/OcelotDemo

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

  1. public interface IDefinedAggregator

  2. {

  3. Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses);

  4. }

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

  1. public class DownstreamContext

  2. {

  3. public DownstreamContext(HttpContext httpContext);


  4. public List<PlaceholderNameAndValue> TemplatePlaceholderNameAndValues { get; set; }

  5. public HttpContext HttpContext { get; }

  6. public DownstreamReRoute DownstreamReRoute { get; set; }

  7. public DownstreamRequest DownstreamRequest { get; set; }

  8. public DownstreamResponse DownstreamResponse { get; set; }

  9. public List<Error> Errors { get; }

  10. public IInternalConfiguration Configuration { get; set; }

  11. public bool IsError { get; }

  12. }

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

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

  1. public async Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses)

  2. {

  3. List<string> results = new List<string>();

  4. var contentBuilder = new StringBuilder();


  5. contentBuilder.Append("{");


  6. foreach (var down in responses)

  7. {

  8. string content = await down.DownstreamResponse.Content.ReadAsStringAsync();

  9. results.Add($"\"{down.DownstreamReRoute.Key}\":{content}");

  10. }

  11. //来自leader的声音

  12. results.Add($"\"leader\":{{comment:\"我是leader,我组织了他们两个进行调查\"}}");


  13. contentBuilder.Append(string.Join(",", results));

  14. contentBuilder.Append("}");


  15. var stringContent = new StringContent(contentBuilder.ToString())

  16. {

  17. Headers = { ContentType = new MediaTypeHeaderValue("application/json") }

  18. };


  19. var headers = responses.SelectMany(x => x.DownstreamResponse.Headers).ToList();

  20. return new DownstreamResponse(stringContent, HttpStatusCode.OK, headers, "some reason");

  21. }

输出结果:

640?wx_fmt=png

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

案例四 服务发现

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

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

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

640?wx_fmt=png

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

640?wx_fmt=png

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

关于Consul的介绍跟使用说明,网上已经有很多相关资料,所以我这里是基于大家都了解Consul的情况下的介绍。
官方建议每个Consul Cluster至少有3个或以上的运行在Server Mode的Agent,Client节点不限。由于我就这么一台机子,又不想搞虚拟机,所以我就直接用了Docker来部署使用Consul。
(可能这里又涉及到了一个Docker的知识点,我这里暂时也不展开细说了。)

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

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

  1. docker pull consul

启动Consul
节点1

  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

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

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

节点2

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

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

节点3

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

节点4以Client模式

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

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

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

  1. docker exec markserver1 consul members

640?wx_fmt=png

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

640?wx_fmt=png

640?wx_fmt=png

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

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

  1. // GET api/ocelot/consulWilling

  2. [HttpGet("consulWilling")]

  3. public async Task<IActionResult> ConsulWilling(int id)

  4. {

  5. var result = await Task.Run(() =>

  6. {

  7. ResponseResult response = new ResponseResult()

  8. { Comment = $"我是Willing,你可以在Consul那里找到我的信息, host: {HttpContext.Request.Host.Value}, path: {HttpContext.Request.Path}" };

  9. return response;

  10. });

  11. return Ok(result);

  12. }

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

准备好下游服务后,就可以进行注册了。在PowerShell执行下面的命令:
<YourIP>为我本机的IP地址,大家使用时注意替换。这里需要使用IP,而不能直接用localhost或者127.0.0.1,因为我的Consul是部署在Docker里面的,所以当Consul进行HealthCheck时,就无法通过localhost访问到我本机了。

  1. curl http://localhost:8500/v1/agent/service/register -Method PUT -ContentType 'application/json' -Body '{

  2. "ID": "ocelotService1",

  3. "Name": "ocelotService",

  4. "Tags": [

  5. "primary",

  6. "v1"

  7. ],

  8. "Address": "localhost",

  9. "Port": 8001,

  10. "EnableTagOverride": false,

  11. "Check": {

  12. "DeregisterCriticalServiceAfter": "90m",

  13. "HTTP": "http://<YourIP>:8001/api/ocelot/5",

  14. "Interval": "10s"

  15. }

  16. }'

640?wx_fmt=png

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

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

640?wx_fmt=png

640?wx_fmt=png

服务发现
直接通过浏览器或者PowerShell命令行都可以进行服务发现过程。
浏览器访问 http://localhost:8500/v1/catalog/service/ocelotService
或者命令行 curl http://localhost:8500/v1/catalog/service/ocelotService

640?wx_fmt=png

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

  1. Install-Package Ocelot.Provider.Consul

在Startup.cs的 ConfigureServices方法中

  1. services

  2. .AddOcelot()

  3. .AddConsul()

  4. .AddSingletonDefinedAggregator<LeaderAdvancedAggregator>();

Ocelot路由配置
首先在 ReRoutes中添加一组路由

  1. {

  2. "DownstreamPathTemplate": "/api/ocelot/consulWilling",

  3. "DownstreamScheme": "http",

  4. "UpstreamPathTemplate": "/ocelot/consulWilling",

  5. "UpstreamHttpMethod": [ "Get" ],

  6. "LoadBalancerOptions": {

  7. "Type": "RoundRobin"

  8. },

  9. "ServiceName": "ocelotService",

  10. "Priority": 2

  11. }

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

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

  1. "GlobalConfiguration": {

  2. "BaseUrl": "http://localhost:4727",

  3. "ServiceDiscoveryProvider": {

  4. "Host": "localhost",

  5. "Port": 8500,

  6. "Type": "Consul"

  7. }

  8. }

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

640?wx_fmt=png

640?wx_fmt=png

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

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

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

上游服务请求Url模板: <Scheme>:// <BaseUrl>/ <ServiceName>/ <ApiPath>/

例如:http://localhost:4727/ocelotService/api/ocelot/consulWilling

当Ocelot接收到请求,会向Consul查询服务 ocelotService的信息,例如获取到对应IP为localhost,Port为8001,于是Ocelot会转发请求到 http://localhost:8001/api/ocelot/consulWilling.

Ocelot不支持动态路由与ReRoutes配置混合使用,因此,当我们要使用动态路由,就必须要保证 ReRoutes中没有配置任何路由。

来看 Ocelot.json的配置

  1. {

  2. "ReRoutes": [],

  3. "Aggregates": [],

  4. "GlobalConfiguration": {

  5. "BaseUrl": "http://localhost:4727",

  6. "ServiceDiscoveryProvider": {

  7. "Host": "localhost",

  8. "Port": 8500,

  9. "Type": "Consul"

  10. },

  11. "DownstreamScheme": "http"

  12. }

  13. }

这就是使用动态路由最简单的配置,当然,在这种模式下还支持RateLimitOptions,QoSOptions,LoadBalancerOptions和HttpHandlerOptions,DownstreamScheme等配置,也允许针对每个下游服务进行个性化设置,我这里不演示具体案例。

  1. {

  2. "ReRoutes": [],

  3. "Aggregates": [],

  4. "GlobalConfiguration": {

  5. "RequestIdKey": null,

  6. "ServiceDiscoveryProvider": {

  7. "Host": "localhost",

  8. "Port": 8500,

  9. "Type": "Consul",

  10. "Token": null,

  11. "ConfigurationKey": null

  12. },

  13. "RateLimitOptions": {

  14. "ClientIdHeader": "ClientId",

  15. "QuotaExceededMessage": null,

  16. "RateLimitCounterPrefix": "ocelot",

  17. "DisableRateLimitHeaders": false,

  18. "HttpStatusCode": 429

  19. },

  20. "QoSOptions": {

  21. "ExceptionsAllowedBeforeBreaking": 0,

  22. "DurationOfBreak": 0,

  23. "TimeoutValue": 0

  24. },

  25. "BaseUrl": null,

  26. "LoadBalancerOptions": {

  27. "Type": "LeastConnection",

  28. "Key": null,

  29. "Expiry": 0

  30. },

  31. "DownstreamScheme": "http",

  32. "HttpHandlerOptions": {

  33. "AllowAutoRedirect": false,

  34. "UseCookieContainer": false,

  35. "UseTracing": false

  36. }

  37. }

  38. }

运行结果如下:

640?wx_fmt=png

因为使用动态路由就要清空其它的路由配置,因此,我就不将动态路由这部分的配置commit到仓库中了,大家要使用的时候可将我案例中的配置直接复制到 Ocelot.json文件中即可。

总结

Ocelot发布13.5.1这个版本还是挺有惊喜的,而且正巧我刚做完请求聚合的案例,所以也方便大家实践。服务发现,就Ocelot而言只是很小的一个篇幅,因为确实只要配置几个参数就可以灵活运用了,但在于Consul提供程序,还有Docker,这两个都是新的知识点,对于已经接触过的朋友很快就能搭建出来,但对于还没玩过的朋友,就需要花点时间研究。
OK,今天就先跟大家介绍到这里,希望大家能持续关注我们。

640?wx_fmt=jpeg

640?wx_fmt=jpeg


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/315578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P3527 [POI2011]MET-Meteors 整体二分 + 树状数组

洛谷 题意&#xff1a; 思路&#xff1a; 考虑整体二分前&#xff0c;一定要思考一下直接二分怎么做。显然对每个城市&#xff0c;当<pos<pos<pos的时候收集不够足够的陨石&#xff0c;>pos>pos>pos的时候能收集足够多陨石&#xff0c;这个时候pospospos即…

Ocelot(二)- 请求聚合与负载均衡

作者&#xff1a;markjiang7m2原文地址&#xff1a;https://www.cnblogs.com/markjiang7m2/p/10865511.html源码地址&#xff1a;https://gitee.com/Sevenm2/OcelotDemo在上一篇Ocelot的文章中&#xff0c;我已经给大家介绍了何为Ocelot以及如何简单使用它的路由功能&#xff0…

「分布式系统理论」系列专题

如今互联网已经成为整个社会的基础设施&#xff0c;分布式系统并不是少数大公司的专属&#xff0c;所以分布式系统理论可能是你迟早需要掌握的知识。如果你是程序员&#xff0c;相信这些文章你肯定能看懂&#xff1b;如果你不是程序员&#xff0c;相信这些能使你能更懂程序员&a…

SQL Server 2012如何打开2016的profiler文件

作者&#xff1a;markjiang7m2原文地址&#xff1a;https://www.cnblogs.com/markjiang7m2/p/10980191.html背景在上星期&#xff0c;公司负责support的同事接到反馈说某个项目生产环境上的某个页面加载很慢&#xff0c;一般遇到这种问题&#xff0c;我们的support同事都会先上…

Codeforces Round #655 (Div. 2) E. Omkar and Last Floor 区间dp + 巧妙的状态设计

传送门 题意&#xff1a; 思路&#xff1a; 按照贪心的思路来考虑的话&#xff0c;显然是每一列111的个数越多越好&#xff0c;所以我们能放到一列就放到一列。设f[l][r]f[l][r]f[l][r]为在[l,r][l,r][l,r]内&#xff0c;区间全部都在里面的贡献。显然这个贡献就是全部落在[l…

AKS使用Azure File实现动态持久化存储

本文作者|搪瓷小娃娃本文来源|搪瓷小娃娃博客园如我们所知&#xff0c;Kubernetes通过 Volume 为集群中的容器提供存储&#xff0c;通过Persistent Volume 和 Persistent Volume Claim实现Volume 的静态供给和动态供给。Azure File和Azure Disk 也在Kubernetes 支持的动态供给 …

ASP.NET Core 应用程序状态

在ASP.NET Core中&#xff0c;由多种途径可以对应用程序状态进行管理&#xff0c;使用哪种途径&#xff0c;由检索状态的时机和方式决定。应用程序状态指的是用于描述当前状况的任意数据。包括全局和用户特有的数据。开发人员可以根据不同的因素来选择不同的方式存储状态数据&a…

Asp.net core使用MediatR进程内发布/订阅

1、背景最近&#xff0c;一个工作了一个月的同事离职了&#xff0c;所做的东西怼了过来。一看代码&#xff0c;惨不忍睹&#xff0c;一个方法六七百行&#xff0c;啥也不说了吧&#xff0c;实在没法儿说。介绍下业务场景吧&#xff0c;一个公共操作A&#xff0c;业务中各个地方…

[开源] FreeSql.Tools Razor 生成器

FreeSql 经过半年的开发和坚持维护&#xff0c;在 0.6.x 版本中完成了几大重要事件&#xff1a;1、按小包拆分&#xff0c;每个数据库实现为单独 dll&#xff1b;2、实现 .net framework 4.5 支持&#xff1b;3、同时支持 MySql.Data、MySqlConnector 的实现&#xff1b;4、自定…

WebAssembly和Blazor:解决了一个存在十年的老问题

本文要点WebAssembly 是一种新的客户端技术&#xff0c;可以在所有现代浏览器&#xff08;包括移动浏览器&#xff09;中实现近乎原生的性能&#xff0c;而且不需要插件。许多语言&#xff0c;包括 C、C#、Go 和 Rust&#xff0c;都可以编译成面向基于栈的 WebAssembly 虚拟机的…

《电商后台系统产品逻辑解析》学习笔记

文是我阅读《电商产品经理宝典&#xff1a;电商后台系统产品逻辑全解析》一书的学习笔记&#xff0c;为后续我司做家居电商后台系统储备相关领域的业务知识。一、支撑线后台概览“前端用户的一小步&#xff0c;后台系统的一大步”&#xff0c;平时常见的功能如购物车、优惠券等…

P3403 跳楼机 同余最短路

传送门 题意&#xff1a; 思路&#xff1a; 转换一下题目就是用若干x,y,zx,y,zx,y,z能凑出来多少个<h<h<h的数。先考虑两个数y,zy,zy,z的情况&#xff0c;我们如果能求出来这两个数能凑出来的数设为sumsumsum&#xff0c;让后sumkx<hsumkx<hsumkx<h求出来…

NopCommerce 4.2的安装与运行

、关于NopCommerceNopCommerce是国外ASP.Net领域一个高质量的B2C开源电商项目&#xff0c;最新版本4.2基于ASP.NET Core MVC 2.2和EF Core 2.2开发&#xff0c;其强大的功能特性和插件机制使其成为了.NET领域开源电商项目的标杆。当然&#xff0c;还有一些其他的开源电商项目如…

P1527 [国家集训队]矩阵乘法 整体二分 + 二维树状数组

传送门 题意&#xff1a; 思路&#xff1a; 算是个整体二分的板子啦&#xff0c;不过这个是二维的矩阵&#xff0c;我们只需要把一位树状数组改成二维的&#xff0c;让后动态维护单点加&#xff0c;区间查询前缀和即可。 //#pragma GCC optimize(2) #include<cstdio>…

应用性能问题解决实际案例

某项目在上线前的APT&#xff08;Application Performance Testing应用程序性能测试&#xff09;过程中发现性能问题&#xff0c;性能测试结果影响是否上线&#xff0c;紧急求助外部项目组技术专家。因分属不同项目&#xff0c;只能通过项目组提供的信息进行分析。第一轮评审现…

Worker Service in ASP .NET Core

介绍提到 ASP.NET Core&#xff0c;我们多半会想到 ASP.NET MVC、ASP.NET Web API、Razor page 及 Blazor。随着 .NET Core 3.0 的推出&#xff0c;今天会介绍一个全新推出的功能&#xff1a;Work Service 。我们可以在 Visual Studio 2019 中通过预定的项目模版快速创建一个 W…

ASP.NET Core 奇淫技巧之动态WebApi

一.前言接触到动态WebApi&#xff08;Dynamic Web API&#xff09;这个词的已有几年&#xff0c;是从ABP框架里面接触到的&#xff0c;当时便对ABP的这个技术很好奇&#xff0c;后面分析了一波&#xff0c;也尝试过从ABP剥离一个出来作为独立组件来使用&#xff0c;可是后来因与…

Codeforces Round #693 (Div. 3) E. Correct Placement 思维

传送门 题意&#xff1a; 思路&#xff1a; 对于每个人都有个二元组(x,y)(x,y)(x,y)&#xff0c;从题意中提取有效信息就是&#xff1a;当(x1,y1)(x_1,y_1)(x1​,y1​)的最大值大于(x2,y2)(x_2,y_2)(x2​,y2​)的最大值&#xff0c;(x1,y1)(x_1,y_1)(x1​,y1​)的最小值大于(…

程序员过关斩将--你为什么还在用存储过程?

点击上面“蓝字”关注&#xff0c;带你看好电影菜菜哥&#xff0c;我新接手了一个项目&#xff0c;看的我头疼呀业务有这么复杂呀&#xff1f;不是的&#xff0c;这个老项目完全是用存储过程写的&#xff0c;每个存储过程都好几百行这样呀&#xff0c;是够头疼的~有没有办法帮我…

Educational Codeforces Round 101 (Rated for Div. 2) C. Building a Fence 思维取范围

传送门 题意&#xff1a; 思路&#xff1a; 刚看到这个题其实是没什么思路&#xff0c;想过从前往后推或者从后往前推&#xff0c;但是都不是很可行。因为两边都有一个固定的挡板挡住&#xff0c;我们可以根据其中的一个算出来每个位置高度的范围&#xff0c;让后检查一下范…