Java并发:分布式应用限流Redis+Lua实践

任何限流都不是漫无目的的,也不是一个开关就可以解决的问题,常用的限流算法有:令牌桶,漏桶。在之前的文章中,也讲到过,但是那是基于单机场景来写。

之前文章:接口限流算法:漏桶算法令牌桶算法

然而再牛逼的机器,再优化的设计,对于特殊场景我们也是要特殊处理的。就拿秒杀来说,可能会有百万级别的用户进行抢购,而商品数量远远小于用户数量。如果这些请求都进入队列或者查询缓存,对于最终结果没有任何意义,徒增后台华丽的数据。对此,为了减少资源浪费,减轻后端压力,我们还需要对秒杀进行限流,只需保障部分用户服务正常即可。

就秒杀接口来说,当访问频率或者并发请求超过其承受范围的时候,这时候我们就要考虑限流来保证接口的可用性,以防止非预期的请求对系统压力过大而引起的系统瘫痪。通常的策略就是拒绝多余的访问,或者让多余的访问排队等待服务。

分布式限流

单机限流,可以用到AtomicInteger、RateLimiter、Semaphore这些。但是在分布式中,就不能使用了。常用分布式限流用Nginx限流,但是它属于网关层面,不能解决所有问题,例如内部服务,短信接口,你无法保证消费方是否会做好限流控制,所以自己在应用层实现限流还是很有必要的。

本文不涉及Nginx+Lua,简单介绍Redis+Lua分布式限流的实现。如果是需要在接入层限流的话,应该直接采用nginx自带的连接数限流模块和请求限流模块。

Redis+Lua限流示例

本次项目使用SpringBoot2.0.4,使用到Redis集群,Lua限流脚本

引入依赖

org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-data-redisorg.springframework.bootspring-boot-starter-aoporg.apache.commonscommons-lang3org.springframework.bootspring-boot-starter-testRedis配置

application.properties

spring.application.name=spring-boot-limit#Redis数据库索引spring.redis.database=0#Redis服务器地址spring.redis.host=10.4.89.161#Redis服务器连接端口spring.redis.port=6379#Redis服务器连接密码spring.redis.password=#连接池最大连接数spring.redis.jedis.pool.max-active=8#连接池最大阻塞等待时间spring.redis.jedis.pool.max-wait=-1#连接池中的最大空闲连接spring.redis.jedis.pool.max-idle=8#连接池中的最小空闲连接spring.redis.jedis.pool.min-idle=0#连接超时时间spring.redis.timeout=10000Lua脚本

参考:聊聊高并发系统之限流特技http://jinnianshilongnian.iteye.com/blog/2305117

localkey="rate.limit:"..KEYS[1]--限流KEYlocallimit=tonumber--限流大小localcurrent=tonumberor"0")ifcurrent+1limitthen--如果超出限流大小return0else--请求数+1,并设置2秒过期redis.callredis.callreturncurrent+1end

1、我们通过KEYS[1]获取传入的key参数2、通过ARGV[1]获取传入的limit参数3、redis.call方法,从缓存中get和key相关的值,如果为nil那么就返回04、接着判断缓存中记录的数值是否会大于限制大小,如果超出表示该被限流,返回05、如果未超过,那么该key的缓存值+1,并设置过期时间为1秒钟以后,并返回缓存值+1

(责任编辑:电玩之家app)

本文地址:/gaokao/20200606/5838.html

上一篇:排队在1200余万位,我提前拿回了电玩之家app我的ofo押金

下一篇:沃伦·巴菲特最喜欢的百科全书成为他的最棘手的问题

留下评论

(必填)

(必填)