首页 > 解决方案 > limit_req 按一天中的时间区分区域

问题描述

我想根据一天中的时间限制对我的服务的请求。
夜间 (21:00 - 06:59) 应为 4 r/s,白天 (07:00-20:59) 应为 1 r/s。
我可以有2个不同的req_limit_zone喜欢

limit_req_zone $server_name zone=day:1m rate=1r/s;
limit_req_zone $server_name zone=night:1m rate=4r/s;

但是我如何limit_req根据一天中的时间来区分它们呢?

nginx 背后的服务是另一个服务的 API 包装器,具有上述限制。Flask-RESTful我的服务是uWSGIredis.

可以这样配置nginx吗?
如果不是,是否有任何常见的解决方法?其他服务如何解决此任务?
更具体地说,它应该是一个泄漏的存储桶,因此客户端只需等待没有任何错误的答案,例如 HTTP 429 Too Many Requests。

标签: nginxrate-limiting

解决方案


答案

关键是绑定limit_req_zonemap。文档中有两个关于它们的相关说明。地图

默认

如果源值不匹配任何指定的变体,则设置结果值。如果default未指定,则默认结果值为空字符串

limit_req_zone

limit_req_zone key zone=name:size rate=rate;

为共享内存区域设置参数,该区域将保持各种键的状态。特别是,状态存储当前过多请求的数量。可以包含文本、key变量及其组合。不计入空键值的请求

因此,如果它应该工作,则只需使用白天夜晚 作为键,如果不应该使用空字符串。并将根据一天中的时间返回一个或空字符串。limit_req_zone$server_namemap$server_name

map $date_gmt $day {  
    # 07:00-20:59 GMT  
    ~(0[7-9]|1[0-9]|20):[0-5][0-9]:[0-5][0-9] $server_name;  
}

map $date_gmt $night {  
    # 21:00-06:59 GMT  
    ~(2[1-4]|0[0-6]):[0-5][0-9]:[0-5][0-9] $server_name;  
}

limit_req_zone $day zone=day_zone:1m rate=1r/s;
limit_req_zone $night zone=night_zone:1m rate=4r/s;

...

limit_req zone=day_zone burst=100;
limit_req zone=night_zone burst=100;

关于的一些注意事项req_limit

第一次尝试我尝试在 中使用映射变量limit_req,但 nginx 不理解这样的语法。此外,乍一看nginx -s reload没有任何问题,但实际上没有任何重新加载,只service nginx restart显示错误(nginx版本:1.12.2)。所以我想展示一个人不应该怎么做

limit_req_zone $server_name zone=day:1m rate=1r/s;
limit_req_zone $server_name zone=night:1m rate=4r/s;

map $date_gmt $time_of_day {  
    ~(0[7-9]|1[0-9]|20):[0-5][0-9]:[0-5][0-9] day;  
    ~(2[1-4]|0[0-6]):[0-5][0-9]:[0-5][0-9] night;  
}

...

limit_req zone=$time_of_day burst=100;  

关于性能的一些说明

这不是最好的解决方案,因为对每个请求都要进行两次检查。可以选择拥有两个单独的 nginx 配置并使用 cron 之类的东西切换它们。这将是丑陋和错误的,因为你应该记得编辑两个配置,但它会工作得更快;我认为这个选项应该作为最后的手段。如果有水平扩展的能力,最好负载平衡多台服务器。就我而言,这没什么大不了的:服务每小时只收到大约 8k 个请求(2.2 r/s)。


推荐阅读