案例-实现访问频率限制: 实现访问者 $ip 在一定的时间 $time 内只能访问 $limit 次.
  • 非脚本实现
private boolean accessLimit(String ip, int limit, int time, Jedis jedis) {
boolean result = true; String key = "rate.limit:" + ip;
if (jedis.exists(key)) {
long afterValue = jedis.incr(key);
if (afterValue > limit) {
result = false;
}
} else {
Transaction transaction = jedis.multi();
transaction.incr(key);
transaction.expire(key, time);
transaction.exec();
}
return result;
}
  • 以上代码有两点缺陷 
    1. 可能会出现竞态条件: 解决方法是用 WATCH 监控 rate.limit:$IP 的变动, 但较为麻烦;
    2. 以上代码在不使用 pipeline 的情况下最多需要向Redis请求5条指令, 传输过多.

  • Lua脚本实现 
    Redis 允许将 Lua 脚本传到 Redis 服务器中执行, 脚本内可以调用大部分 Redis 命令, 且 Redis 保证脚本的原子性:

    • 首先需要准备Lua代码: script.lua
--
-- Created by IntelliJ IDEA.
-- User: jifang
-- Date: 16/8/24
-- Time: 下午6:11
-- local key = "rate.limit:" .. KEYS[1]
local limit = tonumber(ARGV[1])
local expire_time = ARGV[2] local is_exists = redis.call("EXISTS", key)
if is_exists == 1 then
if redis.call("INCR", key) > limit then
return 0
else
return 1
end
else
redis.call("SET", key, 1)
redis.call("EXPIRE", key, expire_time)
return 1
end
  • Java
private boolean accessLimit(String ip, int limit, int timeout, Jedis connection) throws IOException {
List<String> keys = Collections.singletonList(ip);
List<String> argv = Arrays.asList(String.valueOf(limit), String.valueOf(timeout)); return 1 == (long) connection.eval(loadScriptString("script.lua"), keys, argv);
} // 加载Lua代码
private String loadScriptString(String fileName) throws IOException {
Reader reader = new InputStreamReader(Client.class.getClassLoader().getResourceAsStream(fileName));
return CharStreams.toString(reader);
}

  • Lua 嵌入 Redis 优势: 
    1. 减少网络开销: 不使用 Lua 的代码需要向 Redis 发送多次请求, 而脚本只需一次即可, 减少网络传输;
    2. 原子操作: Redis 将整个脚本作为一个原子执行, 无需担心并发, 也就无需事务;
    3. 复用: 脚本会永久保存 Redis 中, 其他客户端可继续使用.

Redis两种方式实现限流的更多相关文章

  1. ubuntu 安装redis两种方式 教程

    方式一: 下载地址:http://redis.io/download,下载最新文档版本. 本教程使用的最新文档版本为 2.8.17,下载并安装: $ wget http://download.redi ...

  2. Redis实战(二)CentOS 7上Redis两种方式持久化

    Redis的持久化之RDB RDB方式是通过快照完成的,当符合一定条件时Redis会自动将内存中的所有数据进行快照并且存储到硬盘上. 进行快照的条件在配置文件中指定,有2个参数构成:时间和改动的键的个 ...

  3. 基于redis实现的四种常见的限流策略

    引言 在web开发中功能是基石,除了功能以外运维和防护就是重头菜了.因为在网站运行期间可能会因为突然的访问量导致业务异常.也有可能遭受别人恶意攻击 所以我们的接口需要对流量进行限制.俗称的QPS也是对 ...

  4. Redis两种持久化方式(RDB&AOF)

    爬虫和转载请注明原文地址;博客园蜗牛:http://www.cnblogs.com/tdws/p/5754706.html Redis所需内存 超过可用内存怎么办 Redis修改数据多线程并发—Red ...

  5. Redis的持久化的两种方式drbd以及aof日志方式

    redis的持久化配置: 主要包括两种方式:1.快照  2 日志 来看一下redis的rdb的配置选项和它的工作原理: save 900 1 // 表示的是900s内,有1条写入,则产生快照 save ...

  6. IOS文件操作的两种方式:NSFileManager操作和流操作

    1.常见的NSFileManager文件方法 -(NSData *)contentsAtPath:path //从一个文件读取数据 -(BOOL)createFileAtPath: path cont ...

  7. Redis持久化的两种方式(RDB和AOF)

    redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File). RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储 ...

  8. 实现Comet(服务器推送)的两种方式:长轮询和http流

    Comet 是一种高级的Ajax技术,实现了服务器向页面实时推送数据的技术,应用场景有体育比赛比分和股票报价等. 实现Comet有两种方式:长轮询与http流 长轮询是短轮询的翻版,短轮询的方式是:页 ...

  9. Redis持久化的两种方式和区别

    该文转载自:http://www.cnblogs.com/swyi/p/6093763.html Redis持久化的两种方式和区别 Redis是一种高级key-value数据库.它跟memcached ...

随机推荐

  1. 十五丶IO model

    事件驱动模型 上节的问题: 协程:遇到IO操作就切换. 但什么时候切回去呢?怎么确定IO操作完了? 很多程序员可能会考虑使用“线程池”或“连接池”.“线程池”旨在减少创建和销毁线程的频率,其维持一定合 ...

  2. angular2 图片赋值的时候前面自动加 unsafe:xxx 导致图片信息不显示问题

    需要创建一个pipe 代码如下 import { Pipe, PipeTransform } from '@angular/core'; import {DomSanitizer} from '@an ...

  3. 创建自己的library类库包并使用webpack4.x打包发布到npm

    创建自己的library类库包并使用webpack4.x打包发布到npm 我们在开发过程中,可能经常要使用第三方类库,比如jquery.lodash等.我们通过npm,下载安装完之后,就可以使用了,简 ...

  4. 手把手带你入门kubernetes部署

    实验环境准备 k8s-master   192.168.2.156 k8s-node节点   192.168.2.161 Ps:两台保证时间同步,firewalld防火墙关闭,selinxu关闭,系统 ...

  5. UOJ#335. 【清华集训2017】生成树计数 多项式,FFT,下降幂,分治

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ335.html 前言 CLY大爷随手切这种题. 日常被CLY吊打系列. 题解 首先从 pruffer 编码的角度考虑这个问 ...

  6. jquery的选择器——[作为学习备用]

    1,转载:https://www.cnblogs.com/onlys/articles/jQuery.html jQuery 的选择器可谓之强大无比,这里简单地总结一下常用的元素查找方法 $(&quo ...

  7. Hadoop HDFS安装、环境配置

    hadoop安装 进入Xftp将hadoop-2.7.3.tar.gz 复制到自己的虚拟机系统下的放软件的地方,我的是/soft/software 在虚拟机系统装软件文件里,进行解压缩并重命名 进入p ...

  8. c语言博客作业--结构体&文件

    1.本章学习总结 1.1思维导图 1.2.本章学习体会 本章学到了结构体如何构建,用typedef进行重定义结构体,结构指针,访问结构体的方式等. 文件:文件的读取,文件读写的几个函数,基本了解了文本 ...

  9. DW1000 用户手册中文版 附录3:双向测距(Two-Way Ranging)

    由于已经在wode中排版无法直接复制到博客中,故本节博客发布使用了图片. 论坛可下载PDF  http://bphero.com.cn/forum.php?mod=viewthread&tid ...

  10. SpringBoot整合多数据源实现

    项目架构 1.导入相关依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifac ...