博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
限流(三)Redis + lua分布式限流
阅读量:6588 次
发布时间:2019-06-24

本文共 3064 字,大约阅读时间需要 10 分钟。

一、简介

1)分布式限流

如果是单实例项目,我们使用Guava这样的轻便又高性能的堆缓存来处理限流。但是当项目发展为多实例了以后呢?这时候我们就需要采用分布式限流的方式,分布式限流可以以redis + lua 或者 nignx + lua这样的组合来实现。。

分布式限流一般应用场景都是在业务上进行限流,所以本文不涉及niginx + lua,简单介绍redis + lua分布式限流的实现。如果是需要在接入层限流的话,应该直接采用nginx自带的连接数限流模块请求限流模块

 

2)redis

redis是一种键值对的单线程架构模型,所以它是线程安全的,也是分布式缓存常用的解决方案。(本文不涉及redis的分布式缓存,只是讲如何结合redis实现限流)

3)lua

lua是基于c语言的一种脚本语言,它可以很轻便地被使用在嵌入式方面。我们不会去重写redis,但是我们可以去使用lua来扩展redis的功能。而redis也内置了对lua支持的模块。

 

二、示例

示例图

 

1)启动redis服务

我们得确保redis安装,并使用: ./redis-server 命令启动redis服务端

redis常用命令:

./redis-server 启动服务端./redis-cli 启动客户端./redis-cli shutdown 关闭服务keys * 查看所有keyget 键 根据键获取值

2)编写lua脚本

创建limit.lua文件

local key = KEYS[1] --限流KEY(一秒一个)local limit = tonumber(ARGV[1]) --限流大小local current = tonumber(redis.call('get', key) or "0")if current + 1 > limit then --如果超出限流大小    return 0else --请求数+1,并设置2秒过期    redis.call("INCRBY", key,"1")    redis.call("expire", key,"1")    return 1end

1)我们通过KEYS[1] 获取传入的key参数

2)通过ARGV[1]获取传入的limit参数

3)redis.call方法,从缓存中get和key相关的值,如果为nil那么就返回0

4)接着判断缓存中记录的数值是否会大于限制大小,如果超出表示该被限流,返回0

5)如果未超过,那么该key的缓存值+1,并设置过期时间为1秒钟以后,并返回1

 

3)Java调用

java采用jedis来操作redis

引入redis依赖和apache io的工具包(方便读取lua文件的内容)

redis.clients
jedis
2.9.0
commons-io
commons-io
2.4

创建RedisLua.java文件

import org.apache.commons.io.FileUtils;import redis.clients.jedis.Jedis;import java.io.File;import java.io.IOException;import java.net.URISyntaxException;import java.util.ArrayList;import java.util.List;import java.util.concurrent.CountDownLatch;/** * @author lay * @date 2018/5/22. * @time 17:48 */public class RedisLua {    public static void main(String[] args) {        final CountDownLatch latch = new CountDownLatch(1);        for (int i = 0; i < 7; i++) {            new Thread(new Runnable() {                public void run() {                    try {                        latch.await();                        System.out.println(accquire());                    } catch (Exception e) {                        e.printStackTrace();                    }                }            }).start();        }        latch.countDown();    }    public static boolean accquire() throws IOException, URISyntaxException {        Jedis jedis = new Jedis("127.0.0.1");        File luaFile = new File(RedisLua.class.getResource("/").toURI().getPath() + "limit.lua");        String luaScript = FileUtils.readFileToString(luaFile);        String key = "ip:" + System.currentTimeMillis()/1000; // 当前秒        String limit = "5"; // 最大限制        List
keys = new ArrayList
(); keys.add(key); List
args = new ArrayList
(); args.add(limit); Long result = (Long)(jedis.eval(luaScript, keys, args)); // 执行lua脚本,传入参数 return result == 1; }}

以上模拟了多线程下,使用jedis连接redis服务,并执行lua脚本

 

4)输出结果

truetruefalsetruefalsetruetrue

我们看到,7个线程,其中2个线程被判断为false

 

参考文章:

转载于:https://www.cnblogs.com/lay2017/p/9074477.html

你可能感兴趣的文章
Nuget 管理报repositories.config 访问路径被拒绝 解决办法
查看>>
存储过程传递参数时出现类型转换错误!如:varchar转换为int时出错
查看>>
python list append 相关知识点
查看>>
C# 图像编程 (1) 准备工作; 你好,空姐; 为空姐照片添加特效
查看>>
NAND FLASH ECC校验原理与实现
查看>>
SQL SERVER的锁机制(二)——概述(锁的兼容性与可以锁定的资源)
查看>>
Jira中的BUG导出
查看>>
基于FPGA的跨时钟域信号处理——专用握手信号
查看>>
软考难点—软件开发模型(借鉴)
查看>>
操纵浏览器的历史记录
查看>>
2013年省赛总结
查看>>
C++多态性(续)
查看>>
迷你MVVM框架 avalonjs 0.71发布
查看>>
用C++设计一个不能被继承的类
查看>>
cocos2dx游戏开发必备工具之PhysicsEditor【ZT】
查看>>
vim配置之目录结构
查看>>
【Android LibGDX游戏引擎开发教程】第06期:图形图像的绘制(下)图片整合工具的使用...
查看>>
mysql-connector-java-5.1.22下载
查看>>
vim中设置tab的长度的方法
查看>>
林权抵押贷款政策出台 将实现林业资源变资本
查看>>