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

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

相关推荐
想用offer打牌2 小时前
面试官问:Redis和MySQL数据一致,为什么还需要MySQL?🤠
数据库·redis·mysql
chen.@-@2 小时前
后端下载限速(redis记录实时并发,bucket4j动态限速)
数据库·redis·缓存
呼拉拉呼拉2 小时前
Redis高可用架构
数据库·redis·架构·高可用架构
编程乐学(Arfan开发工程师)3 小时前
42、响应处理-【源码分析】-浏览器与PostMan内容协商完全适配
java·spring boot·后端·测试工具·lua·postman
用户79117724235833 小时前
黑马点评【基于redis实现共享session登录】
java·redis
观无4 小时前
redis分布式锁
数据库·redis·分布式
颜淡慕潇4 小时前
Redis 实现分布式锁:深入剖析与最佳实践(含Java实现)
java·redis·分布式
CV点灯大师5 小时前
C++算法训练营 Day10 栈与队列(1)
c++·redis·算法
啾啾Fun5 小时前
【Java微服务组件】分布式协调P4-一文打通Redisson:从API实战到分布式锁核心源码剖析
java·redis·分布式·微服务·lua·redisson
多多*8 小时前
LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考
linux·开发语言·redis·python·bootstrap·lua