日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

java验证码限流_Java实现系统限流

發布時間:2023/12/10 windows 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java验证码限流_Java实现系统限流 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在微服務系統中,緩存、限流、熔斷是保證系統高可用的三板斧,今天我們就來聊聊限流。

限流是保障系統高可用的方式之一,當然啦也是大廠高頻面試題,如果阿里的面試官問一句:“如何實現每秒鐘1K個請求的限流?”,你要是分分鐘給他寫上幾種限流方案,那豈不香哉,哈哈:smirk:! 話不多說,我來列幾種常用限流實現方式。

Guava RateLimiter

Guava是Java領域很優秀的開源項目,包含了日常開發常用的集合、String、緩存等, 其中RateLimiter是常用限流工具。

RateLimiter是基于令牌桶算法實現的,如果每秒10個令牌,內部實現,會每100ms生產1個令牌。

使用Guava RateLimiter

引入pom依賴:

com.google.guava

guava

23.0

復制代碼

代碼:

public class GuavaRateLimiterTest{

//比如每秒生產10個令牌,相當于每100ms生產1個令牌

private RateLimiter rateLimiter = RateLimiter.create(10);

/**

* 模擬執行業務方法

*/

public void exeBiz(){

if (rateLimiter.tryAcquire(1)) {

try {

Thread.sleep(500);

} catch (InterruptedException 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 limiterTest = new GuavaRateLimiterTest();

Thread.sleep(500);//等待500ms,讓limiter生產一些令牌

//模擬瞬間生產100個線程請求

for (int i = 0; i < 100; i++) {

new Thread(limiterTest::exeBiz).start();

}

}

}

復制代碼

滑窗計數

打個比方,某接口每秒允許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() + ",index:" + index);

} else {

System.out.println(Thread.currentThread().getName() + "執行業務邏輯" + ",currentQPS:" + currentQPS() + ",index:" + index);

}

}

/**

* 定時執行器,

* 每N毫秒滑塊移動一次,然后再設置下新滑塊的初始化數字0,然后新的請求會落到新的滑塊上

* 同時總數減掉新滑塊上的數字,并且重置新的滑塊上的數量

*/

@Override

public void run(){

index = (index + 1) % block;

long val = countPerBlock[index].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();

}

}

復制代碼

信號量

利用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() {

@Override

public 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();

}

}

}

復制代碼

令牌桶

令牌桶算法:一個存放固定容量令牌的桶,按照固定速率往桶里添加令牌,如有剩余容量則添加,沒有則放棄。如果有請求進來,則需要先從桶里獲取令牌,當桶里沒有令牌可取時,則拒絕任務。

令牌桶的優點是:可以改變添加令牌的速率,一旦提高速率,則可以處理突發流量。

代碼:

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;

}

}

@Test

public void testTokenBucket() throws InterruptedException{

Bucket bucket = new Bucket(5, 2);

//固定線程,固定的速率往桶里放數據,比如每秒N個

ScheduledThreadPoolExecutor scheduledCheck = new ScheduledThreadPoolExecutor(1);

scheduledCheck.scheduleAtFixedRate(() -> {

bucket.put();

}, 0, 1, TimeUnit.SECONDS);

//先等待一會兒,讓桶里放點token

Thread.sleep(6000);

//模擬瞬間10個線程進來拿token

for (int i = 0; i < 10; i++) {

new Thread(() -> {

if (bucket.get()) {

System.out.println(Thread.currentThread() + "獲取到了資源");

} else {

System.out.println(Thread.currentThread() + "被拒絕");

}

}).start();

}

//等待,往桶里放token

Thread.sleep(3000);

//繼續瞬間10個線程進來拿token

for (int i = 0; i < 10; i++) {

new Thread(() -> {

if (bucket.get()) {

System.out.println(Thread.currentThread() + "獲取到了資源");

} else {

System.out.println(Thread.currentThread() + "被拒絕");

}

}).start();

}

}

}

復制代碼

總結

本文主要介紹幾種限流方法:Guava RateLimiter、簡單計數、滑窗計數、信號量、令牌桶,當然啦,限流算法還有漏桶算法、nginx限流等等。半支煙所寫的這些方法只是個人在實際項目總使用過的,或者是參加阿里筆試時寫過的方式。

如果你更好的想法,也歡迎跟我一起交流!

總結

以上是生活随笔為你收集整理的java验证码限流_Java实现系统限流的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。