专栏首页腾讯BBTeam团队的专栏服务端频率控制的几种实现方式
原创

服务端频率控制的几种实现方式

服务端频率控制一般有以下几种常见的方式:

一、局部频率控制

对于某一个接口I,请求频率阈值T,假设请求均匀分散到N台服务器上,每台服务器上接口I的频率阈值就是T/N,这样每台机器通过检查接口I的本地请求频率就可以做频率控制。

这种方式优点是实现简单,而且由于是本地控制,效率极高,如果流量均匀的话,频率控制也会比较实时。对于服务器配置,地理位置,路由权重一样,这种方式可以有一些使用场景。当然缺点也很明显,就是局限性比较大,没法做全局的控制,很多场景下并不能保证每台机器流量一样,另外一旦集群发生扩容/缩容,每台机器分配到的频率阈值需要额外的重新计算。

二、全局频率控制

这种方式一般会有分布式的请求频率上报,然后有一个中心化的频率控制服务汇总请求频率信息检查是否超频,在实现上又有很多种。

简易实现

基于一些Nosql系统支持的原子计数器功能,比如可以使用CKV,Redis等提供的INCR/DECR接口,汇总来自各台服务器上报的请求频率。这种方式实现上也可以有多种。

可以利用expire机制,设置每个业务key的过期时间为频率控制周期。以1分钟频率控制周期为例,伪代码如下:

time_unit = 60
value = INCR $key
if key not exist
    init_value = 0
    INIT $key $init_value
    EXPIRE $key $time_unit
else
    if $value < $threshold
        // 没有超频,放行
   else
       // 超频了,限制 

也可以自己控制过期时间,原子计数器的value一般是64位整数,可以拆成两部分,高32位为时间部分,后32位为实际频率计数(当然这里不一定是以32位拆分,比如限制每天最大调用量,可能时间部分只需要16位,留下更多位给计数用)。以1分钟频率控制周期为例,伪代码如下:

time_unit = 60
value = INCR $key
current_minute = current_timestamp() / $time_unit * $time_unit
if key not exist
    init_value = $current_minute << 32
    INIT $key $init_value
else 
    freq_minute = $value >> 32
    freq = $value & 0xFFFFFFFF
    if $current_minute != $freq_minute
        // 不是当前频率周期了,重新初始化
        init_value = $current_minute << 32
        INIT $key $init_value
    else
        if $freq < $threshold
           // 没有超频,放行
        else
          // 超频了,限制

这两种实现方式原理都差不多,能比较实时地监测到超频的情况。前一种可以设置的频率阈值范围更大,不过对nosql系统的过期机制依赖比较严重,个人相对偏好后一种方式。不过由于都需要依赖外部存储且需要经过网络,如果网络抖动以及外部存储发生故障,频率控制可能就会失效,另外由于这类方式是把业务的请求量会直接放给外部存储,对存储的性能要求也会比较高。

复杂实现

前面的几种情况都是比较简易的实现方式,可以应对大多数简单的频率控制场景。但是对于提供API接口的门户系统,前面的功能是远远不够的,所以一般都会实现一套频率控制服务,除了限频,还有结合告警,请求频率流水等形成一套完整的频控生态。

这类系统一般会在每台业务机器上部署一个agent,业务进程写入频率信息到共享内存,agent从共享内存收集再上报,后端有一个频率服务server汇总,执行频率控制策略,下发是否超频以及频率告警等。典型的架构流程如下:

这种频控方式是比较通用的一种实现,频率上报和频率检测通过共享内存解耦了,不会像原子计数器会受制于业务的请求量,频率检测也不需要经过网络,业务进程直接从本地共享内存中就能判断是否超频了,比前面基于原子计数的快。不过受制于agent的上报的实时性,决策是否超频可能会相对延迟一些。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring - application.yml 数字读取错误、eg: 000001

    application.yml 文件在读取纯数字的时候会将0开头的数字自动转换成8进制,场景如下:

    夹胡碰
  • 斯坦福CS231N深度学习与计算机视觉第八弹:神经网络训练与注意点

    大数据文摘
  • RxJava 1.x 笔记:过滤型操作符

    我真的是奇怪,上下班的路上看书、看文章学习的劲头特别大,到了周末有大把的学习时间,反而不珍惜,总想打游戏,睡前才踏踏实实地写了篇文章,真是服了自己! 本文内容...

    张拭心 shixinzhang
  • 大数据常见面试题总结

    很多学员在面试的时候都会问到老师,常见的面试题有哪些。今天老师根据往届学员的面试反馈,整理了常见的一些面试题目,希望可以帮助到需要的同学。

    加米谷大数据
  • 数值积分| 辛普森公式

    辛普森积分法是一种用抛物线近似函数曲线来求定积分数值解的方法。把积分区间等分成若干段,对被积函数在每一段上使用辛普森公式,根据其在每一段的两端和中点处的取值近似...

    fem178
  • Lync日志收集

    Lync管理人员在部署Lync过程中,测试或多或少会遇到一些问题,通过Lync客户端可以收集测试项的日志,如下是收集日志的方法:

    杨强生
  • 哈希表(散列表)原理详解

    哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构 。也就是说,它通过把关键码值映射到表中一个位置来访问记...

    233333
  • Linux命令(14)——日期相关操作date、hwclock、timedatectl、nptdate、cal

    可见成功减少了两天 (5)设置系统时间 可以加上-s选项 后面加上你想要设置的时间 (6)获取硬件时间

    gzq大数据
  • 奥地利科研团队优化BCI技术,将帮助深度残疾音乐家进行创作 | 技术

    镁客网
  • Chrome小游戏《Boxel Rebound》“嗨到中毒”的弹跳小方块

    https://chrome.google.com/webstore/detail/boxel-rebound/iginnfkhmmfhlkagcmpgofnj...

    zhaoolee

扫码关注云+社区

领取腾讯云代金券