分布式限流解决方案-Redis+Lua
1、分析
黑客或者一些恶意的用户为了攻击网站或者APP,通过并发用肉机并发或者死循环请求接口,从而导致系统出现宕机。
- 针对新增数据的接口,会出现大量的重复数据,甚至垃圾数据会将数据库和CPU或者内存磁盘耗尽,直到数据库撑爆为止。
- 针对查询的接口。一般是重点攻击慢查询,比如一个SQL是2S。只要一致攻击,就必然造成系统被拖垮,数据库查询全都被阻塞,连接一直得不到释放造成数据库无法访问。
一个用户在1秒钟之内,只允许请求n次。
2、Redis + Lua实现限流解决方案
2.1 redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--这里就是redis的核心jar包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.2 限流userLimit.lua脚本
-- 限流
-- 获取方法签名特征
local key = KEYS[1]
-- 调用脚本传入的限流大小
local limit = tonumber(ARGV[1])
-- 获取当前流量大小
local count = tonumber(redis.call('get',key) or "0")
-- 是否超出限流阈值
if count + 1 > limit then
-- 拒绝服务
return false
else
-- 没有超过阈值
-- 设置当前访问的数量 + 1
redis.call("incr",key)
-- 设置过期时间
redis.call("expire",key,ARGV[2])
return true
end
3.3 加载lua脚本的DefaultRedisScript对象
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
/**
* @Auther: 长颈鹿
* @Date: 2021/08/16/12:48
* @Description: 将lua脚本的内容加载出来放入到DefaultRedisScript
*/
@Configuration
public class LuaConfiguration {
@Bean
public DefaultRedisScript<Boolean> limitUserAccessLua() {
// 初始化一个lua脚本的对象DefaultRedisScript
DefaultRedisScript<Boolean> defaultRedisScript = new DefaultRedisScript<>();
// 通过这个对象去加载lua脚本的位置 Class