当前位置: 首页 > news >正文

新泰做网站东莞疫情最新消息

新泰做网站,东莞疫情最新消息,网站建设与管理方案书,wordpress 没有保存基于 Redis 实现分布式限流 一、 简介二、分布式限流1 数据结构1.1 Redis List1.2 Redis Set1.3 Redis Sorted Set 2 实现分布式限流3 实现原理分析 三、分布式限流算法1. 计数器算法2. 漏斗算法3. 令牌桶算法 四、分布式限流实战1. 单机限流实现2. 基于Redis Clusters的分布式…

基于 Redis 实现分布式限流

  • 一、 简介
  • 二、分布式限流
      • 1 数据结构
        • 1.1 Redis List
        • 1.2 Redis Set
        • 1.3 Redis Sorted Set
      • 2 实现分布式限流
      • 3 实现原理分析
  • 三、分布式限流算法
    • 1. 计数器算法
    • 2. 漏斗算法
    • 3. 令牌桶算法
  • 四、分布式限流实战
    • 1. 单机限流实现
    • 2. 基于Redis Clusters的分布式限流实现
  • 五、基于Redis分布式限流的优化
    • 1. 缓存击穿
      • 1.1 问题描述
      • 1.2 解决方案
        • 1.2.1 使用互斥锁
        • 1.2.2 使用预热机制
    • 2. 热点key问题的解决方案
      • 2.1 问题描述
      • 2.2 解决方案
        • 2.2.1 分布式锁
        • 2.2.2 分布式缓存
    • 3. 并发竞争优化
      • 3.1 问题描述
      • 3.2 解决方案
        • 3.2.1 使用限流器
        • 3.2.2 使用异步线程池

一、 简介

分布式限流是指通过将限流策略嵌入到分布式系统中,以控制流量或保护服务,保证系统在高并发访问情况下不被过载。

分布式限流可以防止系统因大量请求同时到达导致压力过大而崩溃,从而提高系统的稳定性和可靠性。同时,它可以使得业务资源能够更好地分配,提高系统的效率。

二、分布式限流

1 数据结构

1.1 Redis List

Redis List 是一个可以输入相同元素和非唯一元素的集合且支持在两端进行快速(O(1))插入和删除元素。

1.2 Redis Set

Redis Set 是一个无序,但不允许重复元素的集合。您可以使用这些命令对Redis集进行常规操作: SADD,SREM,SISMEMBER,SMEMBERS等。

1.3 Redis Sorted Set

Redis Sorted Set 是一个有序的、不重复的元素集合。每个元素都关联着一个浮点数值(称为 Score)。通过 Score 可以从小到大排序得到一个有序集合。

2 实现分布式限流

在Redis中可以使用令牌桶算法来实现分布式限速。具体方法为:

Step 1:创建一个列表作为Redis令牌桶

String key = "rate_limit:" + userId;
// 模拟用户请求访问
List<String> tokens = redis.lrange(key, 0, -1);

Step 2:设定令牌桶的基准参数

int maxTokens = 50;
long timeInterval = 1 * 1000;
long now = System.currentTimeMillis();

Step 3:计算Redis中令牌数量

long expiredTokens = tokens.stream().filter(t -> Long.parseLong(t) < now - timeInterval).count();
tokens = tokens.subList((int) expiredTokens, tokens.size());
long remainTokens = maxTokens - tokens.size();

Step 4:基于令牌数量,判断是否超过限制

if (remainTokens < 1) {throw new RateLimitException("请求太频繁,请稍后再试!");
}

Step 5:如果没有超出限制,则更新Redis中令牌数并设置过期时间

Long expiresIn = now + timeInterval;
redis.multi();
redis.rpush(key, String.valueOf(expiresIn));
redis.pexpire(key, timeInterval);
redis.exec();

3 实现原理分析

以上代码所示首先需要建立Redis List用于存储Token,其次需要设定令牌桶的基准参数(比如最大Token数量和Token过期间隔等)。在用户访问请求时,需要计算Redis中的令牌数量,根据规则对访问量进行限制。如果没有超过限制,则需要更新Redis List中令牌数并设置过期时间;如果超过了限制,则需要返回错误信息并拒绝服务。

整个过程中,需要注意并发访问情况下的线程安全问题,并确保流量控制配置的公共协商,如最大QPS(Queries Per Second),哪些接口需限制流量等。

三、分布式限流算法

在实际的系统设计中,为了防止某一时刻出现大量请求导致系统崩溃,我们通常会采用限流策略来控制流量,而Redis作为分布式NoSQL数据库,在限流中也有着广泛的应用。下面介绍一些Redis分布式限流的经典算法。

1. 计数器算法

计数器算法比较简单,直接利用Redis存储每个IP或者用户的请求次数,当请求次数超过预设阈值时拒绝服务。代码如下:

public boolean isAllowed(String key, int limit, int timeout) {Jedis jedis = getJedis();long count = jedis.incr(key);if (count == 1) {jedis.expire(key, timeout);}boolean allowed = count <= limit;if (!allowed) {jedis.del(key);}jedis.close();return allowed;
}
  • key:需要限流的用户标识,可根据IP、UserID等进行定义
  • limit:阈值,即允许的最大请求数
  • timeout:过期时间,对于计数器算法,一定要设置过期时间,否则缓存中的请求次数会一直不断累加

2. 漏斗算法

漏斗算法的核心思想是将请求按照恒定的速率转换为水流,有效控制请求超出服务处理能力的情况。漏斗算法实现代码如下:

public boolean isAllowed(String key, int capacity, double leakRate, int reqCount) {Jedis jedis = getJedis();long nowTime = System.currentTimeMillis();String luaScript ="local currentCapacity = tonumber(redis.call('hget', KEYS[1], 'leftCapacity'))\n"+ "if currentCapacity == nil then\n"+ "    redis.call('hset', KEYS[1], 'lastTime', ARGV[2])\n"+ "    redis.call('hset', KEYS[1], 'leftCapacity', ARGV[1] - 1)\n"+ "    return 1\n"+ "end\n"+ "local changeTime = tonumber(redis.call('hget', KEYS[1], 'lastTime'))\n"+ "local delayMillSeconds = nowTime - changeTime\n"+ "local currentDelayCount = tonumber(delayMillSeconds*ARGV[3])\n"+ "local currentCapacity = math.min(currentDelayCount+currentCapacity, ARGV[1])\n"+ "if currentCapacity >= ARGV[4] then\n"+ "    return 0\n"+ "else\n"+ "    redis.call('hset', KEYS[1], 'leftCapacity', currentCapacity-1)\n"+ "    redis.call('hset', KEYS[1], 'lastTime', nowTime)\n"+ "    return 1\n"+ "end";Object result = jedis.eval(luaScript,Collections.singletonList(key),Arrays.asList(String.valueOf(capacity), String.valueOf(nowTime), String.valueOf(leakRate), String.valueOf(reqCount)));boolean allowed = (result instanceof Long ? (Long) result : 0L) == 1L;jedis.close();return allowed;
}
  • key:需要进行限流的用户标识
  • capacity:漏斗容量,即最大允许请求数量
  • leakRate:漏嘴流水速率,保证有序的请求到达
  • reqCount:预计请求量,用于计算漏斗每次流出的数量

3. 令牌桶算法

令牌桶算法的特点是以一个固定的速率不断产生令牌,并将令牌放入到桶中,访问时若桶为空,则表示请求数超限。令牌桶算法实现代码如下:

public boolean isAllowed(String key, int capacity, double rate, int reqCount) {long nowTime = System.currentTimeMillis();Jedis jedis = getJedis();String luaScript ="local currentLimit = tonumber(redis.call('get', KEYS[1]) or '0')\n"+ "if currentLimit + ARGV[1] > tonumber(KEYS[2]) then\n"+ "    return false\n"+ "else\n"+ "    redis.call('incrby', KEYS[1], ARGV[1])\n"+ "    redis.call('expire', KEYS[1], ARGV[2])\n"+ "    return true\n"+ "end";Object result = jedis.eval(luaScript, 2, key, String.valueOf(capacity), String.valueOf(reqCount), String.valueOf(rate * (nowTime / 1000)));boolean allowed = (result instanceof Boolean ? (Boolean) result : false);jedis.close();return allowed;
}
  • key:需要进行限流的用户标识
  • capacity:桶容量
  • rate:令牌发放速率
  • reqCount:请求数量

四、分布式限流实战

1. 单机限流实现

假设我们有一个需求,需要限制每个IP一分钟内最多只能发送100个请求。可以通过Redis的INCR、EXPIRE等API操作来简单实现单机限流。

public boolean isAllowed(String ip, int limit, int interval) {Jedis jedis = getJedis();String key = "ip:" + ip;long count = jedis.incr(key);if (count == 1) {jedis.expire(key, interval);}boolean allowed = count <= limit;if (!allowed) {jedis.del(key);}jedis.close();return allowed;
}

2. 基于Redis Clusters的分布式限流实现

当业务规模扩大时,单机的限流已经无法满足需求,这时候需要考虑使用Redis Clusters实现分布式限流。Clusers扩展了原先Redis的功能,不仅支持横向扩展,而且提高了整个集群的可用性。限流算法同上,只是需要使用把数据分配到Cluser内不同的节点上。

public boolean isAllowed(String ip, int limit, int interval) {JedisCluster jedis = getJedisCluster();String key = "ip:" + ip;long count = jedis.incr(key);if (count == 1) {jedis.expire(key, interval);}boolean allowed = count <= limit;if (!allowed) {jedis.del(key);}return allowed;
}

五、基于Redis分布式限流的优化

1. 缓存击穿

1.1 问题描述

在高并发场景下,如果存在大量的缓存未命中请求,将会导致访问底层数据存储系统,这种情况被称为缓存击穿

1.2 解决方案

1.2.1 使用互斥锁

/*** 获取缓存值方法* @param key 缓存键值* @return 缓存值*/
public String getCacheValue(String key) {String value = cache.get(key);if (value == null) { //缓存未命中//使用互斥锁Lock lock = redisson.getLock(key);if (lock.tryLock()) { //尝试获取锁try {value = cache.get(key); //再次尝试获取缓存if (value == null) { //如果仍然未命中,从数据库中获取value = db.get(key);cache.put(key, value); //将查询结果放入缓存}} finally {lock.unlock(); //释放锁}} else {Thread.sleep(100); //自旋一段时间后重试return getCacheValue(key);}}return value;
}

1.2.2 使用预热机制

预热机制是指在系统启动的时候,提前加载热点数据到缓存中,以减少缓存未命中请求。预热的方式可以使用定时任务或者其他方式,在系统低峰期进行加载。

2. 热点key问题的解决方案

2.1 问题描述

在高并发场景下,如果某个key的请求量过大,将会导致这个key成为热点key,从而导致缓存雪崩问题。

2.2 解决方案

2.2.1 分布式锁

/*** 获取缓存值方法* @param key 缓存键值* @return 缓存值*/
public String getCacheValue(String key) {String value = cache.get(key);if (value == null) { //缓存未命中//使用分布式锁RLock lock = redisson.getFairLock(key);if (lock.tryLock()) { //尝试获取锁try {value = cache.get(key); //再次尝试获取缓存if (value == null) { //如果仍然未命中,从数据库中获取value = db.get(key);cache.put(key, value); //将查询结果放入缓存}} finally {lock.unlock(); //释放锁}} else {Thread.sleep(100); //自旋一段时间后重试return getCacheValue(key);}}return value;
}

2.2.2 分布式缓存

使用分布式缓存将数据均匀地分散到多个节点上,从而避免单点瓶颈问题。

3. 并发竞争优化

3.1 问题描述

在高并发场景下,对于某些资源的并发访问将会导致性能瓶颈,需要进行并发竞争优化。

3.2 解决方案

3.2.1 使用限流器

限流器类似于信号灯,用于控制并发请求的数量,在高峰期可以采用漏桶算法或令牌桶算法进行限流。

3.2.2 使用异步线程池

对于一些耗时的操作,可以使用异步线程池进行处理,从而避免阻塞主线程,提升系统的并发能力。

http://www.hkea.cn/news/951877/

相关文章:

  • 局域网内的网站建设西安网站建设公司排名
  • 普通网站报价多少中南建设集团有限公司
  • 蚌埠做网站哪家好全网营销国际系统
  • 沈阳市网站制作谷歌香港google搜索引擎入口
  • 做美食网站的背景高端网站建设制作
  • 文件什么上传到wordpress泉州seo技术
  • 网站地址地图怎么做网页制作的软件有哪些
  • 如何用万网建设网站口碑营销策划方案
  • 做网站的基础架构东莞seo建站公司
  • 嘉兴做网站的哪家好龙岗网站制作
  • 论坛做网站好吗百度官方网页
  • 微信开发者工具获取系统日期seo优化一般包括
  • 怎么用文本做网站百度排行榜风云榜
  • 未来网站开发需求多搜索网站有哪几个
  • 网站建设 成都郑州高端网站制作
  • 快站怎么做淘客网站深圳关键词
  • 做网站时如何去掉网站横条小红书软文案例
  • 图虫南宁百度快速排名优化
  • 上城网站建设app推广文案
  • 网站建设特点宁波seo搜索引擎优化公司
  • 地产商网站建设网球新闻最新消息
  • 做爰全过程网站免费的视频谷歌seo搜索引擎
  • 怎么架设网站seo推广培训
  • 自己网站做问卷调查网页设计学生作业模板
  • 清远企业网站排名深圳网站建设系统
  • 互助平台网站建设费用卡点视频免费制作软件
  • 上海做b2b国际网站公司排名优化公司电话
  • 裙晖wordpress重庆seo整站优化
  • 乌克兰网站后缀谷歌浏览器下载电脑版
  • 建设部网站撤销注册资质的都是公职人员吗正规网络公司关键词排名优化