java實(shí)現(xiàn)單機(jī)限流
何時(shí)使用限流:
比如你希望自己的應(yīng)用程序 QPS不要超過(guò)1000,那么RateLimiter設(shè)置1000的速率后,就會(huì)每秒往桶里 扔1000個(gè)令牌,RateLimiter經(jīng)常用于限制對(duì)一些物理資源或者邏輯資源的訪 問速率。
簡(jiǎn)介:
對(duì)于單機(jī)版的限流,可以使用Google 開源的 Guava項(xiàng)目,這個(gè)項(xiàng)目提供了Google在Java項(xiàng)目中使用一些核心庫(kù),包含集合(Collections),緩存(Caching),并發(fā)編程庫(kù)(Concurrency),常用注解(Common annotations),String操作,I/O操作方面的眾多非常實(shí)用的函數(shù)。
這個(gè)項(xiàng)目也包含了限流的功能,其原理是根據(jù)令牌桶算法來(lái)實(shí)現(xiàn)。
提供了兩種限流策略:
● 平滑突發(fā)限流(SmoothBursty)
● 平滑預(yù)熱限流(SmoothWarmingUp)實(shí)現(xiàn)。

依賴:
<dependency> ? <groupId>com.google.guava</groupId> ? <artifactId>guava</artifactId> ? <version>29.0-jre</version> </dependency>
方法描述:

模擬場(chǎng)景(示例):
場(chǎng)景一:
當(dāng)我們希望某一個(gè)接口每秒的訪問量不超過(guò)10次
package org.xhs.test;
import org.apache.curator.shaded.com.google.common.util.concurrent.RateLimiter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
/**
?* @Author: hu.chen
?* @Description:
?**/
public class Test {
? ? /**
? ? ?* 存儲(chǔ)接口名和令牌生成器的對(duì)應(yīng)關(guān)系
? ? ?*/
? ?private static Map<String, RateLimiter> interfaces = new ConcurrentHashMap<>();
? ?
? ? /**
? ? ?* 線程池
? ? ?*/
? ? private static ExecutorService threadPool = new ThreadPoolExecutor(10,15,3,TimeUnit.SECONDS,new ArrayBlockingQueue<>(100));
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? List<UserRequest> tasks = new ArrayList<UserRequest>();
? ? ? ? // 準(zhǔn)備工作,先初始化 10個(gè)線程(用戶),這10個(gè)用戶同時(shí)訪問一個(gè)接口
? ? ? ? for (int i = 1; i <= 12; i++) {
? ? ? ? ? ? String ip = "127.0.0." + i;
? ? ? ? ? ? String userName="chenhu_"+i;
? ? ? ? ? ? String interfaceName="user/find_";
? ? ? ? ? ? tasks.add(new UserRequest(ip,userName,interfaceName));
? ? ? ? }
? ? ? ? // 先初始化好令牌生成器
? ? ? ? for (UserRequest request : tasks) {
? ? ? ? ? ? // 根據(jù)接口名限流
? ? ? ? ? ? RateLimiter rateLimiter = interfaces.get(request.getInterfaceName());
? ? ? ? ? ? if(rateLimiter==null){
? ? ? ? ? ? ? ? // 創(chuàng)建一個(gè)令牌生成器,每秒產(chǎn)生10個(gè)令牌
? ? ? ? ? ? ? ? synchronized (interfaces) {
? ? ? ? ? ? ? ? ? ? if(rateLimiter==null) {
? ? ? ? ? ? ? ? ? ? ? ? rateLimiter = RateLimiter.create(10);
? ? ? ? ? ? ? ? ? ? ? ? // 將這個(gè)令牌生成器和具體的接口進(jìn)行綁定
? ? ? ? ? ? ? ? ? ? ? ? interfaces.put(request.getInterfaceName(),rateLimiter);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? // 休眠一秒,讓令牌生成器先生成令牌
? ? ? ? Thread.sleep(1000);
? ? ? ? for (UserRequest request : tasks) {
? ? ? ? ? ? // 根據(jù)接口名限流
? ? ? ? ? ? RateLimiter rateLimiter = interfaces.get(request.getInterfaceName());
? ? ? ? ? ? // 獲取令牌桶中一個(gè)令牌,如果獲取不到,則等待 timeout 時(shí)間,如果還獲取不到,則返回false,反之則返回true
? ? ? ? ? ? // timeout設(shè)置為0,表示不等待
? ? ? ? ? ? if(rateLimiter.tryAcquire(1,0,TimeUnit.SECONDS)){
? ? ? ? ? ? ? ? // 得到令牌,處理請(qǐng)求
? ? ? ? ? ? ? ? threadPool.execute(()->{
? ? ? ? ? ? ? ? ? ? System.err.println("接口:"+request.getInterfaceName()+" 訪問還未達(dá)到上限,"+request.getUserName()+"可以訪問");
? ? ? ? ? ? ? ? });
? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? // 已經(jīng)等待了10秒還獲取不到令牌,進(jìn)行其他業(yè)務(wù)處理
? ? ? ? ? ? ? ? System.err.println("當(dāng)前時(shí)間訪問失敗,"+request.getUserName()+"無(wú)法獲取令牌");
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? private static class UserRequest {
? ? ? ? /**
? ? ? ? ?* 請(qǐng)求用戶ip
? ? ? ? ?*/
? ? ? ? private String ip;
? ? ? ? /**
? ? ? ? ?* 用戶名
? ? ? ? ?*/
? ? ? ? private String userName;
? ? ? ? /**
? ? ? ? ?* 請(qǐng)求的接口名
? ? ? ? ?*/
? ? ? ? private String interfaceName;
? ? ? ? public UserRequest(String ip, String userName, String interfaceName) {
? ? ? ? ? ? this.ip = ip;
? ? ? ? ? ? this.userName = userName;
? ? ? ? ? ? this.interfaceName = interfaceName;
? ? ? ? }
? ? ? ? public String getIp() {return ip;}
? ? ? ? public String getUserName() { return userName;}
? ? ? ? public String getInterfaceName() {return interfaceName;}
? ? }
}場(chǎng)景二:
當(dāng)我們希望某一個(gè)用戶或者ip,每秒的訪問量不超過(guò)10
package org.xhs.test;
import org.apache.curator.shaded.com.google.common.util.concurrent.RateLimiter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
/**
?* @Author: hu.chen
?* @Description:
?**/
public class Test {
? ? /**
? ? ?* 存儲(chǔ)用戶名和令牌生成器的對(duì)應(yīng)關(guān)系
? ? ?*/
? ?private static Map<String, RateLimiter> interfaces = new ConcurrentHashMap<>();
? ? /**
? ? ?* 線程池
? ? ?*/
? ? private static ExecutorService threadPool = new ThreadPoolExecutor(10,15,3,TimeUnit.SECONDS,new ArrayBlockingQueue<>(100));
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? List<UserRequest> tasks = new ArrayList<UserRequest>();
? ? ? ? // 準(zhǔn)備工作,先初始化 10個(gè)線程(用戶),這10個(gè)用戶同時(shí)訪問一個(gè)接口
? ? ? ? for (int i = 1; i <= 12; i++) {
? ? ? ? ? ? String ip = "127.0.0." + i;
? ? ? ? ? ? String userName="chenhu_";
? ? ? ? ? ? String interfaceName="user/find_"+i;
? ? ? ? ? ? tasks.add(new UserRequest(ip,userName,interfaceName));
? ? ? ? }
? ? ? ? // 先初始化好令牌生成器
? ? ? ? for (UserRequest request : tasks) {
? ? ? ? ? ? // 根據(jù)接口名限流
? ? ? ? ? ? RateLimiter rateLimiter = interfaces.get(request.getUserName());
? ? ? ? ? ? if(rateLimiter==null){
? ? ? ? ? ? ? ? // 創(chuàng)建一個(gè)令牌生成器,每秒產(chǎn)生5個(gè)令牌
? ? ? ? ? ? ? ? synchronized (interfaces) {
? ? ? ? ? ? ? ? ? ? if(rateLimiter==null) {
? ? ? ? ? ? ? ? ? ? ? ? rateLimiter = RateLimiter.create(10);
? ? ? ? ? ? ? ? ? ? ? ? // 將這個(gè)令牌生成器和具體的接口進(jìn)行綁定
? ? ? ? ? ? ? ? ? ? ? ? interfaces.put(request.getUserName(),rateLimiter);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? // 休眠一秒,讓令牌生成器先生成令牌
? ? ? ? Thread.sleep(1000);
? ? ? ? for (UserRequest request : tasks) {
? ? ? ? ? ? // 根據(jù)接口名限流
? ? ? ? ? ? RateLimiter rateLimiter = interfaces.get(request.getUserName());
? ? ? ? ? ? // 獲取令牌桶中一個(gè)令牌,如果獲取不到,則等待 timeout 時(shí)間,如果還獲取不到,則返回false,反之則返回true
? ? ? ? ? ? // timeout設(shè)置為0,表示不等待
? ? ? ? ? ? if(rateLimiter.tryAcquire(1,0,TimeUnit.SECONDS)){
? ? ? ? ? ? ? ? // 得到令牌,處理請(qǐng)求
? ? ? ? ? ? ? ? threadPool.execute(()->{
? ? ? ? ? ? ? ? ? ? System.err.println("用戶:"+request.getUserName()+" 當(dāng)前時(shí)間訪問次數(shù)還未達(dá)到上限,可以訪問");
? ? ? ? ? ? ? ? });
? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? // 已經(jīng)等待了10秒還獲取不到令牌,進(jìn)行其他業(yè)務(wù)處理
? ? ? ? ? ? ? ? System.err.println("當(dāng)前時(shí)間訪問失敗,"+request.getUserName()+"無(wú)法獲取令牌");
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? private static class UserRequest {
? ? ? ? /**
? ? ? ? ?* 請(qǐng)求用戶ip
? ? ? ? ?*/
? ? ? ? private String ip;
? ? ? ? /**
? ? ? ? ?* 用戶名
? ? ? ? ?*/
? ? ? ? private String userName;
? ? ? ? /**
? ? ? ? ?* 請(qǐng)求的接口名
? ? ? ? ?*/
? ? ? ? private String interfaceName;
? ? ? ? public UserRequest(String ip, String userName, String interfaceName) {
? ? ? ? ? ? this.ip = ip;
? ? ? ? ? ? this.userName = userName;
? ? ? ? ? ? this.interfaceName = interfaceName;
? ? ? ? }
? ? ? ? public String getIp() {return ip;}
? ? ? ? public String getUserName() { return userName;}
? ? ? ? public String getInterfaceName() {return interfaceName;}
? ? }
}以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java限流實(shí)現(xiàn)的幾種方法詳解
- 詳解5種Java中常見限流算法
- Java服務(wù)限流算法的6種實(shí)現(xiàn)
- Java中實(shí)現(xiàn)接口限流的方案詳解
- java通過(guò)信號(hào)量實(shí)現(xiàn)限流的示例
- 關(guān)于Java限流功能的簡(jiǎn)單實(shí)現(xiàn)
- 使用Java自定義注解實(shí)現(xiàn)一個(gè)簡(jiǎn)單的令牌桶限流器
- Java中常見的4種限流算法詳解
- Java實(shí)現(xiàn)限流接口的示例詳解
- Java面試之限流的實(shí)現(xiàn)方式小結(jié)
- Java代碼實(shí)現(xiàn)四種限流算法詳細(xì)介紹
相關(guān)文章
Java8中用foreach循環(huán)獲取對(duì)象的index下標(biāo)詳解
這篇文章主要給大家介紹了關(guān)于Java8中用foreach循環(huán)獲取對(duì)象的index下標(biāo)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
MybatisPlus查詢條件為空字符串或null問題及解決
這篇文章主要介紹了MybatisPlus查詢條件為空字符串或null問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
Java均攤復(fù)雜度和防止復(fù)雜度的震蕩原理分析
這篇文章主要介紹了Java均攤復(fù)雜度和防止復(fù)雜度的震蕩,結(jié)合實(shí)例形式分析了Java均攤復(fù)雜度和防止復(fù)雜度的震蕩相關(guān)概念、原理、實(shí)現(xiàn)方法與注意事項(xiàng),需要的朋友可以參考下2020-03-03
Springboot整合JPA配置多數(shù)據(jù)源流程詳解
這篇文章主要介紹了Springboot整合JPA配置多數(shù)據(jù)源,JPA可以通過(guò)實(shí)體類生成數(shù)據(jù)庫(kù)的表,同時(shí)自帶很多增刪改查方法,大部分sql語(yǔ)句不需要我們自己寫,配置完成后直接調(diào)用方法即可,很方便2022-11-11
Spring MVC 中 AJAX請(qǐng)求并返回JSON的示例
本篇文章主要介紹了Spring MVC 中 AJAX請(qǐng)求并返回JSON,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01

