使用場景
系統使用下游資源時,需要考慮下游對資源受限、處理能力,在下游資源無法或者短時間內無法提升處理性能的情況下,可以使用限流器或者類似保護機制,避免下游服務崩潰造成整體服務的不可用。
常用算法
常見限流算法有兩種:漏桶算法和令牌桶算法。
限流的一般思路:
1、隨機丟棄一定規則的用戶(迅速過濾掉90%的用戶);
2、MQ削峰(比如設一個MQ可以容納的最大消息量,達到這個量后MQ給予reject);
3、業務邏輯層使用RateLimiter(令牌桶算法)進行限流;
4、最終可以承受的流量到達DB層。
package ratelimiter; import com.google.common.util.concurrent.RateLimiter; import org.springframework.stereotype.Component; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * @author xfyou * @date 2018/10/31 */ @Component public class AccessLimitService { private static volatile int acquireCount = 0; private static final Object OBJECT = new Object(); /** * 每秒可以獲得50個許可證 */ private RateLimiter rateLimiter = RateLimiter.create(50); private boolean tryAcquire() { // 等待1秒鍾如果未能獲取到許可證就返回false,否則返回true return rateLimiter.tryAcquire(1, 1000, TimeUnit.MILLISECONDS); } public static void main(String[] args) { AccessLimitService accessLimitService = new AccessLimitService(); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 1000; i++) { executorService.execute(new Runnable() { @Override public void run() { if (accessLimitService.tryAcquire()) { System.out.println("獲取許可證,執行業務邏輯。"); synchronized (OBJECT) { System.out.println(++acquireCount); } try { Thread.sleep(20); } catch (InterruptedException ex) { // } } else { System.err.println("未獲取到許可證,請求可以丟棄。"); } } }); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } executorService.shutdown(); } }