当我们设计分布式流量控制系统时,我们需要使用哪些工具和算法?
Criteo是世界上最大的广告技术公司之一。随着广告市场的持续发展,Criteo在过去几年中一直致力于改善API,并帮助客户更好地访问编程界面访问的需求。
随着越来越多的客户使用新的API,很明显,需要实现某些交通管制,以确保所有客户都可以平均访问资源,并保护API免受(恶意或错误)的经常调用。
流控制似乎很简单:仅允许给定的客户端执行X单订单每分钟。它在单个服务器实例上实现流量控制非常容易,并且很容易找到相关的库来实现它。但是问题是我们的API监护权位于6个数据中心(欧洲,北部和亚洲)。每个数据中心都有多个示例,这意味着我们需要一些分布式流量控制系统。
流动控制不仅与呼叫数量有关,而且还需要同步当前有限的状态(例如,使用特殊的报纸标头和状态代码)。而且本文将主要关注用于流控制的算法和系统。
在尝试开发自己的系统之前,请先使用负载平衡,检查现有基础架构是否可以提供所需的特征更重要。
那么,数据中心的所有实例的部署是什么,并且已经负责检查和路由流量?负载平衡器。大多数负载balangers提供流量控制特性或可以用于实现流量控制的抽象。例如,Haproxy拥有可以用来设置流量控制的现成的棍子表[2],可以在实例和工作良好之间同步。
不幸的是,负载平衡并不支持我们需要的某些特征(动态限制,对该省代币的内省...),因此我们需要自己实现这些特定需求。
如果给定客户端的负载不平衡并且总是与单个实例交互,则主要方案会话粘附(粘性会话)在负载平衡时进行平衡时?然后,无需分发分布式流量控制系统。大多数客户端访问最近的数据中心(通过GEO-DNS)。如果在负载平衡器上启用了“粘性”,则客户端应始终访问同一实例。在这种情况下,我们可以使用简单的“本地”限制。
从理论上讲这是可行的,但不是在实践中。任何时间并准备扩大基础架构以满足客户不断增长的需求。但是,会话附着力和可扩展性不能很好地配合(如果所有客户都遵守旧实例,那么创建新示例的用途是什么?)
它将有助于使用更智能的会话粘附(扩展时重组对令牌),但这意味着每个扩展可能会切换到另一个实例,并且尚不知道客户端是前一个示例的上一个示例,许多调用是如何本质上,这将导致我们的流量控制在每次望远镜时都会不一致,并且当每个系统面临压力时,客户可能会拨打更多的呼叫。
如果客户端可以访问任何实例,则意味着必须在实例之间共享“调用计数”。一个方案是允许每个实例呼叫所有其他实例,并请求给定客户端的当前计数并添加它。,每个服务器将“计数更新”广播到其他服务器。
这将导致两个主要问题:
尽管可以实现此解决方案(本质上是一个点环,已经实现了许多系统),但成本却更高。
如果Kafka不想与其他实例进行通信,则可以在所有情况下使用Kafka同步计数器。
例如,当调用实例时,将事件推到相应的主题。这些事件由滑动窗口汇总(Kafka流在这方面做得很好),并且每个客户端的最后一分钟的最新计数将发布在另一个主题上。每个主题通过此主题获得了所有客户端的共享计数。
问题是Kafka本质上是异步的。尽管延迟通常很小,但是当API负载增加时,延迟将增加。如果实例使用过时的计数器,则应该停止的呼叫。
这些解决方案有一个共同点:当一切正常时,它都可以正常工作,但是当负载太重时,它会退化。我们的大多数系统都是这样设计的,通常没有问题,但是流量控制是不是典型的组件。目标是保护系统的另一部分免于这种超重负荷的影响。
流控制系统的目标是在系统负载较重时运行良好,其施工目标是服务最多1%,而不是99%。
分布式算法我们需要一个集中式同步存储系统,以及计算每个客户端的当前速率的算法。MEMORY缓存(例如Memcached或redis)是一个理想的系统,但并非所有流量控制算法都可以在缓存系统中实现。让我们看看哪些算法可用。
为了简化,我们考虑尝试实现“每分钟100个呼叫”的流量控制。
看看有哪些工具可用。
如果您想知道过去一分钟的客户打电话给客户,您可以存储缓存中每个客户端的时间戳列表。每个时间段电话,erige time呼叫,相应的时间戳将添加到列表中。然后循环列表中的每个项目,都将旧项目丢弃超过一分钟,然后计算新项目。
?优势:
?缺点:
固定窗口的大多数分布式高速缓存系统具有特定的高性能“计数”抽象(一个可以自动增加的整数值,连接到字符串键)。
以“”为密钥,可以为每个客户端维护一个计数器非常容易,但是它只会计算自计数器创建以来的客户端呼叫数量,而不是最后一分钟的次数。维护每分钟客户端的计数器(换句话说:1分钟作为固定窗口),找到与当前时间相对应的计数器可以告诉我们客户在此分钟执行的呼叫数量。IFIF此值超过上限,它可以阻止通话。
请注意,这与“最后一刻”不同。如果在早上07:10:23有一个电话,则固定的窗户计数器将在07:10:00 am到07:10:23之间显示。但是我们真正想要的是早上07:09:23至07:10:23之间的电话数量。
在一定程度上,固定的窗口算法被“忘记”“忘记”的每一分钟,因此客户可以在07:09:59上执行100个电话,然后在07:10:00 100泰士and 100次执行100次。Timesextra打电话。
?优势:
?缺点:
令牌桶返回1994年,父母将您送到游戏厅与朋友一起玩“超级街头战斗机2”。他们给你一个带有5美元的硬币的小桶,然后去街对面的酒吧,然后过来一小时才能在枪管中投入5美元的硬币。因此,您基本上仅限于每小时5美元(希望您在Street Fighter中表现良好)。
这是“令牌桶”算法背后的主要思想:与简单计数器不同,“桶”存储在每个客户端缓存中。桶是两个属性的对象:
当调用API时,请检索枪管,然后根据当前呼叫和最后一个呼叫之间的时间间隔向枪管添加新令牌。
因此,与“街道霸主”的示例相反,没有“父母”可以帮助我们每分钟重新填充枪管。枪管与令牌消费相同的操作有效地倾斜了(令牌的数量相对应在最后一个电话后的时间间隔)。如果最后一个电话是半分钟前半分钟,则每分钟100个电话的限制意味着将50张令牌卡添加到枪管中。如果枪管太“旧”(最后一次通话超过1分钟),令牌计数将重置为100。
实际上,它可以填充100多个令牌卡(但初始化时的补充速度为100令牌/分钟):这类似于“爆发”功能,使客户可以超过短期内流量控制的限制时间,但不能延长期限的维护。
注意:计算要正确添加的令牌数量,否则可以填充枪管。
该算法提供了完美的准确性,同时提供了稳定的性能。主要问题是它需要事务(不希望两个实例同时更新缓存对象)。
?优势:
?缺点:
漏水桶:算法的另一个版本。在此版本中,呼叫在存储桶中累积,并以恒定的速率处理(匹配速率的限制)。如果枪管溢出,则拒绝呼叫。这更复杂,更复杂,更复杂,但这可能是平滑的服务负载(这可能是您想要的,或者不需要的)。
?与这三种算法相比,最好的算法是,令牌枪管似乎在性能和准确性方面提供了最好的折衷。但是,只有当系统提供良好的事务支持时,只有在实现良好的事务支持时。完美的解决方案(即使是基于LUA的算法也可以直接在Redis群集上实现以提高性能),但仅记忆的仅支持原子计数器而不是交易。
您可以根据Memcachd版本[3]实现令牌枪管的乐观,但这更复杂,当负载重时,乐观的并发性能会降低。
如果您使用固定的窗口模拟滑动窗口,如果没有强大的交易支持,是否注定使用不准确的固定窗口算法?
就是这样,但是仍然有改进的余地。请记住,固定窗口的主要问题是每分钟都会“忘记”的事情,但是我们仍然可以访问相关信息(前一分钟在柜台),所以可以通过计算加权平均值来估计。
例如:如果在00:01:43执行呼叫,则获得“ 00:01”计数器的值。由于这是当前的日历分钟,00:01:00和00:01的电话数量:43(没有发生最后17秒)。但是我们想要的是60年代滑动窗口中的电话数量,这意味着我们错过了从00:00:00:43到00:01:00的计数。,我们可以阅读“ 00:00”计数器并调整17/60因子,这表明我们只对过去17秒感兴趣。
如果负载没有变化,这几乎是完美的。但是,如果大多数呼叫集中在上一分钟,它将获得高估的值。当大多数呼叫集中在上一分钟内,此数字将被低估。
为了更准确地了解准确性,最好在相同条件下模拟两种算法。
下图显示了输入随机流程时“固定计数器”算法将返回的内容。灰色线是“完美”滑动窗口输出。窗口在过去60秒内随时对应于通话数。这是我们的目标。橙色虚线表示相同流量上同一流量算法的“计数”。
他们在第一分钟的输出是相同的,但是很快他们就可以看到固定的窗口版本在每分钟的标记下都有很大的下降。固定的窗口算法很少有100多个呼叫,这意味着许多应该是许多呼叫停了下来。
下图表示相同的场景,并且具有相同的流量,但使用了近似的滑动窗口。相似,灰色线表示“完美”的滑动窗口。橙色虚线表示相似的算法。
下降不再接近每分钟的分数。您可以看到该算法的新版本更接近完美的算法。有时它稍高,有时略低,但通常是一个巨大的进步。
回报降低,但是我们可以做得更好吗?
我们的大约算法仅使用当前和前60秒固定的窗口。但是,您还可以使用几个较小的子窗口。一种极端的方法是使用60 1S窗口重建最后一分钟的流量。明显地,这意味着每次呼叫的60个计数器,这将大大增加性能成本。窗口越小,计数越多,近似值就越准确。
让我们看一下组合的5秒窗口的效果:
不出所料,精度有所提高,但仍然不完美。
我们处于经典的更好准确性=较差的性能。没有绝对的最佳解决方案,我们必须平衡准确性和性能的要求,并找到最合适的解决方案。如果您只关心保护您的服务,则不会在没有连续控制的情况下过度使用,那么,即使是最简单的窗口也可能是可行的解决方案。
结论流控制是一个非常容易描述的特征,但隐藏了很多复杂性。希望本文可以帮助您了解复杂分布式系统中流量控制中涉及的工具和算法。
/blog/intrantion-to-haproxy-tables/[3]乐观的货币控制:https://en.wikipedia.org/wikimistic_control
你好,我是你的粉丝。我已经在摩托罗拉完成了研发。现在,我已经在Mavenir完成了技术工作,并且我一直对沟通,网络,后端建筑,Yunyan,DevOps,CICD,CICD,Blockchain,AI和其他技术保持着浓厚的兴趣。我通常喜欢阅读和思考,我相信持续的学习和成长,欢迎一起交流和学习。Wechat公共帐户:DeepNomind