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的功能,其中有何不同,请看下文。 一、内存的构成 在我们日常编程过程中最常接触到的就是以下四个分区 以下将分别给出例…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...

RKNN开发环境搭建2-RKNN Model Zoo 环境搭建
目录 1.简介2.环境搭建2.1 启动 docker 环境2.2 安装依赖工具2.3 下载 RKNN Model Zoo2.4 RKNN模型转化2.5编译C++1.简介 RKNN Model Zoo基于 RKNPU SDK 工具链开发, 提供了目前主流算法的部署例程. 例程包含导出RKNN模型, 使用 Python API, CAPI 推理 RKNN 模型的流程. 本…...