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

作者:markjiang7m2
原文地址:https://www.cnblogs.com/markjiang7m2/p/10865511.html
源码地址:https://gitee.com/Sevenm2/OcelotDemo

在上一篇Ocelot的文章中,我已经给大家介绍了何为Ocelot以及如何简单使用它的路由功能,如果你还没有不了解Ocelot为何物,可以查看我的系列文章 Ocelot - .Net Core开源网关。在这篇文章中,我将会继续给大家介绍Ocelot的功能:请求聚合与负载均衡。

开篇题外话:在上一篇文章的案例中,我直接使用API返回服务器的端口和接口的路径,我感觉这样举例过于偏技术化,比较沉闷,然后我想到了之前参加PMP课程培训时候,我们的培训讲师——孙志斌老师引用 小王老李的模型给我们讲述项目管理的各种实战,可谓是生动形象,而且所举的例子也非常贴近我们的日常工作,通俗易懂,因此,我也尝试使用类似的人物形象进行案例的讲解。首先,本文将会引入两个人物 WillingJack。Willing是一名资深专家,工作多年,而Jack则是.NET新手。

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

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

案例二 请求聚合

我们在案例一路由中已经知道,Ocelot可以定义多组路由,然后根据优先级对上游服务发出的请求进行不同的转发处理,每个路由转发都匹配唯一的一个下游服务API接口。然而,有时候,上游服务想要获得来自两个API接口返回的结果。Ocelot允许我们在配置文件中声明聚合路由 Aggregates,从而实现这样的效果。
举个例子,有一天我的老板(用户)让我(上游服务)去了解清楚Willing和Jack两位同事对工作安排有什么意见(请求),当然了,我可以先跑去问Jack,然后再跑到Willing那里了解情况,可是这样我就要跑两趟,这样不划算啊,于是,我去找了他们的领导(聚合)说我老板想要了解他们两个的意见,他们领导一个电话打过去,Willing和Jack就都一起过来了,我也就很快完成了老板交代的任务。
在这个过程中,我是可以单独访问Willing或者Jack的,因此,他们是在 ReRoutes中声明的两组普通的路由,而他们的领导是在 Aggregates中声明的一组聚合路由。刚刚我们的举例当中,访问不同的人需要到达不同的地方,因此在声明路由时,也需要注意它们的 UpstreamPathTemplate都是不一样的。
下面是具体的路由配置:

"ReRoutes": [	
{	"DownstreamPathTemplate": "/api/ocelot/aggrWilling",	"DownstreamScheme": "http",	"DownstreamHostAndPorts": [	{	"Host": "localhost",	"Port": 8001	}	],	"UpstreamPathTemplate": "/ocelot/aggrWilling",	"UpstreamHttpMethod": [ "Get" ],	"Key": "aggr_willing",	"Priority": 2	
},	
{	"DownstreamPathTemplate": "/api/ocelot/aggrJack",	"DownstreamScheme": "http",	"DownstreamHostAndPorts": [	{	"Host": "localhost",	"Port": 8001	}	],	"UpstreamPathTemplate": "/ocelot/aggrJack",	"UpstreamHttpMethod": [ "Get" ],	"Key": "aggr_jack",	"Priority": 2	
}	
],	
"Aggregates": [	
{	"ReRouteKeys": [	"aggr_willing",	"aggr_jack"	],	"UpstreamPathTemplate": "/aggrLeader"	
}	
]

大家可以注意到,在 ReRoutes中声明的两组路由相比案例一不同的是,多加了一个 Key属性。 AggregatesReRoutes是同级的,而且也是一个数组,这代表着我们可以声明多个聚合路由,而在我们声明的这一组聚合路由中的属性 ReRouteKeys,它包含的元素就是我们真正需要响应的路由的 Key属性值。

当然,我们的下游服务也相应添加两个API接口。

  1. // GET api/ocelot/aggrWilling

  2. [HttpGet("aggrWilling")]

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

  4. {

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

  6. {

  7. return $"我是Willing,还是多加工资最实际, path: {HttpContext.Request.Path}";

  8. });

  9. return Ok(result);

  10. }

  11. // GET api/ocelot/aggrJack

  12. [HttpGet("aggrJack")]

  13. public async Task<IActionResult> AggrJack(int id)

  14. {

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

  16. {

  17. return $"我是Jack,我非常珍惜现在的工作机会, path: {HttpContext.Request.Path}";

  18. });

  19. return Ok(result);

  20. }

下面我们一起来看看执行的结果。

我们按照案例一,先单独来问问Jack。
640?wx_fmt=png

然后再看看直接通过聚合路由访问
640?wx_fmt=png

可以看到,在返回结果中同时包含了Willing和Jack的结果,并且是以 json串的格式返回,以路由的 Key属性值作为返回json的属性。

(返回的结果好像哪里不太对,不知道你是否发现了,但暂时先不要着急,我在后面会为大家揭晓)

需要注意的是,Ocelot仅支持 GET方式的请求聚合。Ocelot总是以 application/json的格式返回一个聚合请求的,当下游服务是返回404状态码,在返回结果中,其对应的值则为空值,即使聚合路由中所有的下游服务都返回404状态码,聚合路由的返回结果也不会是404状态码。

我们在不添加任何API接口的情况下,声明一组下游服务不存在的路由,并将它添加到聚合路由当中。

  1. "ReRoutes": [

  2. ...,

  3. {

  4. "DownstreamPathTemplate": "/api/ocelot/aggrError/1",

  5. "DownstreamScheme": "http",

  6. "DownstreamHostAndPorts": [

  7. {

  8. "Host": "localhost",

  9. "Port": 8001

  10. }

  11. ],

  12. "UpstreamPathTemplate": "/ocelot/aggrError/1",

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

  14. "Key": "aggr_error",

  15. "Priority": 2

  16. }

  17. ],

  18. "Aggregates": [

  19. {

  20. "ReRouteKeys": [

  21. "aggr_willing",

  22. "aggr_jack",

  23. "aggr_error"

  24. ],

  25. "UpstreamPathTemplate": "/aggrLeader"

  26. }

  27. ]

测试结果如下:

直接请求aggr_error
640?wx_fmt=png

直接通过聚合路由访问
640?wx_fmt=png

前面我说到返回结果好像有哪里不太对,那到底是哪里出错了呢?我来将返回的json串进行格式化一下。

  1. {

  2. "aggr_willing":我是Willing,还是多加工资最实际, path: /api/ocelot/aggrWilling,

  3. "aggr_jack":我是Jack,我非常珍惜现在的工作机会, path: /api/ocelot/aggrJack,

  4. "aggr_error":

  5. }

我们会发现这并不是一个正确的json串,那到底为什么会这样呢?既然Ocelot是开源的,那我们就来深挖一下源码到底是怎么处理聚合请求返回结果的。
Ocelot Github:https://github.com/ThreeMammals/Ocelot找到位于 Ocelot.Middleware.Multiplexer中的一个类 SimpleJsonResponseAggregator,静态方法 MapAggregateContent

  1. var content = await contexts[0].DownstreamResponse.Content.ReadAsStringAsync();

  2. contentBuilder.Append($"\"{responseKeys[k]}\":{content}");

因为我的下游服务返回结果是一个字符串,然后被Ocelot直接拼接到返回结果中,从而得到我们上面看到的结果。
因此,在我看来,当我们使用Ocelot的聚合路由功能时,下游服务的返回结果必须要保证是一个json串,这样才能最终被正确识别。

我把下游服务改一改,添加一个类,然后将API返回结果格式更改为这个类型。

  1. public class ResponseResult

  2. {

  3. public string Comment { get; set; }

  4. }

  1. // GET api/ocelot/aggrWilling

  2. [HttpGet("aggrWilling")]

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

  4. {

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

  6. {

  7. ResponseResult response = new ResponseResult()

  8. { Comment = $"我是Willing,还是多加工资最实际, path: {HttpContext.Request.Path}" };

  9. return response;

  10. //return $"我是Willing,还是多加工资最实际, path: {HttpContext.Request.Path}";

  11. });

  12. return Ok(result);

  13. }

  14. // GET api/ocelot/aggrJack

  15. [HttpGet("aggrJack")]

  16. public async Task<IActionResult> AggrJack(int id)

  17. {

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

  19. {

  20. ResponseResult response = new ResponseResult()

  21. { Comment = $"我是Jack,我非常珍惜现在的工作机会, path: {HttpContext.Request.Path}" };

  22. return response;

  23. //return $"我是Jack,我非常珍惜现在的工作机会, path: {HttpContext.Request.Path}";

  24. });

  25. return Ok(result);

  26. }

运行看执行结果
640?wx_fmt=png

简单总结为以下三点注意:

  • 仅支持 GET方式

  • 下游服务返回类型要求为application/json

  • 返回内容类型为application/json,不会返回404请求

进阶请求聚合

在上一个案例中,我已经可以通过Willing和Jack的领导得到我想要的结果,但在这个过程中,他们的领导(聚合)都只是在帮我获得结果,没有对得到的结果做任何的干预。那如果领导想着,既然老板想要了解情况,自己当然也要干点活,让老板知道在这个过程中自己也是有出力的,这就涉及到进阶的请求聚合了。

在网上搜了一下关于进阶请求聚合的资料,好像没有怎么见到有相关实例的Demo,最全面的资料来自于官网文档说明,也许是在实际应用中这个功能不怎么被运用?或是我打开的方式不对?原因暂时未知,知道的朋友们可以在留言区给我说一下。那么我在这里就用实例给大家介绍一下。

Ocelot支持在获得下游服务返回结果后,通过一个聚合器对返回结果进行再一步的加工处理,目前支持内容,头和状态代码的修改。我们来看配置文件

  1. "Aggregates": [

  2. {

  3. "ReRouteKeys": [

  4. "aggr_willing",

  5. "aggr_jack",

  6. "aggr_error"

  7. ],

  8. "UpstreamPathTemplate": "/aggrLeaderAdvanced",

  9. "Aggregator": "LeaderAdvancedAggregator"

  10. }

  11. ]

因为是请求聚合的进阶,所以 ReRoutes路由不需要任何更改。 Aggregates中一组配置增加了属性 Aggregator,表示当获得返回结果,由聚合器 LeaderAdvancedAggregator进行处理。

然后我在Ocelot项目中添加聚合器 LeaderAdvancedAggregator,要实现这个聚合器,就必须实现来自 Ocelot.Middleware.Multiplexer提供的接口 IDefinedAggregator

  1. public class LeaderAdvancedAggregator : IDefinedAggregator

  2. {

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

  4. {

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

  6. var contentBuilder = new StringBuilder();


  7. contentBuilder.Append("{");


  8. foreach (var down in responses)

  9. {

  10. string content = await down.Content.ReadAsStringAsync();

  11. results.Add($"\"{Guid.NewGuid()}\":{content}");

  12. }

  13. //来自leader的声音

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


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

  16. contentBuilder.Append("}");


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

  18. {

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

  20. };


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

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

  23. }

  24. }

当下游服务返回结果后,Ocelot就会调用聚合器的 Aggregate方法,因此,我们的处理代码就写在这个方法中。

之后,我们就需要将聚合器在容器中进行注册
Startup.cs

  1. services

  2. .AddOcelot()

  3. .AddSingletonDefinedAggregator<LeaderAdvancedAggregator>();

运行,访问进阶请求聚合的Url http://localhost:4727/aggrLeaderAdvanced,得到如下结果:
640?wx_fmt=png

也许大家已经留意到,我在处理返回结果是,并没有像Ocelot内部返回结果一样使用路由的 Key作为属性,而是使用了Guid。其实这也是我在做Demo时候的一处疑惑,我似乎无法像Ocelot内部一样处理。
在这个 Aggregate方法中提供的参数类型只有 List<DownstreamResponse>,但 DownstreamResponse中并没有关于 ReRouteKeys的信息。我查看了Ocelot的源码, ReRouteKeys只存在于 DownstreamReRoute中,但我无法通过 DownstreamResponse获取到 DownstreamReRoute
希望有知道的朋友能在留言区告诉我一下,感谢。

另外,这个聚合器也能像一般服务一样,可以使用依赖注入的方式添加依赖。我也尝试在案例中添加了一个依赖 LeaderAdvancedDependency。如何使用依赖注入,我这里就不细说了,大家可以搜索 .net core依赖注入的相关资料。
LeaderAdvancedAggregator.cs

  1. public LeaderAdvancedDependency _dependency;


  2. public LeaderAdvancedAggregator(LeaderAdvancedDependency dependency)

  3. {

  4. _dependency = dependency;

  5. }

Startup.cs

  1. services.AddSingleton<LeaderAdvancedDependency>();

这样,我们就可以在聚合器中使用依赖了。

Ocelot除了支持 Singleton的聚合器以外,还支持 Transient的聚合器,大家可以按需使用。
Startup.cs

  1. services

  2. .AddOcelot()

  3. .AddTransientDefinedAggregator<LeaderAdvancedAggregator>();

案例三 负载均衡

在前面的案例中,我们全部的路由配置中都是一组路由配置一个下游服务地址,也就意味着,当上游服务请求一个Url,Ocelot就必定转发给某一个固定的下游服务,但这样对于一个系统来说,这是不安全的,因为有可能某一个下游服务阻塞,甚至挂掉了,那就可能导致整个服务瘫痪了,对于当前快速运转的互联网时代,这是不允许的。

Ocelot能够通过可用的下游服务对每个路由进行负载平衡。我们来看看具体的路由配置

  1. {

  2. "DownstreamPathTemplate": "/api/ocelot/{postId}",

  3. "DownstreamScheme": "http",

  4. "DownstreamHostAndPorts": [

  5. {

  6. "Host": "localhost",

  7. "Port": 8001

  8. },

  9. {

  10. "Host": "localhost",

  11. "Port": 8002

  12. }

  13. ],

  14. "UpstreamPathTemplate": "/ocelot/{postId}",

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

  16. "LoadBalancerOptions": {

  17. "Type": "RoundRobin"

  18. }

  19. }

LeadConnection负载均衡器算法共有4种:

  • LeastConnection 把新请求发送到现有请求最少的服务上

  • RoundRobin 轮询可用的服务并发送请求

  • NoLoadBalancer 不负载均衡,总是发往第一个可用的下游服务

  • CookieStickySessions 使用cookie关联所有相关的请求到制定的服务

为了能快速验证负载均衡器的有效性,我们这个案例中采用了 RoundRobin轮询算法。然后下游服务还是用了案例一中建立的基本服务,在IIS中部署两套同样的下游服务,分别占用端口8001和8002。

当我们第一次请求 http://localhost:4727/ocelot/5,得到的是端口8001的返回结果

640?wx_fmt=png

而当我们再次请求 http://localhost:4727/ocelot/5,得到的是端口8002的返回结果

640?wx_fmt=png

再次请求则又是8001的返回结果,如此轮询下去。
但需要注意的是,当我尝试将8002端口服务停止时

640?wx_fmt=png

我得到了这样的结果:第一次请求得到8001的返回结果,第二次请求得到的则是500的状态码

640?wx_fmt=png

根据官网文档的说明

  1. RoundRobin - loops through available services and sends requests. The algorythm state is not distributed across a cluster of Ocelots.

的确说的是轮询可用的服务,似乎与我的测试结果不相符。不知道是我的测试环境出了问题,还是我某个环节配置错误,亦或是这个算法真的没有避开不可用的服务。希望有知道的朋友在留言区给我解惑,感谢。

在本案例中,我就不再展开演示另外3种算法了,其中 NoLoadBalancer会与服务发现的案例再进行深入探讨。

总结

本来今天是想给大家写多两个功能案例的,奈何这个进阶的资料实在不多,当然也有我自己一方面实力不足的原因,导致花了很长的时间进行消化。在本文中介绍了Ocelot的请求聚合与负载均衡,其中请求聚合在使用的过程中还是有几点需要注意的,负载均衡则需要大家按需选择适合自己系统的算法。后续还会有Ocelot的系列文章,希望大家持续关注。

640?wx_fmt=jpeg

640?wx_fmt=jpeg


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

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

相关文章

BZOJ #3064. Tyvj 1518 CPU监控(线段树,历史最值)

BZOJ #3064. Tyvj 1518 CPU监控(线段树&#xff0c;历史最值) Solution 我们考虑用线段树维护此题。 先不考虑历史最值。 大概需要维护一种特殊的懒标记(x,y)(x,y)(x,y)表示让区间内所有数ppp&#xff0c;pmax(px,y)pmax(px,y)pmax(px,y)。 对于区间加zzz&#xff0c;打一…

Codeforces Round #655 (Div. 2) B. Omkar and Last Class of Math 数学

传送门 题意&#xff1a; 找出ABnABnABn并且lcm⁡(A,B)\operatorname{lcm}(A,B)lcm(A,B)最小的AAA和BBB。 思路&#xff1a; nnn为偶数的时候答案肯定为都是n2\frac{n}{2}2n​。当nnn为奇数的时候&#xff0c;我们假设xxx为nnn的一个因子&#xff0c;那么nmodx0n \bmod x0nmo…

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

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

AGC002F - Leftmost Ball(dp,组合计数)

AGC002F - Leftmost Ball Solution 设fi,jf_{i,j}fi,j​表示放iii个白球&#xff0c;确定了jjj个颜色的球的位置的方案数。 有两种转移&#xff1a; 放白球&#xff0c;fi,j−>fi1,jf_{i,j}->f_{i1,j}fi,j​−>fi1,j​放完一种颜色的球&#xff0c;fi,j−>fi,j…

Codeforces Round #655 (Div. 2) D. Omkar and Circle 思维 + 奇偶贪心

传送门 题意&#xff1a; 给一个长为nnn的数组(nnn为奇数)&#xff0c;iii与i−1i-1i−1相邻&#xff0c;111与nnn相邻&#xff0c;每次选择一个位置&#xff0c;将这个位置的值变成与它相邻的两个位置的和&#xff0c;让后将相邻位置删掉。求最终剩下一个数的时候最大值是多少…

AGC004E - Salvage Robots(dp,思维)

AGC004E - Salvage Robots Solution 怎么又双叒叕遇到和NOIP2020T4NOIP2020T4NOIP2020T4和那道CFCFCF题一样的题了啊&#xff0c;惨痛回忆QAQQAQQAQ。 大概就是把问题看成刚开始的点不动&#xff0c;整个网格图动&#xff0c;机器人向上111格等于网格整体向下111格&#xff…

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 支持的动态供给 …

AGC005D - ~K Perm Counting(组合数学,背包,dp)

AGC005D - ~K Perm Counting Solution 经典数排列个数题&#xff0c;写了个大麻烦容斥。 直接容斥&#xff0c;考虑求出fif_ifi​表示有iii个位置∣pi−i∣k|p_i-i|k∣pi​−i∣k的方案数。一个位置iii满足∣pi−i∣k|p_i-i|k∣pi​−i∣k&#xff0c;要么piikp_iikpi​ik&a…

Codeforces Round #704 (Div. 2) D. Genius‘s Gambit 构造 + 细节

传送门 题意&#xff1a; 给a,b,ka,b,ka,b,k&#xff0c;要求用aaa个000和bbb个111组成二进制xxx和yyy&#xff0c;并且x−yx-yx−y恰好有kkk个111&#xff0c;并且xxx和yyy不含前导零。 思路&#xff1a; 首先需要看到不含前导零&#xff0c;一开始没看见wa5了。让后一个很明…

ASP.NET Core 应用程序状态

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

HDU6218 2017ACM/ICPC亚洲区沈阳站 Bridge(Set,线段树)

HDU6218 2017ACM/ICPC亚洲区沈阳站 Bridge Solution 我们考虑维护在环上的边的个数&#xff0c;答案就是总边数减去环上边数。 环的形态是这样的&#xff1a;(0,l),(0,l1)...(0,r),(1,r),(1,r−1)...(1,l)(0,l),(0,l1)...(0,r),(1,r),(1,r-1)...(1,l)(0,l),(0,l1)...(0,r),(…

Codeforces Round #704 (Div. 2) E. Almost Fault-Tolerant Database 思维

传送门 题意&#xff1a; 给nnn个长度为mmm的数组&#xff0c;要求构造一个长度为mmm的数组&#xff0c;使得这个数组与前面nnn个数组同一位置最多两个元素不同。 思路&#xff1a; 我们为了方便构造&#xff0c;可以先把要构造的数组看成nnn个数组的第一个数组&#xff0c;让…

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

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

[APIO2018] New Home 新家(线段树,二分答案,离散化)

[APIO2018] New Home 新家 Solution 对于时间轴我们直接离散化扫描线&#xff0c;维护每一个商店的加入和删除。 对于询问(x,t)(x,t)(x,t)&#xff0c;不好直接回答&#xff0c;这里的关键一步是&#xff1a;我们要求的是kkk种商店最小距离的最大值&#xff0c;于是考虑二分…

Codeforces Round #701 (Div. 2) C. Floor and Mod 数学分块

传送门 题意&#xff1a; 给两个数x,yx,yx,y。现在你计算有多少对a(a<x)a(a<x)a(a<x)和b(b<y)b(b<y)b(b<y)使得⌊ab⌋amodb\left \lfloor \frac{a}{b} \right \rfloora\bmod b⌊ba​⌋amodb。 思路&#xff1a; 因为xxx和yyy都是1e91e91e9的范围&#xff0…

AGC011D - Half Reflector(模拟)

AGC011D - Half Reflector Solution 先考虑改变一次。 我们令LLL表示往左走的球&#xff0c;RRR表示往右走的球&#xff0c;xxx表示任意种类的球&#xff0c;(−x)(-x)(−x)表示与xxx相反种类的球。 当球处于ARAARAARA的状态&#xff08;即有一个向右的球在两个AAA机器人之间…

[开源] 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、自定…

Codeforces Round #701 (Div. 2) D. Multiples and Power Differences 思维构造

传送门 题意&#xff1a; 给定一个矩阵aaa&#xff0c;让你构造一个矩阵bbb&#xff0c;要求矩阵bbb的每个元素是aaa对应位置元素的倍数&#xff0c;且矩阵bbb的每两个相邻元素相差为k4(k>1)k^4(k>1)k4(k>1)。注意aaa的元素范围是1<a<161<a<161<a<…