java进行系统的限流实现--Guava RateLimiter、简单计数、滑窗计数、信号量、令牌桶
本文主要介绍了几种限流方法:Guava RateLimiter、简单计数、滑窗计数、信号量、令牌桶,漏桶算法和nginx限流等等
1、引入guava集成的工具
pom.xml 文件
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>23.0</version></dependency>
demo代码实现
package com.znkeji.zn_wifi_carck.guava;import com.google.common.util.concurrent.RateLimiter;public class GuavaRateLimiterTest {//比如每秒生产10个令牌,相当于每100ms生产1个令牌//RateLimiter是Guava库中的一个限流器// 基于PPS进行限流//基于PPS限流的同时提供热启动private RateLimiter rateLimiter=RateLimiter.create(10);/*** 模拟执行业务方法*/public void exeBiz(){if (rateLimiter.tryAcquire(1)){///返回boolean 尝试获取许可,如果该许可可以在无延迟下的情况下立即获取得到的话try {Thread.sleep(50);}catch (Exception e){e.printStackTrace();}System.out.println("线程"+Thread.currentThread().getName()+":执行业务逻辑");}else {System.out.println("线程"+Thread.currentThread().getName()+":被限流了");}}public static void main(String[] args) throws InterruptedException {GuavaRateLimiterTest guavaRateLimiterTest = new GuavaRateLimiterTest();System.out.println("线程开始等待");Thread.sleep(500); //等待500ms,让limiter生产一些令牌System.out.println("线程睡了0.5秒");//模拟瞬间生产100个线程请求for (int i=0;i<100;i++){new Thread(guavaRateLimiterTest::exeBiz).start();}}}
2.令牌桶算法
package com.znkeji.zn_wifi_carck.guava;import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;/*** 令牌桶算法:一个存放固定容量令牌的桶,按照固定速率往桶里添加令牌,如有剩余容量则添加,没有则放弃。如果有请求进来,则需要先从桶里获取令牌,当桶里没有令牌可取时,则拒绝任务。** 令牌桶的优点是:可以改变添加令牌的速率,一旦提高速率,则可以处理突发流量。*/
public class TokenBucket {/*** 定义的桶*/public class Bucket {//容量int capacity;//速率,每秒放多少int rateCount;//目前token个数AtomicInteger curCount = new AtomicInteger(0);public Bucket(int capacity, int rateCount) {this.capacity = capacity;this.rateCount = rateCount;}public void put() {if (curCount.get() < capacity) {System.out.println("目前数量==" + curCount.get() + ", 我还可以继续放");curCount.addAndGet(rateCount);}}public boolean get() {if (curCount.get() >= 1) {curCount.decrementAndGet();return true;}return false;}}// @Testpublic void testTokenBucket() throws InterruptedException {Bucket bucket = new Bucket(5, 2);//固定线程,固定的速率往桶里放数据,比如每秒N个ScheduledThreadPoolExecutor scheduledCheck = new ScheduledThreadPoolExecutor(1);scheduledCheck.scheduleAtFixedRate(() -> {bucket.put();}, 0, 1, TimeUnit.SECONDS);//先等待一会儿,让桶里放点tokenThread.sleep(6000);//模拟瞬间10个线程进来拿tokenfor (int i = 0; i < 10; i++) {new Thread(() -> {if (bucket.get()) {System.out.println(Thread.currentThread() + "获取到了资源");} else {System.out.println(Thread.currentThread() + "被拒绝");}}).start();}//等待,往桶里放tokenThread.sleep(3000);//继续瞬间10个线程进来拿tokenfor (int i = 0; i < 10; i++) {new Thread(() -> {if (bucket.get()) {System.out.println(Thread.currentThread() + "获取到了资源");} else {System.out.println(Thread.currentThread() + "被拒绝");}}).start();}}
}
3、滑窗计数器
package com.znkeji.zn_wifi_carck.guava;import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;/*** 滑窗计数器 打个比方,某接口每秒允许100个请求,设置一个滑窗,窗口中有10个格子,每个格子占100ms,每100ms移动一次。滑动窗口的格子划分的越多,滑动窗口的滚动就越平滑,限流的统计就会越精确。*/
public class SliderWindowRateLimiter implements Runnable {//每秒允许的最大访问数private final long maxVisitPerSecond;//将每秒时间划分N个块private final int block;//每个块存储的数量private final AtomicLong[] countPerBlock;//滑动窗口划到了哪个块儿,可以理解为滑动窗口的起始下标位置private volatile int index;//目前总的数量private AtomicLong allCount;/*** 构造函数** @param block,每秒钟划分N个窗口* @param maxVisitPerSecond 每秒最大访问数量*/public SliderWindowRateLimiter(int block,long maxVisitPerSecond){this.block=block;this.maxVisitPerSecond=maxVisitPerSecond;countPerBlock= new AtomicLong[block];for (int i=0;i<block;i++){countPerBlock[i]=new AtomicLong();}allCount=new AtomicLong(0);}/*** 判断是否超过最大允许数量** @return*/public boolean isOverLimit() {return currentQPS() > maxVisitPerSecond;}/*** 获取目前总的访问数** @return*/public long currentQPS() {return allCount.get();}/*** 请求访问进来,判断是否可以执行业务逻辑*/public void visit(){countPerBlock[index].incrementAndGet();allCount.incrementAndGet();if (isOverLimit()){System.out.println(Thread.currentThread().getName()+"被限流了,currentQPS:"+currentQPS());}else {System.out.println(Thread.currentThread().getName()+"执行业务逻辑,currentQPS:"+currentQPS());}}/*** 定时执行器,* 每N毫秒滑块移动一次,然后再设置下新滑块的初始化数字0,然后新的请求会落到新的滑块上* 同时总数减掉新滑块上的数字,并且重置新的滑块上的数量*/@Overridepublic void run() {index=(index+1)%block;long val= countPerBlock[block].getAndSet(0);allCount.addAndGet(-val);}public static void main(String[] args) {SliderWindowRateLimiter sliderWindowRateLimiter = new SliderWindowRateLimiter(10, 100);//固定的速率移动滑块ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();scheduledExecutorService.scheduleAtFixedRate(sliderWindowRateLimiter, 100, 100, TimeUnit.MILLISECONDS);//模拟不同速度的请求new Thread(() -> {while (true) {sliderWindowRateLimiter.visit();try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}).start();//模拟不同速度的请求new Thread(() -> {while (true) {sliderWindowRateLimiter.visit();try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
}
4、信号量
package com.znkeji.zn_wifi_carck.guava;import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Semaphore;/*** 利用Semaphore,每隔固定速率,释放Semaphore的资源。线程获取到资源,则执行业务代码。*/
public class SemaphoreOne {private static Semaphore semaphore = new Semaphore(10);public static void bizMethod() throws InterruptedException {if (!semaphore.tryAcquire()) {System.out.println(Thread.currentThread().getName() + "被拒绝");return;}System.out.println(Thread.currentThread().getName() + "执行业务逻辑");Thread.sleep(500);//模拟处理业务逻辑需要1秒semaphore.release();}public static void main(String[] args) {Timer timer = new Timer();timer.scheduleAtFixedRate(new TimerTask() {@Overridepublic void run() {semaphore.release(10);System.out.println("释放所有锁");}}, 1000, 1000);for (int i = 0; i < 10000; i++) {try {Thread.sleep(10);//模拟每隔10ms就有1个请求进来} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {try {SemaphoreOne.bizMethod();} catch (InterruptedException e) {e.printStackTrace();}}).start();}}
}
相关文章:
java进行系统的限流实现--Guava RateLimiter、简单计数、滑窗计数、信号量、令牌桶
本文主要介绍了几种限流方法:Guava RateLimiter、简单计数、滑窗计数、信号量、令牌桶,漏桶算法和nginx限流等等 1、引入guava集成的工具 pom.xml 文件 <dependency><groupId>com.google.guava</groupId><artifactId>guava<…...
《86盒应用于家居中控》——实现智能家居的灵动掌控
近年来,智能家居产品受到越来越多消费者的关注,其便捷、舒适的生活方式让人们对未来生活充满期待。作为智能家居方案领域的方案商,启明智显生产设计的86盒凭借出色的性能和良好的用户体验,成功应用于家居中控系统,让家…...
【LeetCode】328. 奇偶链表
328. 奇偶链表(中等) 思路 如果链表为空,则直接返回链表。 对于原始链表,每个节点都是奇数节点或偶数节点。头节点是奇数节点,头节点的后一个节点是偶数节点,相邻节点的奇偶性不同。因此可以将奇数节点和偶…...
数字城市:科技革命下的未来之城
随着科技的不断进步,数字城市已经成为了未来城市发展的关键趋势。数字城市是指利用先进的信息技术、互联网和大数据等工具,将城市各个方面进行数字化、智能化、互联化的发展模式。它不仅仅是一种技术,更是一种对城市管理、发展和居民生活方式…...
Qt鼠标点击事件处理:按Escape键退出程序
创建项目 Qt 入门实战教程(目录) 首先,创建一个名称为QtKeyEscape的Qt默认的窗口程序。 参考 :Qt Creator 创建 Qt 默认窗口程序 Qt响应键盘Escape事件 打开Qt Creator >>编辑 >> 项目 >> Headers>> …...
P1162 填涂颜色
填涂颜色 - 洛谷 这个题用逆向思维,见不用染色的地方标记。 这里为了处理一些情况,将图周围一圈的0空出来,用于吧围墙之外的部分都标记上 用宽搜,四联通,感觉好奇怪,八连通ac不了 #include <iostrea…...
Vagrant命令
文章目录 1.介绍2.下载3. 配置3.1 配置环境变量3.2 在xshell中连接使用 4. 相关命令4.1 Box相关4.2 初始化环境4.4 虚拟机相关 1.介绍 Vagrant 是一个虚拟机管理工具 2.下载 https://www.vagrantup.com/ 3. 配置 3.1 配置环境变量 测试安装是否成功 3.2 在xshell中连接使…...
vue3+pinia实现动态类名及动态颜色
前提 store下models下有个before.ts文件 import { defineStore } from "pinia"; export const usebeforeloggininStore defineStore("counterStore", {state: () > ({beforelogin_params: [{type: "A登录",color: "#000",flag: 1,…...
CSS实现隐藏滚动条但可以滚动
场景 隐藏滚动条,但可以滚动 解决 全局样式 /* 隐藏滚动条 */ .outer-container::-webkit-scrollbar {width: 0; /* 设置滚动条的宽度为0 */background-color: transparent; /* 设置滚动条背景为透明 */ }/* 自定义滚动条轨道样式 */ .outer-container::-webkit…...
Ceph入门到精通-lunix将文本5行合成1行并按列统计
要将每5行合并为1行,您可以使用shell命令来完成。假设您有一个名为text.txt的文本文件,您可以使用以下命令来实现: bash cat text.txt | paste -d - - - - - 这将把文件中的每5行合并为1行,并且每个字段之间用空格分隔开来。您…...
linux线程讲解
1.线程概述 一个进程在同一时刻只做一件事情,进程是程序执行的一个实例。 线程是操作系统能够进行运算调度的最小单位,一个进程中可以并发多个线程,每条线程并行执行不同的任务。 进程:资源分配的最小单位。线程,程…...
解决本地jar包导入maven
1、确定是否安装maven 2、输入导入命令 命令说明 <path-to-file>为你jar包所在的路径(尽量简单并且不要含中文) <group-id>为grouId号,与<artifact-id>组成唯一识别你jar包的坐标,当不在公共资源jar包中&#…...
ArcGis地图
1、概述 官网:https://developers.arcgis.com/qt/ 官网:官网指导 官网:Add graphics to a map view Arcgis runtime sdk for Qt 开发记录(系列文章) 2、创建地图 //online: m_mapView new MapGraphicsV…...
Chrome 和 Edge 上出现“status_breakpoint”错误解决办法
文章目录 STATUS_BREAKPOINTSTATUS_BREAKPOINT报错解决办法Chrome浏览器 Status_breakpoint 错误修复- 将 Chrome 浏览器更新到最新版本- 卸载不再使用的扩展程序和应用程序- 安装计算机上可用的任何更新,尤其是 Windows 10- 重启你的电脑。 Edge浏览器 Status_brea…...
华为AP升级操作记录
AP型号:AP4050DN 原版本:AP4050DN CLOUD V200R008C10SPC700 升级后版本:AP4000 V200R019C00SPC913 开启FTP,用户名:admin, 密码:123456 FTP服务端地址:192.168.8.58 操作:将AP连接…...
面试系列 - String字符串使用详解
String 类是 Java 中最常用的类之一,它用于表示和操作字符串。字符串是一系列字符的序列,可以包含字母、数字、符号等。在 Java 中,String 类是不可变的,这意味着一旦创建了字符串对象,它的内容就不能被修改。 一、常…...
1782_Adobe Reader X实现pdf分页保存
全部学习汇总: GitHub - GreyZhang/windows_skills: some skills when using windows system. 看了一本pdf电子书,觉得其中几页很值得分享。如果分享整本书当然是不错的选择,但是分享整本书很可能会导致一个结局——内容太多别人不会去看&…...
筛选图片,写JSON文件和复制
筛选图片,写JSON文件和复制 筛选图片,写JSON文件筛选图片复制 筛选图片,写JSON文件 # coding: utf-8 from PIL import Image, ImageDraw, ImageFont import os import shutil import cv2 as cv import numpy as np import jsondef zh_ch(str…...
C++并发编程:构建线程安全队列(第二部分:细粒度锁)
C++并发编程:构建线程安全队列(第二部分:细粒度锁) 1. 引言 在多线程环境下,为了保证数据的一致性和正确性,需要使用同步原语来对共享数据的访问进行互斥和同步。std::queue作为一种先进先出(FIFO)的数据结构,它本身并不是线程安全的,同时访问它可能导致数据竞争和不一致的问…...
浅述C++内存管理——new与malloc的不同
前言 C相对于其他语言有一个重要的特点就是对于内存的管理,相比于C语言,C提供了新的关键字new来代替malloc的功能,其中有何不同,请看下文。 一、内存的构成 在我们日常编程过程中最常接触到的就是以下四个分区 以下将分别给出例…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
