范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

java限流算法

  1 场景
  程序中经常需要对接口进行限流,防止访问量太大,导致程序崩溃。
  常用的算法有:计数算法、 漏桶算法  、令牌桶算法  ,最常用的算法是后面两种。2 算法详解2.1 计数算法2.1.1 说明
  技术算法,为最简单的限流算法。
  核心思想是, 每隔一段时间  ,为计数器设定最大值  ,请求一次,计数器数量减一  ,如果计数器为0,则拒绝请求  。2.1.2 图示
  2.1.3 适用场景
  虽然此算法是大多数人第一个想到可以限流的算法,但是 不推荐使用此算法  。
  因为,此算法有个致命性的问题,如果1秒允许的访问次数为100,前0.99秒内没有任何请求,在 最后0.01秒内,出现了200个请求  ,则这200个请求,都会获取调用许可,给程序带来一次请求的高峰。
  2.1.4 代码import java.time.LocalDateTime; import java.util.concurrent.TimeUnit;  /**  * 计数器限流器  */ public class CountLimiter {     /**      * 执行区间(毫秒)      */     private int secondMill;          /**      * 区间内计数多少次      */     private int maxCount;          /**      * 当前计数      */     private int currentCount;          /**      * 上次更新时间(毫秒)      */     private long lastUpdateTime;          public CountLimiter(int second, int count) {         if (second = secondMill) {             this.currentCount = maxCount;             this.lastUpdateTime = now;         }     }          /**      * 获取授权      * @return      */     public synchronized boolean tryAcquire() {         // 刷新计数器         this.refreshCount();         if ((this.currentCount - 1) >= 0) {             this.currentCount--;             return true;         } else {             return false;         }     } }
  测试方法: public static void main(String[] args) throws Exception {     // 1秒限制执行2次     CountLimiter countLimiter = new CountLimiter(1, 2);     for (int i = 0; i < 10; i++) {         System.out.println(LocalDateTime.now() + " " + countLimiter.tryAcquire());         TimeUnit.MILLISECONDS.sleep(200);     } }
  执行结果: 2021-05-31T22:01:08.660 true 2021-05-31T22:01:08.868 true 2021-05-31T22:01:09.074 false 2021-05-31T22:01:09.275 false 2021-05-31T22:01:09.485 false 2021-05-31T22:01:09.698 true 2021-05-31T22:01:09.901 true 2021-05-31T22:01:10.104 false 2021-05-31T22:01:10.316 false 2021-05-31T22:01:10.520 false2.2 漏桶算法2.2.1 说明
  漏桶算法称为 leaky bucket  ,可限制指定时间内的最大流量,如限制60秒内,最多允许100个请求。
  其中 接受请求的速度是不恒定的  (水滴入桶),处理请求的速度是恒定的  (水滴出桶)。
  算法总体描述如下: 有个 固定容量的桶 B  (指定时间区间X  ,允许的的最大流量B  ),如60秒内最多允许100个请求,则B  为100,X  为60。有水滴流进来(有请求进来), 桶里的水+1 。 有水滴流出去(执行请求对应的业务), 桶里的水-1 ( 业务方法,真正开始执行  =>这是保证漏桶匀速处理业务的根本  ),水滴流出去的速度是匀速的,流速为B/X  (1毫秒100/60次,约1毫秒0.00167次,精度可根据实际情况自己控制)水桶满了后( 60 秒内请求达到了 100 次),水滴无法进入水桶, 请求被拒绝 2.2.2 图示
  实际开发中,漏桶的使用方式可参考下图:
  需注意,水滴 滴落  的时候,才开始执行业务代码  ,而不是水滴进桶的时候  ,去执行业务代码。
  业务代码的执行方式,个人认为有如下两种: 同步执行 1、调用方请求时,如水滴可以放入桶中,调用方所在的线程"阻塞"
  2、水滴漏出时,唤醒调用方线程,调用方线程,执行具体业务 异步执行 1、调用方请求时,如水滴可以放入桶中,调用方所在的线程收到响应,方法将异步执行
  2、水滴漏出时,水桶代理执行具体业务 网上很多滴桶的实现代码,在水滴进桶的时候,就去执行业务代码了。这样会导致业务代码,无法匀速地执行,仍然对被调用的接口有一瞬间流量的冲击(和令牌桶算法的最终实现效果一样)。
  2.2.3 适用场景
  水桶的 进水速度是不可控的  ,有可能一瞬间有大量的请求  进入水桶。处理请求的速度是恒定的  (滴水的时候处理请求)。
  此算法,主要应用于 自己的服务,调用外部接口  。以均匀  的速度调用外部接口,防止对外部接口的压力过大  ,而影响外部系统的稳定性。如果影响了别人的系统,接口所在公司会来找你喝茶。
  漏桶算法,主要用来保护别人的接口。  2.2.4 代码
  本实例代码的实现,在水滴滴下,执行具体业务代码时,采用 同步执行  的方式。即唤醒调用方的线程,让"调用者"所属的线程  去执行具体业务代码,去调用接口  。import java.net.SocketTimeoutException; import java.time.LocalDateTime; import java.util.Queue; import java.util.UUID; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport;  /**  * 漏桶算法  */ public class LeakyBucketLimiterUtil {          /**      * 漏桶流出速率(多少纳秒执行一次)      */     private long outflowRateNanos;          /**      * 漏桶容器      */     private volatile BlockingQueue queue;          /**      * 滴水线程      */     private Thread outflowThread;          /**      * 水滴      */     private static class Drip {         /**          * 业务主键          */         private String busId;                  /**          * 水滴对应的调用者线程          */         private Thread thread;                  public Drip(String busId, Thread thread) {             this.thread = thread;         }                  public String getBusId() {             return this.busId;         }                  public Thread getThread() {             return this.thread;         }     }          /**      * @param second 秒      * @param time   调用次数      */     public LeakyBucketLimiterUtil(int second, int time) {         if (second (time);                  outflowThread = new Thread(() -> {             while (true) {                 Drip drip = null;                 try {                     // 阻塞,直到从桶里拿到水滴                     drip = queue.take();                 } catch (Exception e) {                     e.printStackTrace();                 }                 if (drip != null && drip.getThread() != null) {                     // 唤醒阻塞的水滴里面的线程                     LockSupport.unpark(drip.getThread());                 }                 // 休息一段时间,开始下一次滴水                 LockSupport.parkNanos(this, outflowRateNanos);             }         }, "漏水线程");         outflowThread.start();     }          /**      * 业务请求      *      * @return      */     public boolean acquire(String busId) {         Thread thread = Thread.currentThread();         Drip drip = new Drip(busId, thread);         if (this.queue.offer(drip)) {             LockSupport.park();             return true;         } else {             return false;         }     } }
  测试代码如下: public static void main(String[] args) throws Exception {     // 1秒限制执行1次     LeakyBucketLimiterUtil leakyBucketLimiter = new LeakyBucketLimiterUtil(5, 2);     for (int i = 0; i < 10; i++) {          new Thread(new Runnable() {                @Override                public void run() {                    String busId = "[业务ID:" + LocalDateTime.now().toString() + "]";                    if (leakyBucketLimiter.acquire(busId)) {                         System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + ":调用外部接口...成功:" + busId);                    } else {                         System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + ":调用外部接口...失败:" + busId);                    }                 }           }, "测试线程-" + i).start(); TimeUnit.MILLISECONDS.sleep(500);     } }
  执行结果如下: 2021-05-31T20:52:52.297 测试线程-0:调用外部接口...成功:[业务ID:2021-05-31T20:52:52.295] 2021-05-31T20:52:53.782 测试线程-3:调用外部接口...失败:[业务ID:2021-05-31T20:52:53.782] 2021-05-31T20:52:54.286 测试线程-4:调用外部接口...失败:[业务ID:2021-05-31T20:52:54.286] 2021-05-31T20:52:54.799 测试线程-1:调用外部接口...成功:[业务ID:2021-05-31T20:52:52.761] 2021-05-31T20:52:55.300 测试线程-6:调用外部接口...失败:[业务ID:2021-05-31T20:52:55.300] 2021-05-31T20:52:55.806 测试线程-7:调用外部接口...失败:[业务ID:2021-05-31T20:52:55.806] 2021-05-31T20:52:56.307 测试线程-8:调用外部接口...失败:[业务ID:2021-05-31T20:52:56.307] 2021-05-31T20:52:56.822 测试线程-9:调用外部接口...失败:[业务ID:2021-05-31T20:52:56.822] 2021-05-31T20:52:57.304 测试线程-2:调用外部接口...成功:[业务ID:2021-05-31T20:52:53.271] 2021-05-31T20:52:59.817 测试线程-5:调用外部接口...成功:[业务ID:2021-05-31T20:52:54.799] 2.3 令牌桶算法2.3.1 说明
  令牌桶算法,主要是匀速地增加可用令牌,令牌数因为桶的限制有数量上限。
  请求拿到令牌,相当于拿到授权,即可进行相应的业务操作。 2.3.2 图示
  2.3.3 适用场景
  和漏桶算法比,有可能导致短时间内的请求数上升(因为拿到令牌后,就可以访问接口,有可能一瞬间将所有令牌拿走),但是不会有计数算法那样高的峰值(因为令牌数量是匀速增加的)。
  一般自己调用自己的接口,接口会有一定的伸缩性, 令牌桶算法,主要用来保护自己的服务器接口。  2.3.4 代码
  简易代码实现如下: import java.time.LocalDateTime; import java.util.concurrent.TimeUnit;  /**  * 令牌桶限流算法  */ public class TokenBucketLimiter {          /**      * 桶的大小      */     private double bucketSize;          /**      * 桶里的令牌数      */     private double tokenCount;          /**      * 令牌增加速度(每毫秒)      */     private double tokenAddRateMillSecond;          /**      * 上次更新时间(毫秒)      */     private long lastUpdateTime;          /**      * @param second 秒      * @param time   调用次数      */     public TokenBucketLimiter(double second, double time) {         if (second = 0) {             // 如果桶中有令牌,令牌数-1             this.tokenCount--;             return true;         } else {             // 桶中已无令牌             return false;         }     } }
  测试代码: public static void main(String[] args) throws Exception{     // 2秒执行1次     TokenBucketLimiter leakyBucketLimiter = new TokenBucketLimiter(2, 1);      for (int i = 0; i < 10; i++) {           System.out.println(LocalDateTime.now() + " " + leakyBucketLimiter.tryAcquire());           TimeUnit.SECONDS.sleep(1);      } }
  执行结果如下: 2021-05-31T21:38:34.560 true 2021-05-31T21:38:35.582 false 2021-05-31T21:38:36.588 true 2021-05-31T21:38:37.596 false 2021-05-31T21:38:38.608 true 2021-05-31T21:38:39.610 false 2021-05-31T21:38:40.615 true 2021-05-31T21:38:41.627 false 2021-05-31T21:38:42.641 true 2021-05-31T21:38:43.649 false
  2.3.5 第三方工具类
  可以使用 Guava  中的RateLimiter  来实现令牌桶的限流功能。
  maven依赖如下: com.google.guavaguava30.1.1-jre
  直接获取令牌(true为获取到令牌,false为获取失败): RateLimiter rateLimiter = RateLimiter.create(2); boolean acquireResule = rateLimiter.tryAcquire(); if (acquireResule) {     System.out.println("获取令牌:成功"); } else {     System.out.println("获取令牌:失败"); }
  等待尝试获取令牌(阻塞当前线程,直到获取到令牌): RateLimiter rateLimiter = RateLimiter.create(2); // 阻塞获取令牌 double waitCount = rateLimiter.acquire(); System.out.println("阻塞等待时间:" + waitCount);

为什么被证明拖后腿的苹果Mini手机,仍然还会再次发布新款?iPhone12Mini系列,前几个月就被网传被苹果公司紧急停产了。作为一台5。4英寸最轻薄的5G全面屏手机,虽然确实很小巧轻薄但是因为续航能力实在太差的缘故导致了许多消费者虽然很边缘计算安全吗?如何赋能企业数智化变革?来源计算机世界在昨天的微信火爆业界的边缘计算,到底是什么?中介绍了边缘计算及其用例,今天继续分享干货边缘设备边缘的物理架构很复杂,但基本思路是客户端设备连接到附近的边缘模块,以实现想买一个双模5G手机尝鲜,不想要太贵的,有什么推荐?一问题1HUAWEInova8SE5G2CPU天玑800处理器八核3快充电66w4像素6400万高清5屏幕6。53英寸nova8SE5G二问题1后置摄像头6400万800万200万互联网时代趋势下实体如何发展?互联网时代趋势下实体如何发展?近年来在互联网技术不断发展的背景下,电商发展呈现出了超越实体店铺的势头,互联网时代的到来正逐渐改变经济格局。实体店铺在互联网背景下在供货渠道销售模式等亚马逊爆款折叠式手提包美国专利侵权预警亚马逊产品专利查询分析欧美专利申请确权!杜绝专利侵权风险,为您的产品保驾护航!今天在浏览亚马逊的时候,看到一款可折叠式手提包,它是美亚站的AmazonsChoice,售价19。99iPhone13定档9月14日!苹果股价再创新高,年内市值涨一个特斯拉9月8日消息,苹果官方宣布当地时间9月14日,苹果将举办秋季新品发布会,届时有望发布包括iPhone13AppleWatch7等在内的多款新品。对此有网友在社交媒体表示,明年上三万纯电MPV,奔驰EQT正式发布随着电动化进程越来越快,不仅新势力品牌推陈出新,传统老牌车企也丝毫不敢怠慢。奔驰旗下的电动系列产品EQ家族,近日也在慕尼黑车展正式发布了一款纯电MPV车型,名为EQT。新车是奔驰与腾讯捐出1000亿,扭头一波薅羊毛微信又要收费了8月17日中央财经委员会第十次会议强调,共同富裕是社会主义的本质要求,是中国式现代化的重要特征,要坚持以人民为中心的发展思想,在高质量发展中促进共同富裕。我们在一部分人先富起来的赛给长辈买手机怎么选?这几款堪称千元机性价比之王相信不少小伙伴在给自己的长辈挑选手机时会感到很困惑,不知道该挑一款怎样的手机才最适合他们,如今的手机可不比从前,手机上的功能变得五花八门,手机也成为了大家娱乐的一项工具,长辈们亦是学到了!来看一车难求的沃尔沃如何演绎电气化之路一个不算冷的知识,汽车行业占全球二氧化碳总排放的7。3,是全球碳排放最大的行业之一。根据IEA国际能源署预计,至2070年,汽车的使用量将较2020年翻倍,如果依然是燃油车当道,二vivoNEX5或将于年底亮剑,98屏占比120W快充,高配18512G存储今年整个智能手机市场迎来了新变局,竞争比以往要激烈很多。各大智能手机厂商为瓜分更多的市场份额在新机上狠下功夫,一年要发布两三旗舰新机,这一点在小米身上展现得淋漓尽致。而其他品牌也纷
成都车展上的国产新能源成都车展成都西博城国际车展8月29日开幕,由于住的远,到西博城外面已经是差不多中午了。所以错过了一些新车发布会,错过了高圆圆,郎朗。大门进去,最近的是6号和10号展厅,我们先去了1小米拍照又要封神了?小米12引入50MP三主摄系统在影像这条道路上,苹果和安卓用着两套不同的方案,苹果1200万像素一用就是6年,改变的只有传感器越来越大,以及软件层面的深度优化,而安卓阵营是以换大底上高像素为主,今年上4800万EV早点汉EV旗舰型首搭DiLink4。0(5G)蜂巢能源无钴电池装车1汉EV旗舰型首搭DiLink4。0(5G)8月29日,比亚迪携DiLink4。0(5G)和为汉EV四驱高性能版旗舰型倾力打造的5G丹拿智能音乐座舱升级包,在成都车展正式上市。5G极狐阿尔法T底气十足,4。6s破百,冲击高端新能源汽车市场如果说谁才是中国高端新能源汽车市场中的领导者?到目前为止,市场尚未有定论,但是有不少自主品牌都在向这一方向努力进取。比如极狐这个定位于高端智能的汽车品牌,北汽携手全球一流的汽车零部10万级纯电车能否来台能打的?比亚迪海豚售9。38万起8月29日,在刚刚开幕的成都车展上,比亚迪3。0纯电平台首款车型海豚正式上市,共推4款车型,售价区间为9。3812。18万元。这是比亚迪认真入主10万元级别纯电动车市场,按道理不管巨头不再撒钱,生鲜电商拐点已至?撰文孟会缘编辑黎文婕带着裁员关城收缩90业务这些标签的十荟团,要暂时离场了,生鲜电商动辄给用户撒钱的习惯也要告一段落了。生鲜赛道的若干玩家们似乎终于明白,只靠巨额补贴打下来的社区生RedmiNote11Pro携120W快充报到,6000mAh7nm芯片,1。08亿像素高通骁龙870芯片采用台积电7nmEUV制程工艺打造,在性能上虽然没有今年最新款骁龙888旗舰芯片采用的4nm工艺制程强悍,但由于骁龙888在功耗上消耗过大,导致手机发热严重,所以流畅使用三年,2500元以内最佳5G手机,选这三款准没错很多朋友在使用了苹果手机以后,都不想再换回安卓了,其实最主要的是一开始,安卓的系统非常卡顿,使用感不是很好,于是这些印象深深的刻在脑子里,比起来每年花一两千买一款安卓机,不如直接买vivo火力全开,屏下摄像头E5屏幕微云台主摄,新机基本确定近段时间国内手机市场可以说是很热闹的,基本上每一家都在抢着发布属于自己的中端,或者高端旗舰手机,以最积极,最精准的方案来铺设属于自己的市场份额,特别是小米OV,纷纷预热,拿出了令人OPPO首款折叠屏手机内折方案LTPO屏随着柔性屏幕技术的飞速发展,包括华为三星摩托等厂商持续发力,带来多款折叠屏旗舰手机。今日,据数码博主数码闲聊站爆料,OPPO的内折叠屏新机已进入排期表,应该不会等太久。同时,该博主低轨道卫星通讯,iPhone13暴露库克野心,国产手机如何破招?文丨辣说科技以往,苹果摸着石头过河,国产手机厂商摸着苹果过河,那么如果角色互换会怎么样?日前,多家知名媒体通过综合分析,得出新款iPhone的发布会会在9月14日这天开启,而随着日