1. 程式人生 > 其它 >主流的四種限流策略,linux核心視訊教程

主流的四種限流策略,linux核心視訊教程

主流的四種限流策略,linux核心視訊教程
  • 在web開發中功能是基石,除了功能以外運維和防護就是重頭戲了。因為在網站執行期間可能會因為突然的訪問量導致業務異常、也有可能遭受別人惡意攻擊

  • 所以我們的介面需要對流量進行限制。俗稱的QPS也是對流量的一種描述

  • 針對限流現在大多應該是令牌桶演算法,因為它能保證更多的吞吐量。除了令牌桶演算法還有他的前身漏桶演算法和簡單的計數演算法

  • 下面我們來看看這四種演算法

固定時間視窗演算法


  • 固定時間視窗演算法也可以叫做簡單計數演算法。網上有很多都將計數演算法單獨抽離出來。但是筆者認為計數演算法是一種思想,而固定時間視窗演算法是他的一種實現

  • 包括下面滑動時間視窗演算法也是計數演算法的一種實現。因為計數如果不和時間進行繫結的話那麼失去了限流的本質了。就變成了拒絕了

優點

  • 在固定的時間內出現流量溢位可以立即做出限流。每個時間視窗不會相互影響

  • 在時間單元內保障系統的穩定。保障的時間單元內系統的吞吐量上限

缺點

  • 正如圖示一樣,他的最大問題就是臨界狀態。在臨界狀態最壞情況會受到兩倍流量請求

  • 除了臨界的情況,還有一種是在一個單元時間窗內前期如果很快地消耗完請求閾值。那麼剩下的時間將會無法請求。這樣就會因為一瞬間的流量導致一段時間內系統不可用。這在網際網路高可用的系統中是不能接受的。

實現

  • 好了,關於原理介紹及優缺點我們已經瞭解了。下面我們動手實現它

  • 首先我們在實現這種計數時,採用redis是非常好的選擇。這裡我們通過redis實現

controller


@RequestMapping(value = "/start",method = RequestMethod.GET)

    public Map<String,Object> start(@RequestParam Map<String, Object> paramMap) {

        return testService.startQps(paramMap);

    } 

service


@Override

public Map<String, Object> startQps(Map<String, Object> paramMap) {

    //根據前端傳遞的qps上線

    Integer times = 100;

    if (paramMap.containsKey("times")) {

        times = Integer.valueOf(paramMap.get("times").toString());

    }

    String redisKey = "redisQps";

    RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(redisKey, redisTemplate.getConnectionFactory());

    int no = redisAtomicInteger.getAndIncrement();

    //設定時間固定時間視窗長度 1S

    if (no == 0) {

        redisAtomicInteger.expire(1, TimeUnit.SECONDS);

    }

    //判斷是否超限  time=2 表示qps=3

    if (no > times) {

        throw new RuntimeException("qps refuse request");

    }

    //返回成功告知

    Map<String, Object> map = new HashMap<>();

    map.put("success", "success");

    return map;

} 

結果測試

  • 我們設定的qps=3 , 我們可以看到五個併發進來後前三個正常訪問,後面兩個就失敗了。稍等一段時間我們在併發訪問,前三個又可以正常訪問。說明到了下一個時間視窗

滑動時間視窗演算法


  • 針對固定時間視窗的缺點–臨界值出現雙倍流量問題。 我們的滑動時間視窗就產生了。

  • 其實很好理解,就是針對固定時間視窗,將時間視窗統計從原來的固定間隔變成更加細度化的單元了。

  • 在上面我們固定時間視窗演示中我們設定的時間單元是1S 。 針對1S我們將1S拆成時間戳。

  • 固定時間視窗是統計單元隨著時間的推移不斷向後進行。而滑動時間視窗是我們認為的想象出一個時間單元按照相對論的思想將時間固定,我們的抽象時間單元自己移動。抽象的時間單元比實際的時間單元更小。

  • 讀者可以看下下面的動圖,就可以理解了。

優點

  • 實質上就是固定時間視窗演算法的改進。所以固定時間視窗的缺點就是他的優點。

  • 內部抽象一個滑動的時間窗,將時間更加小化。存在邊界的問題更加小。客戶感知更弱了。

缺點

  • 不管是固定時間視窗演算法還是滑動時間視窗演算法,他們都是基於計數器演算法進行優化,但是他們對待限流的策略太粗暴了。

  • 為什麼說粗暴呢,未限流他們正常放行。一旦達到限流後就會直接拒絕。這樣我們會損失一部分請求。這對於一個產品來說不太友好

實現

  • 滑動時間視窗是將時間更加細化,上面我們是通過redis#setnx實現的。這裡我們就無法通過他統一記錄了。我們應該加上更小的時間單元儲存到一個集合彙總。然後根據集合的總量計算限流。redis的zsett資料結構就和符合我們的需求。

  • 為什麼選擇zset呢,因為redis的zset中除了值以外還有一個權重。會根據這個權重進行排序。如果我們將我們的時間單元及時間戳作為我們的權重,那麼我們獲取統計的時候只需要按照一個時間戳範圍就可以了。

  • 因為zset內元素是唯一的,所以我們的值採用uuid或者雪花演算法一類的id生成器

controller


@RequestMapping(value = "/startList",method = RequestMethod.GET)

    public Map<String,Object> startList(@RequestParam Map<String, Object> paramMap) {

        return testService.startList(paramMap);

    } 

service


String redisKey = "qpsZset";

        Integer times = 100;

        if (paramMap.containsKey("times")) {

            times = Integer.valueOf(paramMap.get("times").toString());

        }

        long currentTimeMillis = System.currentTimeMillis();

        long interMills = inter * 1000L;

        Long count = redisTemplate.opsForZSet().count(redisKey, currentTimeMillis - interMills, currentTimeMillis);

        if (count > times) {

            throw new RuntimeException("qps refuse request");

        }

        redisTemplate.opsForZSet().add(redisKey, UUID.randomUUID().toString(), currentTimeMillis);

        Map<String, Object> map = new HashMap<>();

        map.put("success", "success");

        return map; 

結果測試

  • 和固定時間視窗採用相同的併發。為什麼上面也會出現臨界狀況呢。因為在程式碼裡時間單元間隔比固定時間間隔採用還要大 。 上面演示固定時間視窗時間單元是1S出現了最壞情況。而滑動時間視窗設計上就應該間隔更短。而我設定成10S 也沒有出現壞的情況

  • 這裡就說明滑動比固定的優處了。如果我們調更小應該更加不會出現臨界問題,不過說到底他還是避免不了臨界出現的問題

漏桶演算法


  • 滑動時間視窗雖然可以極大程度地規避臨界值問題,但是始終還是避免不了

  • 另外時間演算法還有個致命的問題,他無法面對突如其來的大量流量,因為他在達到限流後直接就拒絕了其他額外流量

  • 針對這個問題我們繼續優化我們的限流演算法。 漏桶演算法應運而生

優點

  • 面對限流更加的柔性,不再粗暴的拒絕。

  • 增加了介面的接收性

  • 保證下流服務接收的穩定性。均勻下發

缺點

寫在最後

很多人感嘆“學習無用”,實際上之所以產生無用論,是因為自己想要的與自己所學的匹配不上,這也就意味著自己學得遠遠不夠。無論是學習還是工作,都應該有主動性,所以如果擁有大廠夢,那麼就要自己努力去實現它。

以上學習資料均免費放送,最後祝願各位身體健康,順利拿到心儀的offer!

由於文章的篇幅有限,所以這次的螞蟻金服和京東面試題答案整理在了PDF文件裡

資料獲取方式:點贊+評論我的文章,關注我,然後戳這裡即可免費領取