cover_image

Soul集群限流的线上实践

Soul-后端 Soul技术团队
2023年03月23日 03:15

介绍

引言

本文主要介绍了基于Sentinel集群限流的线上实践,提供了Sentinel集群限流高可用的一种解决方案,以及Token server的自动分配和自动故障转移的实现。
背景
为什么要有集群限流?
借用官方的话
假设我们希望给某个用户限制调用某个 API 的总 QPS 为 50,但机器数可能很多(比如有 100 台)。这时候我们很自然地就想到,找一个 server 来专门来统计总的调用量,其它的实例都与这台 server 通信来判断是否可以调用,这就是最基础的集群流控的方式。
另外,集群流控还可以解决流量不均匀导致总体限流效果不佳的问题。假设集群中有 10 台机器,我们给每台机器设置单机限流阈值为 10 QPS,理想情况下整个集群的限流阈值就为 100 QPS。不过实际情况下流量到每台机器可能会不均匀,会导致总量没有到的情况下某些机器就开始限流。因此仅靠单机维度去限制的话会无法精确地限制总体流量。而集群流控可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果。
我们在流量治理的过程中,也面临着这些问题。单机限流的不足带来了一些额外的麻烦,一些流控场景无法通过单机限流来完成治理,所以集群限流功能也成为我们在流量治理方面迫切需要的能力。
官方的实现方式
Sentinel集群流控与单机流控的本质一样,都需要对用户关心的指标做统计,区别就在于单机流控是在每个应用实例中进行统计,而集群限流则是有一个专门的实例来统计。
集群流控中共有两种身份:
Token Client:集群流控客户端,用于向所属Token Server通信请求Token,集群限流服务端会返回给客户端结果,决定是否限流。

Token Server:集群流控服务端,处理来自Token Client的请求,根据配置的集群规则判断是否应该发放Token。

对于Sentinel集群限流,官方提供了两种模式:独立模式和嵌入模式。

独立模式(Alone):单独部署一台机器作为Token Server

图片

嵌入模式(Embedded):就是在整个微服务集群内部选择一台机器节点作为Token Server

图片

两种部署方式对比

模式
优点
缺点
内嵌模式
不需要独立部署限流服务端,节省资源开支
  • 无故障自动转移

  • 使用于单个微服务集群内部限流

  • Token Server节点的机器性能会受到影响

  • 手动为每个节点设置Token Server,可用性差

独立模式
独立部署限流服务端,不会影响业务节点
  • Token Server默认单机部署,无高可用方案

  • 需要独立部署,额外产生资源开销和维护成本

  • 手动为每个节点设置Token Server,可用性差


基于Sentinel的高可用集群限流平台搭建

方案选择

综合官方对于集群限流两种实现方式的对比,以及当下自身业务的需要,我们选择了基于独立模式的方式实现,并通过Sentinel源码的二次开发,实现了集群限流的高可用、集群限流故障自动转移机制以及完善了集群限流Server的自我保护机制。

整体架构

图片

我们基于Sentinel做了二次改造,形成了上图所示的平台架构,主要分为控制台、事件中心、Token Client、Token Server四部分。

控制台

控制台是一个可视化界面,用户可在控制台进行规则配置、监控查看,并且还实现了Token Server的流量平衡以及相关的报警功能。

事件中心

引入事件中心的目的是为了轻量化控制台与Token Client和Token Server之间的交互,基于事件通知的方式,使Token Server和Token Client做出相应的动作;事件包括配置的变更、节点上下线等。

Token Client

Token Client就是一个Java jar包,它内部封装了Sentinel的基础功能、控制台事件的响应、Token Server集群故障自动转移、Token Server的状态管理、断线重连等功能。

Token Server

它是一个独立部署的Java程序,对外提供限流、热点参数限流计算的功能,它自身是无状态的,可根据需要进行多个Token Server部署,形成Token Server集群,集群间各Token Server之间是独立的,互不影响的存在。

集群限流的高可用实现

官方对于Token Server只是提供了单机版的实现,作为流量治理的核心环节,单机服务根本满足不了需要。所以,单机版Token Server该如何实现集群部署成了高可用的第一个核心问题。

其次,在默认的实现里,无论是创建还是修改集群限流规则,都是需要用户手动去控制台设置或修改Token Server,才能完成集群限流的全部配置,即使某个Token Server故障了,也需要手动设置才能完成切换,如何自动分配Token Server以及无故障自动转移能力成为了集群限流高可用的第二个核心问题。

Token Server的集群部署方案

Token Server的核心功能是提供流量计算的能力,每台Token Server都需要为每个请求资源提供一个滑动窗口,用来计算当前资源在窗口内的请求是否达到上限,并将结果返回给请求方。所以是一个实时计算的场景,并且每个资源间相互独立,互不影响。

针对以上特性,我们采取了无状态、多节点部署的方案。每台Token Server都是一个独立的服务,都可以对外提供流量计算的能力,可以根据需要实现集群服务的水平自动伸缩。

Token Server的自动分配及自动故障转移

这部分功能主要放在Token Client 里实现,Token Client所在的应用程序启动时会处理启动事件,去Sentinel控制台拉取流控规则信息及可用Token Server的信息。

在SDK里有一层Tcp Channel Proxy,它负责与所有Token Server建立tcp链接,并在内部维护一个可用tcp链接列表,然后根据tcp心跳来维护和管理每个tcp链接的状态。

在发起集群限流请求时,Token Client会将资源的流控规则标识与可用tcp链接列表长度按照hash算法,将某个资源的限流请求固定路由到某个Token Server上,实现Token Server的自动固定分配。若某个channel异常,Tcp Channel Proxy会将异常的channel移除可用列表。当列表发生变化时,对应hash算法的结果也会发生变化,从而实现Token Server故障的自动转移,同时后台会尝试重连异常的channel,重连成功则会将channel重新加入可用列表。若全部Token Server节点异常,Token Client则自动退化为单机限流,直到事件通知有Token Server上线,才会重新建立tcp连接并恢复为集群限流。

图片

至此,我们通过轻量化的设计实现了集群限流服务的高可用,在保证集群限流服务的可用性的同时还实现了集群服务的水平自动伸缩。

压测

Token Server是整个集群限流中最重要的一部分,它承载着集群限流计算压力,所以这部分也是重点需要调整和优化的地方,以下是我们在测试过程中的一些数据。

测试场景为单台8C16G的Token Server场景,通过内部压测平台进行压力测试。

图片

图片

图片

以上为QPS20万时,Token Server机器的CPU表现,CPU的利用率是在68%左右,5分钟的最高负载超过了7。

图片

图片

当我们把QPS加到24万时,CPU已经到75%了,并且5分钟负载也已经接近10,按照这个QPS量,我们进行了持续半小时的压测,系统表现良好,没有异常情况。

综上,当使用8C16G的机器时,单机可以每秒处理20万级别的集群流控计算,若有QPS超过这个量级的请求,可通过增加机器配置的方式来实现。

结语

通过基于Sentinel的二次开发,我们搭建了内部的集群限流平台,目前Soul大部分核心服务均已引入限流组件,在限流平台的基础上进行各种场景的流量治理。

同时在推广使用限流平台的使用时也完善了集群限流的核心功能,并且进行了一系列的扩展和治理。例如:Token Server的流量自治理、可视化配置的流控异常处理等,在完成流量治理的同时也在探索该平台更多的应用场景。

继续滑动看下一个
Soul技术团队
向上滑动看下一个