安全:如何设计高吞吐和大流量分布式集群的限流方案?

325 阅读4分钟

集群中的数据加密

要实现这个效果一般有以下两种方案:

  • 第一种就是上面说的,由服务端自动化做好加密解密。工作量全在服务端,客户端没有任何工作量。
  • 第二种是客户端在生产的时候自助做好加密逻辑,在消费的时候自助做好解密操作。好处在于消息队列服务端没有任何工作量,坏处在于工作量全部在客户端,所有的客户端和消费端都需要感知加密的逻辑,在编码和协调各方的成本方面较高。

目前业界主流开源消息产品都是不支持消息加密的。

消息队列限流机制思考

目前有四种常见的限流算法。

image.png

因为消息队列经常需要应对突发流量,需要尽量平滑的限流机制,所以从实现上来看会比较推荐令牌桶算法。

当前主流消息队列产品,主要选择还是单机限流机制,比如 Kafka、Pulsar。思路是:放弃集群维度的精准限流,将集群总的配额根据节点数据量均分到每个节点,在每个节点内部完成单机限流。

从消息队列的特性上来看,主要对流量、连接数、请求数三类资源进行限流,有些消息队列还会对 CPU 和内存进行限制。限制的维度一般包括:集群、节点、租户 / Namespace、Topic、Partition、Group/Subscribe 六个维度。

在限流后,我们一般有两种处理形式。

  1. 返回超额错误,拒绝请求或流量。
  2. 延时回包,通过加大单次请求的耗时,整体上降低集群的吞吐。因为正常状态下,客户端和服务端的连接数是稳定的,如果提升单次处理请求的耗时,集群整体流量就会相应下降。

Kafka 的主要处理机制是延时回包。延时回包的优点是可以承载突发流量,当有突发流量时,不会对客户端造成严重影响,缺点是无法精准限制流量。

单机限流方案

具体实现分以下四步:

  1. 计算单节点的配额。
  2. 存储每个节点的配额信息,以免节点重启后配额信息丢失,比如 Kafka 和 Pulsar 都是存储在 ZooKeeper 上。
  3. 为每个节点下发变更配额信息,节点在重启的时候加载配额信息。
  4. 当生产消费的时候,在内存存储计算流量,并和配额数据进行比较,确认是否限流。

全局限流方案

主要分为五步。

  1. 首先选择一个集中式的限流 Server,你可以选择业界的全局限流的组件,比如 Sentinel 或 PolarisMesh,也可以是消息队列内置实现的一个全局限流的组件,简单点也可以是 MySQL 或者 Redis。
  2. 然后在组件中写入限流配额。
  3. 在生产和消费时,向限流 Server 记录配额信息,获取限流状态,判断是否进行限流。
  4. 同时根据单机限流的方案,在本地缓存一份均分的配额数据,当限流 Server 异常时,直接使用本地缓存的配额数据进行计算限流。
  5. 同时提供开关,在某些情况下可以关闭限流。

消息队列的服务降级

消息队列中常见的降级策略一般有三种。

  1. 配置 Broker 的 CPU 或内存的使用率额度,当使用率到达配额时,通过拒绝生产或消费流量的形式来保证服务的部分正常。
  2. 配置磁盘保护机制,可以保护消费不会有异常。当真实的磁盘使用率使用达到一定的程度时,就禁止流量写入。因为在消息队列中,磁盘较容易被打满,打满的话如果还允许写入服务程序就会有异常,从而影响消费。
  3. 判断异常自动重启 Broker,通过自动判断服务的运行情况,决定是否重启 Broker。比如当发现频繁发生 Full GC 的时候,就自动重启自身服务,以达到回收资源的目的。这种方式用得比较少,因为比较危险,可能会导致集群中的所有 Broker 频繁重启。一般需要依赖第三方组件的多维度判断,以降低误重启的风险。

此文章为11月Day20学习笔记,内容来源于极客时间《深入拆解消息队列 47 讲》