流控算法探討——之計數器模型原理及實現

流控模型

概述

即流量控制,有的地方叫作」限流算法」。對於一個系統來講,受限於資源(CPU、內存、帶寬、I/O等等因素)其處理能力是有限的,一旦客戶的流量超過這個限制,每每會引來災難性的後果。所以各類「限流算法」應運而生。比較簡單的有如下幾種模型算法

  • 計數器模型
  • 漏斗模型
  • 令牌桶模型

受限於本人的知識和眼界,目前只瞭解這三種模型,若是從此學習到更多的模型,會補上。多線程

打算分三篇文章來分別探討這幾種模型的原理及其C++實現。本文是第一篇。性能

計數器算法

先介算法原理、接口,最後實現一個可用基於計數器的限流器。學習

原理

我認爲這是最「簡單粗暴的方法」,使用一個累加器來記錄請求次數(即流量),而後按照規定的時間間隔來檢查累加器的數值。這個模型能夠採用「單線程」、「多線程」、「定時器」等多種多樣的手段來實現。
該模型優勢是實現起來簡單,缺點也很明顯:功能太弱、性能不高、不平滑。fetch

接口設計

接口設計ui

計數器模型的實現

無鎖的單線程實現

基於C++11標準atom

#ifndef RATE_LIMIT_H
#define RATE_LIMIT_H

#include <atomic>
#include <chrono>

class RateLimit
{
private:
    // uncopyable
    RateLimit(RateLimit&&) = delete;
    RateLimit(const RateLimit&) = delete;
    const RateLimit& operator=(const RateLimit&) = delete;

public:
    ///< rate: counter per second
    ///< timeWindow: second(s)
    RateLimit(uint64_t rate, uint64_t timeWindow)
        : m_rate(rate)
        , m_timeWindow(timeWindow * 1000 * 1000)
    {}

    bool Consume()
    {
        const uint64_t now = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
        if (m_time + m_timeWindow <= now)
        {
            m_time = now;
            m_count = 1;
            return true;
        }
        const auto count = m_count.fetch_add(1);
        return (count < m_rate);
    }

private:
    std::atomic<uint64_t> m_time = { 0 }; // the start timepoint of the window
    std::atomic<uint64_t> m_count = { 0 }; // count in one window
    const std::atomic<uint64_t> m_rate {0};
    const std::atomic<uint64_t> m_timeWindow {0}; // micro seconds
};
#endif
相關文章
相關標籤/搜索