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) ,不适用于大并发的请求

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

相关推荐
不想写bug呀2 小时前
Redis主从复制介绍
数据库·redis
XT46254 小时前
交易、订单轮询策略(能用数据库轮询解决的不用Redis,能用Redis解决的不用消息队列)
数据库·redis·bootstrap
梦茹^_^6 小时前
flask框架(笔记一次性写完)
redis·python·flask·cookie·session
panzer_maus6 小时前
Redis简单介绍(3)-持久化的实现
java·redis·mybatis
wWYy.6 小时前
详解redis(1)
数据库·redis·缓存
麦兜*7 小时前
SpringBoot集成Redis缓存,提升接口性能的五大实战策略
spring boot·redis·缓存
晓13137 小时前
第一章:Redis 安装与入门
redis·json·nosql
晓131311 小时前
第二章:Redis常见命令与Java客户端
java·数据库·redis
填满你的记忆11 小时前
【从零开始——Redis 进化日志|Day7】双写一致性难题:数据库与缓存如何不再“打架”?(附 Canal/读写锁实战)
java·数据库·redis·缓存·面试
小冷coding11 小时前
【Java】以 Java + Redis + MySQL 为技术栈,模拟电商商品详情的读写场景,Cache Aside+ 延迟双删 方案
java·redis·mysql