当前位置: 首页 > 文档资料 > Zebra 中文文档 >

Zebra 流量控制

优质
小牛编辑
128浏览
2023-12-01

1 背景

在系统访问量较大时,某些库的负载可能非常高,或者因为临时故障或系统bug导致大量异常SQL打到某个库上。为了防止数据库被这些异常流量打垮,需要在数据库访问层上对MySQL进行保护,因此zebra需要提供对某些特定SQL或某个库进行限流的功能。(SQL限流只是用于临时解决问题,事后还需业务方进行优化或扩容)

2 目标

  • 动态限流,可动态配置限流策略与流量大小
  • 支持限制某个数据源上的某些特定的SQL(sqlId)或者某些类型的SQL
  • 支持对事务的限流优化(特定条件下生效)

3 架构

zebra提供按照sqlId限制某些特定SQL或者限制某种类型的SQL两种限流方式,并且可动态配置。

应用在启动时或策略变更后,解析并根据与本机有关的配置修改filter。在限流开启后,要执行的SQL依次通过多个rule,如果某条SQL被判断为需要限制,则进行拦截并向上层服务抛出异常。

4 配置

zebra-flow.jdbcref.config

{
     "rules": [
    {
        "enable": false,                            // 规则是否有效
          "type": "SqlId",                            // 规则是否有效
          "config": {
            "id1": 10,                                // 某个sqlId及对应允许通过的百分比
            "id2": 20
          },
          "dbIp": "10.1.2.3",                            // 要限制的数据库ip
          "appIp": "10.72.*,10.73.*"                    // 要限制的应用ip
    },
    {
          "enable": false,
          "type": "AutoControl",
          "config": {
            "strategy": "Connection",                // 通过连接请求失败率来进行限流(暂时不需配)
            "threshold": 10,                        // 失败率超过百分之十是开始限流
            "floor": 50,                            // 流量下限是百分之五十
            "reduce": "linear:5/fast",                // 流量限制策略
            "recovery": "linear:5/exponential:2",    // 流量恢复策略
            "window":60,                            // 统计时间窗口(选配,默认60s,最大300s)
            "total":100                                // 窗口内请求总量>=total且失败率                                                               >=threshold时限流生效(选配,默认100个)
          },
          "dbIp": "10.1.2.3",
          "appIp": "10.72.*,10.73.*"
    },
    {
          "enable": false,
          "type": "ForceControl",
          "config": {
            "floor": 50                                // 流量下限百分比(针对连接,开启后会直接降到                                                       floor,优先级高于AutoControl)
          },
          "dbIp": "10.1.2.3",
          "appIp": "10.72.*,10.73.*"
    }
  ]
}

限流配置为JdbcRef级别,zebra启动时会在WallFilter内记录应用中所有的JdbcRef,并初始化配置,配置可动态修改。

  • rules:可以配置多个限流规则,每个可以针对sqlId或全部限流
  • enable:JdbcRef限流规则的开关
  • type: 限流规则类型,SqlId指限制特定Id的SQL,AutoControl指失败率达到阈值后自动限流,ForceControl指强行限流
  • config: 对应限流策略的具体配置
  • dbIp: 要限流的实例Ip(可以配置多个;"xx.xx."表示以xx.xx开头的实例;""表示所有实例)
  • appIp: 在某些机器上开启限流(可以配置多个;"xx.xx."表示以xx.xx开头的机器;""表示所有机器)

5 按SqlId限流

SqlId的计算规则:

sqlId = MD5(/*appName*/sqlName).subString(0, 8)

其中appName为应用名;sqlName指的是Mybatis中每一个mapper方法名。通过以上的算法,会给应用中的每一个SQL都生成一个8位的ID。

在接入了zebra-dao后,zebra可以给通过PreparedStatement执行的SQL算出一个唯一的ID,这个ID会拼接到每个SQL的前面一起发往数据库。一旦数据库发生故障,DBA可以抓取到这个SQL的ID,那么就可以根据这个ID进行流量控制了。

在管理端上进行配置后,lion会将配置推送到监听了该配置的客户端上。WallFilter收到配置后首先会检查限流是否开启且是否是本机Ip需要限流,然后根据配置创建过滤规则。在processSQL中计算每条SQL的Id,发现可以匹配时,利用随机数根据设定的流量比例进行控制,被拒绝的SQL会向上层服务配SQLException。

注意:根据SqlId限流时无法针对事务进行优化。

6 自动限流

开启自动限流策略后,zebra会维护一个时间窗口(窗口大小默认60s,可通过配置修改),统计过去一段时间内的状态,统计指标包括:

  • 失败连接请求数:滑动窗口内,拿连接失败的请求数
  • 总连接请求数:滑动窗口内,一共请求拿了多少次连接(总请求中不包括被限流的连接)

在滑动窗口内,失败率=失败连接请求数/总连接请求数,当失败率超过阈值时便触发自动限流,限制请求拿连接池中的连接

在自动限流触发后,如果失败率超过阈值,zebra需要减小流量,默认为每秒降指定比例的线性策略;当检测到失败率低于阈值时,开始恢复流量,默认也是线性恢复。

流量限制策略(参考上面配置,参数需要具体测试后再调整):

1.linear:n或linear:n,t 例如linear:5表示每秒减少5%的流量,直到达到下限,linear:5,2表示每2秒减少5%的流 量,时间间隔为2s

2.fast 表示出现问题后立即降低到下限,然后失败率小于阈值后再逐步恢复

流量恢复策略:

1.linear:n或linear:n,t 如linear:5表示在失败率小于阈值的时候,每秒增加5%的流量,直到达到完全恢复

2.exponential:n或exponential:n,t 表示以指数的形式恢复,exponential:3第一秒恢复3%的流量,第二秒6%,第三秒12%等等

eg.

以流量降低和恢复都是线性策略为例简单介绍下限流及恢复过程,下图中横轴表示时间,纵轴表示允许通过的连接请求比例。

在t=3时开始出现问题,失败率大于阈值,开始限制连接请求,按每秒百分之十的比例降低;在t=8达到设置的下限后不再继续下降;t=9时,失败率小于阈值,开始逐步恢复;t=12时,恢复到百分之八十,这时再次出现失败率大于阈值的情况,继续执行限流;t=13后开始恢复,t=16之后恢复正常。

7 强制限流

开启强制限流后,会对所有连接进行过滤,立即将流量降到下限。需要手动开启,用于在紧急情况下对流量进行快速限流,恢复正常后需要手动关闭(优先级大于自动限流)。