8 Redis与Lua

LUA脚本语言是C开发的,类似存储过程,是为了实现完整的原子性操作,可以用来补充redis弱事务的缺点.

1、LUA脚本的好处
2、Lua脚本限流实战

支持分布式

java 复制代码
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

/**
 * 分布式限流的服务类
 */
@Service
public class IsAcquire {
    //引入一个Redis的Lua脚本的支持
    private DefaultRedisScript<Long> getRedisScript;



    //判断限流方法---类似于RateLimiter
    public boolean acquire(String limitKey,int limit,int expire) throws  Exception{
        //连接Redis
        Jedis jedis =  new Jedis("127.0.0.1",6379);
        getRedisScript =new  DefaultRedisScript<>();
        getRedisScript.setResultType(Long.class);//脚本执行返回值 long
        getRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("rateLimiter.lua")));
        Long result = (Long)jedis.eval(getRedisScript.getScriptAsString(),
                1,limitKey,String.valueOf(limit),String.valueOf(expire));
        if(result ==0){
            return false;
        }
        return true;
    }
}
java 复制代码
import com.google.common.util.concurrent.RateLimiter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 类说明:接口类,抢购接口
 * http请求控制类  Contoller
 */
@RestController
public class Controller {
    @Autowired
    IsAcquire isAcquire;//手下的分布式限流

    //final  RateLimiter rateLimiter = RateLimiter.create(5);  //guava引入的令牌桶限流(非分布式,单机)
    //秒杀接口
    @RequestMapping("/order")
    public String killProduct(@RequestParam(required = true) String name) throws Exception{
        //rateLimiter.tryAcquire(1); //调用
        if(isAcquire.acquire("iphone",10,60)){//60秒只能进行10次
            System.out.println("业务成功!");
            return "恭喜("+name+"),抢到iphone!";
        }else{
            System.out.println("-----------业务被限流");
            return "对不起,你被限流了!";
        }

    }
}

rateLimiter.lua脚本如下:

java 复制代码
--java端送入三个参数(1个key,2个param  )string
--limitKey(redi中key的值)
local key =KEYS[1];
--limit(次数)
local times = ARGV[1];
--expire(秒S)
local expire = ARGV[2];
--对key-value中的 value +1的操作  返回一个结果

local afterval=  redis.call('incr',key);
if afterval ==1 then --第一次
    redis.call('expire',key,tonumber(expire) )  --失效时间(1S)  TLL 1S
    return 1; --第一次不会进行限制
end
--不是第一次,进行判断
if afterval > tonumber(times) then
    --限制了
    return 0;
end

return 1;

以上简单的计数器的方式,就是一种固定窗口的算法,可以实现对单个接口的限流.

3、限流算法
固定窗口算法的问题

解决方案:改为滑动窗口,避免固定窗口的临界问题

滑动窗口演示地址:

java 复制代码
https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat-protocol/index.html
漏桶算法



漏桶,令牌的算法的缺点就是时间复杂度:O(N) ,不适用于大并发的请求

滑动窗口的缺点是需要双方先定好协议

相关推荐
xiaoqiMikko18 小时前
Redis 实战(二):宕机会丢多少数据 —— kill -9 与真断电下 RDB / AOF 逐个实测(6.2.4)
redis·后端
夕除20 小时前
redis--ziplist
redis
2301_322414280421 小时前
基于SSM框架的在线考试管理系统的设计与实现14750-计算机毕设 原创(免费领源码+部署教程+开发环境)
java·redis·mysql·tomcat·maven·mybatis·ssm
我星期八休息1 天前
Redis 的原理和使用(2)
前端·数据库·redis·python·mysql·缓存·bootstrap
笨鸟先飞的橘猫1 天前
skynet热更新实现问题与排错记录
学习·lua·skynet
imDwAaY2 天前
操作系统如何管理程序运行?从线程、进程到内存隔离与用户态切换:CS162 Note2
android·java·redis
码途行者2 天前
处理超时未支付订单:两套轻量化方案,附 PHP 极简实现
开发语言·redis·php
草莓熊Lotso2 天前
【C++ 基于微服务的即时通讯系统】etcd + brpc 从安装到服务注册发现全链路实战
网络·数据库·c++·redis·微服务·etcd
我不会起名字3222 天前
Redis 突然只能读不能写:MISCONF 报错的 3 类触发条件与 4 步恢复
运维·redis·持久化·排查·misconf
我不会起名字3222 天前
Redis 从 0 到 1(九):主库宕机 30 秒自动切主——1 主 2 从 3 哨兵 + Go 客户端
redis·docker·sentinel·高可用·哨兵