专栏首页中间件兴趣圈Sentinel 集群限流设计原理

Sentinel 集群限流设计原理

1、集群限流使用场景


首先一个服务有三个服务提供者,但这三台集群的硬件配置不一样,如图所示:

为了充分利用硬件的资源,诸如 Dubbo 都提供了基于权重的负载均衡机制,例如可以将8C16G的机器设置的权重是4C8G的两倍,这样充分利用硬件资源,假如现在需要引入 Sentinel 的限流机制,例如为一个 Dubbo 服务设置限流规则,这样由于三台集群分担的流量不均匀,会导致无法重复利用高配机器的资源。

假设经过压测,机器配置为C48G最高能承受的TPS为 1500,而机器配置为8C16G能承受的TPS为2800,那如果采取单机限流,其阔值只能设置为1500,因为如果超过1500,会将4C8G的机器压垮。

解决这种办法的方式就是针对整个集群进行限流,即为整个集群设置一个阔值,例如设置限流TPS为6000。

2、集群限流与单机限流的异同思考


限流的一个基本作用就是按照限流规则生成访问许可(Token),然后根据当前实时的调用信息进行判断是否可以获得许可而决定是否放行。

集群与单机限流在实时调用信息收集方面应该差别不大,都可以基于滑动窗口进行统计信息的收集。

集群与单机限流的最主要区别在与许可的生成,单机模式的许可直接在本地生成,但集群限流必须有一个统一的 Token 发放机制,以此来协调当前集群内多机调用,从而基于当前“调用总数”进行限流。

3、探究集群限流实现原理


在探究集群限流实现原理之前先来回顾一下单机限流的执行流程图。

结合流程我们可以看出集群限流的几个关键点 ClusterBuilderSlot、FlowSlot。

3.1 ClusterBuilderSlot 详解

在对一个资源进行流控规则判断时,首先将进入到 NodeSelectorSlot,然后就会进入到 ClusterBuilderSlot,为了与单机限流模式,介绍 ClusterBuilderSlot 时与 NodeSelectorSlot 进行一个对比。

NodeSelectorSlot 的核心实现截图如下所示:

温馨提示:从该系列之前的文章也能得知,一个 资源对应的一个 NodeSelectorSlot 实例,即多线程访问一个资源时,都会调用同一个 NodeSelectorSlot 实例。

NodeSelectorSlot 的关键点如下:

  • Map<String, DefaultNode> map 在 NodeSelectorSlot 中是以 context Id 为维度进行缓存的,例如官方给出的 Dubbo 适配方法,contexId 为 dubbo 服务的全路径名。即 Dubbo的入口节点对应的缓存 Key 为 context id。
  • fireEntry 的 node 参数 由于 NodeSelectorSlot 是第一个过滤器,故第一次调用 fireEntry 方法时的 node 参数就是上面创建的 Node,即与 context 相关链的 Node,即所谓的入口节点即 Entrance Node。

接下来重点关注一下 ClusterBuilderSlot 的关键点:

ClusterBuilderSlot 的关键点如下:

  • Map<ResourceWrapper, ClusterNode> clusterNodeMap 持有的集群节点缓存表,其键为 Entrance Node 所对应的资源ID,即 Context 中关联的节点信息。
  • Node originNode 所谓的 orginNode,即在调用 ContextUtil 中 enter(String name, String origin) 方法中的第二个参数,表示这条调用链的源头,在 Dubbo 中默认为 应用的 application。

经过上面两个Slot,整个调用链就基本创建好了,接下来我们来看一下 FlowSlot 关于集群限流的相关处理逻辑。

3.2 集群限流模式实现原理

FlowSlow FlowSlot 的核心处理逻辑主要是调用 FlowRuleChecker 的 canPassCheck 方法,正如上面看到的一样,根据配置规则,如果是集群模式,则调用的是其 passClusterCheck 方法,接下来我们将重点探讨该方法。

FlowRuleChecker#passClusterCheck 代码@1:获取一个 TokenService 服务类。这里实现关键点:

  • 如果当前节点的角色为 CLIENT,返回的 TokenService 为 DefaultClusterTokenClient。
  • 如果当前节点的角色为 SERVER,返回的 TokenService 为 ClusterTokenServer,这里使用了SPI极致,可以通过查看 META-INF/services 目录下的 com.alibaba.csp.sentinel.cluster.TokenService 文件,默认服务端返回 DefaultTokenService。

代码@2:如果无法获取到集群限流Token服务,如果该限流规则配置了可以退化为单机限流模式,则退化为单机限流。

代码@3:获取集群限流的流程ID,该 flowId 全局唯一。

代码@4:通过 TokenService 去申请 token,这里是与单机限流模式最大的差别。

接下来将分别从 DefaultClusterTokenClient、DefaultTokenService 分别探究集群限流相关的实现原理与细节,更好的指导我们如何使用集群限流功能。

3.2.1 DefaultClusterTokenClient 详解

从我们的经验也得知,TokenClient 的主要职责就是发送请求到 TokenService 端,主要是网络相关的细节将不在此篇文章中给出,如果有兴趣,大家可以关注我的 Netty 专栏。

首先 Sentinel 提供了 SPI 机制,故允许用户自定义 TokenClient 的实现类,官方与 SPI 默认配置的文件如下:

关于 TokenClient 主要关注其初始化代码,因为我们需要关注一个非常重要的点: DefaultClusterTokenClient#initNewConnection

在客户端启动的时候会创建与 TokenServer 之间的链接,即这边需要配置服务端的 IP 与端口号,那如何配置呢?其实配置方式完全由自己去实现对应的解析器,下面根据官方的 Demo 示例如下:

这里需要说明的其配置项由 ClusterGroupEntity 来定义,其字段的定义如下:

  • clientSet 客户端 Set 集合。
  • ip Token 服务端的 IP。
  • machinedId Token 服务端的机器ID。
  • port Token 服务端的机器端口。

其配置示例如下:

[{"clientSet":["112.12.88.66@8729","112.12.88.67@8727"],"ip":"112.12.88.68","machineId":"112.12.88.68@8728","port":11111}]

Client 端接下来就是向服务端发送请求,与网络相关的不在本文的讨论范围内,接下来将重点探讨服务端是如何发放许可的。

3.2.2 DefaultTokenService 详解

Token Server 端收到客户的请求,其处理入口为 FlowRequestProcessor,其处理方法为:processRequest,最终会调用 DefaultTokenService 的 requestToken 方法。 DefaultTokenService#requestToken

代码@1:根据 ruleId 获取指定的限流规则。

代码@2:然后调用 ClusterFlowChecker 的 acquierClusterToken 方法,申请许可。

许可的发放流程主要由 ClusterFlowChecker 的 acquierClusterToken 方法实现。

Step1:首先判断是否允许本次许可申请,这是因为 TokenServe 支持嵌入式,即支持在应用节点中嵌入一个 TokenServer,为了保证许可申请的请求不对正常业务造成比较大的影响,故对申请许可这个动作进行了限流。

一旦触发了限流,将向客户端返回 TOO_MANY_REQUEST 状态码,Sentinel 支持按 namespace 进行限流,具体由 GlobalRequestLimiter 实现,该类的内部同样基于滑动窗口进行收集,原理与 FlowSlot 相似,故这里不加以展开,默认的限流TPS为3W,有关于 Sentinel 相关的配置,将在后续文章专门梳理。

Step2:根据流程ID获取指标采集器。

Step3:计算 latestQps、globalThreashold、 nextRemaining 三个阔值,三个的含义分别如下:

  • latestQps 获取当前正常访问的QPS。
  • globalThreashold 根据限流配置规则得出其总许可数量,其主要根据阔值的方式其有所不同,其配置阔值有两种方式: 1)FLOW_THRESHOLD_GLOBAL 总数,即集群中的许可等于限流规则中配置的 count 值。 2)FLOW_THRESHOLD_AVG_LOCAL 单机分摊模式,此时限流规则中配置的值只是单机的 count 值,集群中的许可数等于 count * 集群中客户端的个数。 注意:这里还可以通过 exceedCount 设置来运行超过其最大阔值,默认为1表示不允许超过。
  • nextRemainging 表示处理完本次请求后剩余的许可数量。

Step4:如果剩余的许可数大于0,则本次申请成功,将当前的调用计入指标采集器中,然后返回给客户即可。

接下来所有流程步骤都是基于没有剩余许可数的处理逻辑。

Step5:当前许可数不足的情况,并且该请求为高优先级的处理逻辑:

  • 获取当前等待的TPS(即1s为维度,当前等待的请求数量)
  • 如果当前等待的TPS低于可借用未来窗口的许可阔值时,可通过,但设置其等待时间,可以通过 maxOccupyRatio 来设置借用的最大比值。

Step6:如果当前许可不足,并且该请求为普通优先级的处理逻辑,增加阻塞相关指标的统计数,并返回 BLOCKED。

TokenServer 返回申请许可之后,那 Token Client 如何处理呢?其处理代码在 FlowRuleChecker#applyTokenResult

我们可以发现,如果服务端返回OK,则顺利通过,返回BLOCKED,则直接返回 false,会抛出 FlowException,如果是 token 限流,如果规则运行退化为单机限流模式,则进行单机限流。

集群限流的基本实现原理就介绍到这里了。

4、总结


集群限流的基本原理接介绍到这里了,与单机限流模式最大的区别就是集群限流模式的需要引入 TokenService,提供许可的发放服务,该服务可以嵌入应用节点,也可以独立于应用之外。这边借用官方文档上的两张图来简单介绍一下嵌入模式与独立模式的架构:

最后抛出一个思考题:集群模式应该算是高大上,但我们项目中真的需要吗?集群限流模式有哪些缺点、哪些优点,欢迎大家留言探讨。

本文分享自微信公众号 - 中间件兴趣圈(dingwpmz_zjj),作者:丁威

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • sentinel 集群流控原理

    为什么需要集群流控呢?假设需要将某个API的总qps限制在100,机器数可能为50,这时很自然的想到使用一个专门的server来统计总的调用量,其他实例与该se...

    luoxn28
  • 限流神器Sentinel,不了解一下吗?

    书接上回: 你来说说什么是限流? ,限流的整体概述中,描述了 限流是什么,限流方式和限流的实现。在文章尾部的 分布式限流,没有做过多的介绍,选择了放到这篇文章中...

    九灵
  • 阿里开源限流组件 Sentinel 集群流控全解析

    假设我们希望给某个用户限制调用某个 API 的总 QPS 为 50,但机器数可能很多(比如有 100 台)。这时候我们很自然地就想到,找一个 server 专门...

    老钱
  • 常见限流方案设计与实现

    编者注:高并发系统设计的3个利器:缓存、限流、降级,本文就限流相关算法,分析其设计与实现。

    luoxn28
  • Sentinel 流控规则详解

    在前面两篇文章给大家介绍了 Sentinel 的功能和基本使用。现在我们继续来学习 Sentinel 控制台的基本使用,以及一些规则配置的说明。让大家能够在工作...

    没有故事的陈师傅
  • 报告老板,微服务高可用神器已祭出,您花巨资营销的高流量来了没?

    正如众所周知,每年的双11除了是购物狂欢节,同样也成了科技的大考和狂欢,让我们得以看到那么多高端的充满想象力的黑技术。在整个双11高并发高流量的过程中,Sent...

    牧码哥
  • 结合 Sentinel 专栏谈谈我的源码阅读方法

    Sentinel 系列共包含15篇文章,主要以源码分析为手段,图文并茂的方式对 Sentinel 的架构设计理念、核心实现要点进行了一一剖析,并加以实战分析与思...

    丁威
  • 没有 “流量防控”,还玩什么双11

    临近双十一,从 2009 年第一届双十一开始,成交量只有 5000 万,到去年 2019 年,成交量达到了 2684 亿。今年迎来了第十二届双十一,想想都挺激动...

    xjjdog
  • 流量防控该如何选型?

    临近双十一,从 2009 年第一届双十一开始,成交量只有 5000 万,到去年 2019 年,成交量达到了 2684 亿。今年迎来了第十二届双十一,想想都挺激动...

    悟空聊架构
  • 限流,永远都不是一件简单的事!

    随着微服务的流行,服务之间的稳定性变得越发重要,往往我们会花很多经历在维护服务的稳定性上,限流和熔断降级是我们最常用的两个手段。前段时间在群里有些小伙伴对限流的...

    用户5397975
  • 现在微服务这么流行!限流和熔断降级你竟然还不会?

    随着微服务的流行,服务之间的稳定性变得越发重要,往往我们会花很多经历在维护服务的稳定性上,限流和熔断降级是我们最常用的两个手段。前段时间在群里有些小伙伴对限流的...

    Java程序猿
  • 中通缓存服务平台基于 Kubernetes Operator 的服务化实践

    ZCache 是中通下一代缓存服务平台,实现多种缓存类型自动部署,提供 Proxy 访问层,通过 Proxy 层提供指令限制、访问权限、限流、分片处理等功能,通...

    张乘辉
  • 快速学习-sentinel简介

    随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从流量控制、熔断降级、系...

    cwl_java
  • Sentinel 流量控制 熔断降级 初探 原

        还记得之前写过一篇防雪崩利器:熔断器 Hystrix 的原理与使用https://my.oschina.net/u/3266761/blog/26544...

    chinotan
  • sentinel实现服务限流降级

    sentinel的官方名称叫分布式系统的流量防卫兵。Sentinel 以流量R为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。在Spri...

    Java旅途
  • Sentinel源码分析,了解Sentinel的整个工作流程

    从上一篇《Sentinel限流的核心功能QPS统计的实现原理》我们了解到,Sentinel统计QPS使用的是时间窗口+Bucket,并且通过循环复用Bucket...

    Java艺术
  • 史上最全Redis高可用技术解决方案大全

    Redis 单副本,采用单个Redis节点部署架构,没有备用节点实时同步数据,不提供数据持久化和备份策略,适用于数据可靠性要求不高的纯缓存业务场景。

    Java知音
  • Sentinel Dubbo 适配器看限流与熔断(实战思考篇)

    本文是源码分析 Sentinel 系列的第十三篇,已经非常详细的介绍了 Sentinel 的架构体系、滑动窗口、调用链上下文、限流、熔断的实现原理,相信各位读者...

    丁威
  • Sentinel: 分布式系统的流量防卫兵

    随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

    35岁程序员那些事

扫码关注云+社区

领取腾讯云代金券