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

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

相关推荐
安冬的码畜日常5 小时前
【JUnit实战3_12】第七章:用 Stub 模拟进行粗粒度测试
测试工具·junit·单元测试·junit5·stub模拟·模拟技术·stub 桩
小丁爱养花10 小时前
Redis 内部编码/单线程模型/string
数据库·redis·缓存·1024程序员节
爬山算法10 小时前
Redis(84)如何解决Redis的缓存击穿问题?
java·redis·缓存
赵庆明老师12 小时前
C# 结合Redis Cache 访问MySQL数据库
数据库·redis·c#
李少兄14 小时前
记一次 Spring Boot 项目中 Redis 工具类的重构实践
spring boot·redis·重构
Merlos_wind15 小时前
【Redis典型应用——缓存详解】
数据库·redis·缓存
摇滚侠15 小时前
Spring Boot3零基础教程,整合 Redis,笔记69
spring boot·redis·笔记
烛阴15 小时前
彻底搞懂Lua闭包
前端·lua
DemonAvenger15 小时前
Redis性能优化实战:从配置调优到代码实现的全面指南
数据库·redis·性能优化
阿祥~19 小时前
windows 安装 Redis
数据库·redis·缓存