Chinaunix首页 | 论坛 | 博客
  • 博客访问: 8077377
  • 博文数量: 594
  • 博客积分: 13065
  • 博客等级: 上将
  • 技术积分: 10324
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-26 16:44
个人简介

推荐: blog.csdn.net/aquester https://github.com/eyjian https://www.cnblogs.com/aquester http://blog.chinaunix.net/uid/20682147.html

文章分类

全部博文(594)

分类: C/C++

2016-09-08 00:06:53

优点:可支持海量访问的频率控制,只需要增加Redis机器,单个Redis节点(只占用一个cpu core)即可支持10万/s以上的处理。
基于IP频率限制是种常见需求,基于Redis可以十分简单实现对IP的频率限制,具体手段为利用Redis的key过期和原子加减两个特性。
以IP作为key,频率为key过期时长,比如限制单个IP在2秒内频率为100,则key过期时长为2秒,基于(a Redis Cluster C++ Client)的实现大致如下:

  1. r3c::CRedisClient redis("127.0.0.1:6379,127.0.0.1:6380");
  2. int ret = redis.incrby(ip, 1);
  3. if (ret > 1000) // 超过频率
  4. {
  5. }
  6. else // 访问放行
  7. {
  8.     if (1 == ret)
  9.         redis.expire(ip, 2); // 频率控制为2秒内1000次访问
  10. }

完整示例:

  1. // https://github.com/eyjian/r3c
  2. #include <r3c/r3c.h>

  3. int main()
  4. {
  5.     std::string ip = "127.0.0.1";
  6.     r3c::CRedisClient redis("10.223.25.102:6379");
  7.     r3c::set_debug_log_write(NULL);
  8.     for (int i=0; i<100000; ++i)
  9.     {
  10.         // r3c基于redis的EVAL命令提供了一个带过期参数的incrby,
            // 这样避免了两次操作的非原子时expire调用可能不成功问题。
  11.         int ret = redis.incrby(ip, 1);
  12.         if (ret > 1000) // 限制单个IP每2秒最多访问1000次
  13.         {
  14.             printf("[OVER] 超过频率,限制访问\n");
  15.         }
  16.         else
  17.         {
  18.             if (1 == ret)
  19.             {
  20.                 redis.expire(ip, 2); // 频率设定为2秒
  21.                 printf("[FIRST] 第一次,访问放行\n");
  22.             }
  23.             else
  24.             {
  25.                 printf("[OK] 访问放行\n");
  26.             }
  27.         }
  28.     }
  29.     redis.del(ip);
  30.     return 0;
  31. }



阅读(14592) | 评论(2) | 转发(1) |
给主人留下些什么吧!~~

Aquester2016-11-16 19:27:32

Aquester:http://redis.io/commands/incr

If for some reason the client performs the INCR command but does not perform the EXPIRE the key will be leaked until we\'ll see the same IP address again.
This can be fixed easily turning the INCR with optional EXPIRE into a Lua script that is send using the EVAL command (only available since&

int64_t increment = 2016;
uint32_t expired_seconds = 100;
rc.incrby(key, increment , increment , expired_seconds);

回复 | 举报

Aquester2016-09-12 12:35:55

http://redis.io/commands/incr

If for some reason the client performs the INCR command but does not perform the EXPIRE the key will be leaked until we\'ll see the same IP address again.
This can be fixed easily turning the INCR with optional EXPIRE into a Lua script that is send using the EVAL command (only available since&