從修身齊家治國平天下談分散式系統中的限流與熔斷
“古之慾明明德於天下者,先治其國;欲治其國者,先齊其家;欲齊其家者,先修其身;欲修其身者,先正其心;欲正其心者,先誠其意;欲誠其意者,先致其知,致知在格物。物格而後知至,知至而後意誠,意誠而後心正,心正而後身修,身修而後家齊,家齊而後國治,國治而後天下平。”--《禮記·大學》
在應對秒殺、大促、雙 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-Sent