redis+lua限流

作者: lesline | 来源:发表于2019-10-25 09:25 被阅读0次

    nginx+lua(openresty/kong)

    Lua 是一种轻量小巧的脚本语言,动态解释型语言 ,一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。
    主要特点是:程序代码级热更新,下载最新代码,实时更新,实时更新,不需要编译环节,比如Nginx
    

    1: 比如游戏引擎领域的cocos2d-x、unity,由于引擎自身使用的c++或者c#作为编写语言,游戏前端发布后,发现bug或者发布新逻辑,都需要重新出包,周期过长,lua作为脚本语言,可以以资源的形式下载,重新加载运行,周期快,且效率损失有限
    2:服务端使用,比较火的也就是nginx+lua的形式,后来整合成框架openresty,基本也是利用nginx的高性能+lua脚本的灵活性,逻辑修改之后只需要触发重新加载脚本就可以,开发运行效率都比较高,相比传统c++、java等需要重新编译部署,开发效率高很多

    京东实现

    1. 有一个定时任务10秒更新限流配置(黑白名单和限流开关)
      local ok, err = new_timer(delay, refresh)
    2. 主要逻辑
    -- 规则设置
    -- 排队规则,即并发数控制+防刷规则,即请求频率控制(集群TPS,用户TPS,单IP的TPS[取不到用户的时候才生效])
    -- AddOn:当前代码无法校验TrackID合法性,故全部使用IP限流,请注意第三个数字!!!(忽略第二个)
    global_key_rules = {
      ['/cart/add_to_cart_ajax.html'] = {1000, -1, 50},
      ['/cart/fetch_cart_num.html'] = {1000, -1, 50},
      ['/cart/sync_cart.html'] = {500, -1, 30},
      ['/order/confirm_order.html'] = {500, -1, 30},
      ['/order/sync_order_cart.html'] = {500, -1, 30},
      ['/order/edit_user_address.html'] = {300, -1, 20},
      ['/order/sync_user_coupon.html'] = {500, -1, 30},
      ['/order/submit_order.html'] = {200, -1, 20}
    }
    -- 主要判断逻辑 
    -- key 为限制的资源
    -- size 为TPS值
    function limit(red, key, size)
        --访问量+1
        local count = red:incr(key)
        -- 判断是否过期,如果过期,修改过期时间为1秒,ttl返回剩余的生存时间,key不
        local ttl = red:ttl(key)
        if ttl < 0 then
          local time = red:expire(key,1)
        end
        -- 判断超过TPS,超过则限流
        if count > size  then
           return false
        end
        return true
     end
    

    ttl是为防止某些key在未设置超时时间并长时间已经存在的情况下做的保护的判断;

    Redis TTL 命令:
    当 key 不存在时,返回 -2 。
    当 key 存在但没有设置剩余生存时间时,返回 -1 。
    否则,以毫秒为单位,返回 key 的剩余生存时间。

    Redis Incr 命令:
    将 key 中储存的数字值增一。
    如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作

    通过redis防止重复提交(无并发限流)

    通过redis也可以在服务层做限流,缺点是此时流量已打到服务器,没有在nginx层做防护好。
    不过,可以在服务层做些防重复提交的防护,示例如下:
    例如:PC端查询订单列表,同一用户和相同查询条件100毫秒内只能查询一次

    通过Redis 字符串命令SETEX key seconds value实现
    setex 惟一标识 过期时间 当前时间
    其中:key:为资源惟一标识=uid+param
    seconds:过期时间=repeat_request_ttl
    valule:当前时间

    repeat_request_ttl: 每次查询的时间间隔=100
    表示:同一用户和相同查询条件100毫秒内只参查询一次

    if(key 存在){
      获取key值的value=上次请求时间
      if(上次请求时间<repeat_request_ttl){
         请求频率过快
       }
    }
    set key 当前时间 过期时间
    

    相关文章

      网友评论

        本文标题:redis+lua限流

        本文链接:https://www.haomeiwen.com/subject/fzojvctx.html