天天看點

高可用(一)思維導圖一、高可用系統設計二、服務限流

思維導圖

高可用(一)思維導圖一、高可用系統設計二、服務限流

一、高可用系統設計

1.概述

系統大部分時間是可用的,即能為我們提供服務,即使在發生硬體故障或更新時。

1.1 判斷

(1)按時間

99.9999%可用:有0.0001%時間不可用

(2)按次數

成功次數與總請求次數之比

99%可用:網站請求100次,其中99次成功(也即1次失敗)

1.2 導緻不可用的情況

  • (1)黑客攻擊
  • (2)硬體故障,比如伺服器壞掉。
  • (3)并發量/使用者請求量激增導緻整個服務宕掉或者部分不可用
  • (4)代碼中原因導緻記憶體洩漏或者其他問題導緻程式挂掉
  • (5)網站架構某個重要元件如Nginx或者資料庫突然不可用
  • (6)自然災害或者人為破壞

2.提高可用性方法

2.1 注重代碼品質,測試嚴格把關

最重要,包括常見的記憶體洩露、循環依賴等會大量損害系統可用性

提高代碼神器:

  • Sonarqube
  • Alibaba 開源的 Java 診斷工具 Arthas
  • 阿裡巴巴 Java 代碼規範(Alibaba Java Code Guidelines)
  • IDEA 自帶的代碼分析等工具

2.2 使用叢集減少單點故障

2.3 限流

流量控制

原理: 監控應用流量的QPS、并發線程數等,當達到指定門檻值時對流量進行控制,已避免被瞬時的流量高峰沖垮。

2.4 逾時和重試機制設定

一旦使用者請求超各某個時間得不到響應就抛出異常

(1)若未設定逾時,導緻請求響應速度慢,甚至導緻請求堆積進而導緻系統無法再處理請求

(2)逾時設定方式不正确

(3)不适合重試或者重試次數過多(一般設為3次)

2.5 熔斷機制

系統自動收集所依賴服務的資源使用情況或性能名額,當所依賴的服務惡化或者失敗調用失敗次數達到某個門檻值時就迅速失敗,并讓目前系統立即切換依賴其他備用服務。

常用熔斷降級架構是Netflix 的 Hystrix 和 alibaba 的 Sentinel。

2.6 異步調用

使用者請求完成使用異步調用就能立即傳回結果,具體處理後續再做。

除了異步調用,還可以使用消息隊列

2.7 使用緩存

并發量高時大量請求直接請求資料庫可能會使資料庫挂掉,使用緩存則可以避免。

2.8 其他

  • 核心應用和服務優先使用更好的硬體
  • 監控系統資源使用情況增加報警設定
  • 注意備份,必要時候復原
  • 灰階釋出

    每次隻釋出服務叢集中若幹機器,若無問題繼續釋出其他機器,若有問題則復原已釋出的機器

  • 定期檢查、更換、更新硬體

二、服務限流

1.概念

對請求的速率進行限制,避免瞬時的大量請求擊垮系統。

2.算法

2.1 固定視窗計數器法

規定了我們機關時間處理的請求數量。

固定視窗其實就是時間視窗。

(1)示例

1分鐘隻能通路60次:

  • 設定目前接口處理的請求數量counter,初始值為0
  • 1分鐘内每處理一個請求counter+1,當counter=60之後就拒絕後面全部的請求
  • 等到1分鐘鐘之後将counter重置0,重新開始計數。

(2)缺點

  • 無法保證限流速率,因而無法保證突然激增的流量
  • 如:某個接口1分鐘内隻能通路1000次,該接口的QPS是500,前59s這個接口1個請求都沒有接收,後1s突然接收了1000個請求,系統直接就被瞬時的大量請求給擊垮了
高可用(一)思維導圖一、高可用系統設計二、服務限流

2.2 滑動視窗計數器法

在固定視窗計數器算法上把時間按一定比例分片。

(1)示例

1分鐘隻能通路60次:

  • 把1分鐘分為60個視窗
  • 每隔1秒移動一次,每個視窗1s隻能處理不大于60請求數/60視窗數=1個請求數的請求
  • 如果目前視窗的請求計數總和超過限制數量的話,就不再處理其他請求
  • 當滑動視窗的格子劃分的越多,滑動視窗的滾動就越平滑,限流的統計就會越準确
高可用(一)思維導圖一、高可用系統設計二、服務限流

2.3 漏桶算法

準備一個隊列用來儲存請求,然後定期從隊列中拿請求來執行(類似消息隊列削峰/限流)

高可用(一)思維導圖一、高可用系統設計二、服務限流

2.4 令牌桶算法

  • 請求在被處理前需要從桶裡拿到一個令牌,請求處理完将這個令牌丢棄(删除)
  • 我們根據限流大小,按照一定的速率往桶裡添加令牌。
  • 如果桶裝滿了,就不能繼續往裡面繼續添加令牌了。
高可用(一)思維導圖一、高可用系統設計二、服務限流

3.單機限流

針對單體架構應用

2.1 RateLimiter

2.1.2 概述

  • Google Guava 自帶的限流工具類 ,不僅有令牌桶算法(平滑突發限流)實作,還有平滑預熱限流算法實作。
  • 平華突發限流就是按照指定的速率放令牌到桶裡
  • 平滑預熱限流則會有一段預熱時間,預熱時間之内,速率會逐漸提升到配置的速率

2.1.3 代碼實作

(1)引入依賴
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>
           
(2)RateLimiter平滑突發限流的Demo
import com.google.common.util.concurrent.RateLimiter;

public class RateLimiterDemo {

    public static void main(String[] args) {
        // 1s 放 5 個令牌到桶裡也就是 0.2s 放 1個令牌到桶裡
        RateLimiter rateLimiter = RateLimiter.create(5);
        for (int i = 0; i < 10; i++) {
            double sleepingTime = rateLimiter.acquire(1);
            System.out.printf("get 1 tokens: %ss%n", sleepingTime);
        }
    }
}

           

輸出:

get 1 tokens: 0.0s
get 1 tokens: 0.188413s
get 1 tokens: 0.197811s
get 1 tokens: 0.198316s
get 1 tokens: 0.19864s
get 1 tokens: 0.199363s
get 1 tokens: 0.193997s
get 1 tokens: 0.199623s
get 1 tokens: 0.199357s
get 1 tokens: 0.195676s
           
(3)RateLimiter平滑預熱限流的Demo
import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.TimeUnit;


public class RateLimiterDemo {

    public static void main(String[] args) {
        // 1s 放 5 個令牌到桶裡也就是 0.2s 放 1個令牌到桶裡
        // 預熱時間為3s,也就說剛開始的 3s 内發牌速率會逐漸提升到 0.2s 放 1 個令牌到桶裡
        RateLimiter rateLimiter = RateLimiter.create(5, 3, TimeUnit.SECONDS);
        for (int i = 0; i < 20; i++) {
            double sleepingTime = rateLimiter.acquire(1);
            System.out.printf("get 1 tokens: %sds%n", sleepingTime);
        }
    }
}

           

輸出:

get 1 tokens: 0.0s
get 1 tokens: 0.561919s
get 1 tokens: 0.516931s
get 1 tokens: 0.463798s
get 1 tokens: 0.41286s
get 1 tokens: 0.356172s
get 1 tokens: 0.300489s
get 1 tokens: 0.252545s
get 1 tokens: 0.203996s
get 1 tokens: 0.198359s
           

Guava 位址:

https://github.com/google/guava

2.2 Bucket4j 與Resilience4j

2.2.1 Bucket4j

Bucket4j基于令牌/漏桶算法不錯的限流庫

  • RateLimiter簡單開箱即用,單機場景下實用
  • Bucket4j限流功能更全面,支援單機限流、分布式限流,還可以內建監控,搭配Prometheus 和 Grafana 使用。

Bucket4j 位址:

https://github.com/vladimir-bukhtoyarov/bucket4j

2.2.1 Bucket4j

  • 輕量級容錯元件,Spring官方和Netflix推薦使用做限流熔斷,SpringCloud Gateway 基于它實作。
  • 提供限流、熔斷、負載保護、自動重試等保障系統高可用開箱即用的功能
  • 生态很好,很多網關都是用它做限流熔斷

Resilience4j 位址:

https://github.com/resilience4j/resilience4j

3.分布式限流

針對分布式、微服務應用架構應用

3.1 常見方案

(1)借助中間件/架構限流

如:用Sentinel、Redis來實作對應的限流邏輯

(2) 網關層限流

網關層限流通常也要用中間件/架構:

  • 如SpringCloud Gateway 的分布式限流實作RedisRateLimiter基于Redis+Lua來實作
  • 如SpringCloud Gateway還可以整合Sentinel來做限流

見我另一篇文章:

SpringCloud之Sentinel

(3) Redis+Lua方式

優點:

  • 減少網絡開銷

    利用Lua腳本送出批量Redis指令到Redis伺服器一次性執行批量

  • 原子性

    一段Lua腳本執行中不會有其他腳本或者Redis指令同時執行

項目實作:

Apache網關項目ShenYu的RateLimiter限流插件基于Redis+Lua實作了令牌桶算法/并發令牌桶算法/漏桶算法/滑動視窗算法。

ShenYu 位址:

https://github.com/apache/incubator-shenyu

備注:

網上也有很多現成的優秀的Redis+Lua限流腳本

下一篇跳轉—高可用(二)

本篇文章主要參考連結如下:

參考連結1-JavaGuide

持續更新中…

随心所往,看見未來。Follow your heart,see light!

歡迎點贊、關注、留言,一起學習、交流!