成都建設(shè)網(wǎng)站分享搜索引擎 磁力吧
LUA腳本語言是C開發(fā)的,類似存儲(chǔ)過程,是為了實(shí)現(xiàn)完整的原子性操作,可以用來補(bǔ)充redis弱事務(wù)的缺點(diǎn).
1、LUA腳本的好處
2、Lua腳本限流實(shí)戰(zhàn)
支持分布式
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;/*** 分布式限流的服務(wù)類*/
@Service
public class IsAcquire {//引入一個(gè)Redis的Lua腳本的支持private DefaultRedisScript<Long> getRedisScript;//判斷限流方法---類似于RateLimiterpublic boolean acquire(String limitKey,int limit,int expire) throws Exception{//連接RedisJedis jedis = new Jedis("127.0.0.1",6379);getRedisScript =new DefaultRedisScript<>();getRedisScript.setResultType(Long.class);//腳本執(zhí)行返回值 longgetRedisScript.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;}
}
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請(qǐng)求控制類 Contoller*/
@RestController
public class Controller {@AutowiredIsAcquire isAcquire;//手下的分布式限流//final RateLimiter rateLimiter = RateLimiter.create(5); //guava引入的令牌桶限流(非分布式,單機(jī))//秒殺接口@RequestMapping("/order")public String killProduct(@RequestParam(required = true) String name) throws Exception{//rateLimiter.tryAcquire(1); //調(diào)用if(isAcquire.acquire("iphone",10,60)){//60秒只能進(jìn)行10次System.out.println("業(yè)務(wù)成功!");return "恭喜("+name+"),搶到iphone!";}else{System.out.println("-----------業(yè)務(wù)被限流");return "對(duì)不起,你被限流了!";}}
}
rateLimiter.lua腳本如下:
--java端送入三個(gè)參數(shù)(1個(gè)key,2個(gè)param )string
--limitKey(redi中key的值)
local key =KEYS[1];
--limit(次數(shù))
local times = ARGV[1];
--expire(秒S)
local expire = ARGV[2];
--對(duì)key-value中的 value +1的操作 返回一個(gè)結(jié)果local afterval= redis.call('incr',key);
if afterval ==1 then --第一次redis.call('expire',key,tonumber(expire) ) --失效時(shí)間(1S) TLL 1Sreturn 1; --第一次不會(huì)進(jìn)行限制
end
--不是第一次,進(jìn)行判斷
if afterval > tonumber(times) then--限制了return 0;
endreturn 1;
以上簡單的計(jì)數(shù)器的方式,就是一種固定窗口的算法,可以實(shí)現(xiàn)對(duì)單個(gè)接口的限流.
3、限流算法
固定窗口算法的問題
解決方案:改為滑動(dòng)窗口,避免固定窗口的臨界問題
滑動(dòng)窗口演示地址:
https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat-protocol/index.html
漏桶算法
漏桶,令牌的算法的缺點(diǎn)就是時(shí)間復(fù)雜度:O(N),不適用于大并發(fā)的請(qǐng)求
滑動(dòng)窗口的缺點(diǎn)是需要雙方先定好協(xié)議