從修身齊家治國平天下談分佈式系統中的限流與熔斷

  • 2019 年 10 月 3 日
  • 筆記

“古之欲明明德於天下者,先治其國;欲治其國者,先齊其家;欲齊其家者,先修其身;欲修其身者,先正其心;欲正其心者,先誠其意;欲誠其意者,先致其知,致知在格物。物格而後知至,知至而後意誠,意誠而後心正,心正而後身修,身修而後家齊,家齊而後國治,國治而後天下平。”–《禮記·大學》

在應對秒殺、大促、雙 11、618 等高性能壓力的場景時,限流已經成為了標配技術解決方案,為保證系統的平穩運行起到了關鍵性的作用。不管應用場景是哪種,限流無非就是針對超過預期的流量,通過預先設定的限流規則選擇性的對某些請求進行限流“熔斷”。

根據修身、齊家、治國平天下的理念,限流與熔斷要先從小點着手,即先對單機進行限流與熔斷,然後對微服務小集群做限流與熔斷,最後是對整個流程的服務集群做限流與熔斷。

1. 限流

1.1 單機限流(修身)

  修身

a>>限制並發量

import java.util.concurrent.ExecutorService;  import java.util.concurrent.Executors;  import java.util.concurrent.Semaphore;  public class SemaphoreTest {   private static final int THREAD_COUNT = 30;   private static ExecutorService threadPool = Executors   .newFixedThreadPool(THREAD_COUNT);   private static Semaphore s = new Semaphore(10);   public static void main(String[] args) {   for (int i = 0; i < THREAD_COUNT; i++) {   threadPool.execute(new Runnable() {   @Override   public void run() {   try {   s.acquire();   System.out.println(Thread.currentThread().getName());   Thread.sleep(5000);   System.out.println("--------------");   s.release();   } catch (InterruptedException e) {   }   }   });   }   threadPool.shutdown();   }  }

 

b>>計數器,以CountDownLatch為例

import java.util.concurrent.CountDownLatch;  public class CountDownLatchTest2 {   public static void main(String[] args) {   // 創建計數器,初始化為2   final CountDownLatch latch = new CountDownLatch(2);   new Thread(() -> {   try {   System.out.println("子線程"+Thread.currentThread().getName()+"正在執行");   Thread.sleep(3000);   System.out.println("子線程"+Thread.currentThread().getName()+"執行完畢");   latch.countDown();// 減一   } catch (InterruptedException e) {   e.printStackTrace();   }   }).start();   new Thread(() -> {   try {   System.out.println("子線程"+Thread.currentThread().getName()+"正在執行");   Thread.sleep(3000);   System.out.println("子線程"+Thread.currentThread().getName()+"執行完畢");   latch.countDown();   } catch (InterruptedException e) {   e.printStackTrace();   }   }).start();   try {   System.out.println("等待2個子線程執行完畢...");   // 阻塞   latch.await();   System.out.println("2個子線程已經執行完畢");   System.out.println("繼續執行主線程");   } catch (InterruptedException e) {   e.printStackTrace();   }   }  }

c>>guava RateLimiter

public void test()  {   /**   * 創建一個限流器,設置每秒放置的令牌數:2個。速率是每秒可以2個的消息。   * 返回的RateLimiter對象可以保證1秒內不會給超過2個令牌,並且是固定速率的放置。達到平滑輸出的效果   */   RateLimiter r = RateLimiter.create(2);   while (true)   {   /**   * acquire()獲取一個令牌,並且返回這個獲取這個令牌所需要的時間。如果桶里沒有令牌則等待,直到有令牌。   * acquire(N)可以獲取多個令牌。   */   System.out.println(r.acquire());   }  }

 

1.2 分佈式限流(齊家)

                齊家

a>> nginx

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;  server {   location / {   limit_req zone=mylimit;   }  }

 

b>>api-gateway+redis限流

https://github.com/wangzheng0822/ratelimiter4j

1.3 大流程限流(治國平天下)

可以從防火牆,cdn,路由器,api網關等做限流

                              治國平天下

2. 熔斷對比

熔斷處理邏輯類似,可以利用一些現成的框架,如Sentinel、Hystrix、resilience4j等。

功能對比

熔斷對比

參考文獻:

【1】https://mp.weixin.qq.com/s?__biz=MjM5MDE0Mjc4MA==&mid=2651008444&idx=1&sn=a579c3ceb143ea30930bd4c6d4a8d7e2&chksm=bdbed5ef8ac95cf93e71c5393f08e3b97a7e19e8232ce3872231f2cae74f7a19ab15501aeb44&scene=27#wechat_redirect

【2】https://mp.weixin.qq.com/s?__biz=MzIwMzY1OTU1NQ==&mid=2247484306&idx=1&sn=b6c1b7b9d7c57bbb9f82ec451bcda867&chksm=96cd43dea1bacac8a24cde429146f69dba8bb15c5c9c3fe9adfe858d9a4349cc127fbfa84a8c&scene=27#wechat_redirect

【3】https://github.com/alibaba/Sentinel/wiki/Guideline:-%E4%BB%8E-Hystrix-%E8%BF%81%E7%A7%BB%E5%88%B0-Sentinel