Redisの分散型電流制限機構の実装方法

WBOY
リリース: 2023-05-11 08:49:35
オリジナル
1344 人が閲覧しました

インターネット アプリケーションの開発に伴い、インターネット企業にとって高い同時アクセスが非常に重要な問題になっています。システムの安定性を確保するには、悪意のある攻撃や過剰なアクセスによるシステムクラッシュを防ぐためにアクセスを制限する必要があります。電流制限メカニズムはインターネット アプリケーションで広く使用されており、人気のあるキャッシュ データベースとして Redis も分散型電流制限ソリューションを提供します。

Redis の電流制限メカニズムには、主に次の 2 つの実装方法があります:

1. トークン バケット アルゴリズムに基づく電流制限

トークン バケット アルゴリズムは、一般的に使用されるアルゴリズムです。ストリーミング アルゴリズムの 1 つである Redis は、トークン バケット アルゴリズムに基づいた電流制限ソリューションを提供します。このソリューションの実装は、主に Redis のオーダード セット (zset) と Lua スクリプトに基づいています。

トークン バケット アルゴリズムの原理は、トークンが一定のレートで投入される固定容量のバケットです。各リクエストは、処理される前にバケットからトークンを取得する必要があります。バケット内にトークンがない場合、リクエストは拒否されます。

Redis では、順序付きセット (zset) を使用してトークン バケットを構築できます。順序付きセット内の各要素はトークンを表し、そのスコアはトークンの到着時間を表し、値は任意の値にすることができます。トークンの取得操作の実装にはLuaスクリプトを使用します。具体的な実装コードは以下のとおりです。

-- 获取令牌
local function acquire_token(key, rate, capacity, now)
  local current_capacity = redis.call("zcount", key, "-inf", "+inf")
  local delta_time = 1000 / rate
  local expected_token = math.floor((now - delta_time * capacity) / delta_time)
  local available_token = math.min(expected_token - current_capacity, capacity)
  if available_token > 0 then
    local members = {}
    for i = 1, available_token do
      members[i] = now
    end
    redis.call("zadd", key, unpack(members))
  end

  local current_time = now
  local stop_time = current_time + 1000
  local expire_time = stop_time - delta_time * (available_token - 1)
  local result = redis.call("zrangebyscore", key, "-inf", expire_time)
  if #result > 0 then
    redis.call("zrem", key, unpack(result))
    return 1
  end

  return 0
end

-- 调用获取令牌操作
local result = acquire_token(KEYS[1], ARGV[1], ARGV[2], ARGV[3])
return result
ログイン後にコピー

このうち、KEYS[1]は電流制限キー、ARGV[1]はトークン投入率、ARGV[2]はバケットを表します。容量、ARGV[3] は現在の時刻を表します。

2. ファネル アルゴリズムに基づく電流制限

ファネル アルゴリズムも一般的に使用される電流制限アルゴリズムです。その原理はファネルです。リクエストは水のようにファネルに流れ込みます。ファネル アルゴリズムがいっぱいになるとオーバーフローします。 Redis では、順序付きセット (zset) と Lua スクリプトを使用してファネル アルゴリズムを実装することもできます。

ファネル アルゴリズムは、最後のリクエストの時刻とバケットの現在の容量を記録するためにファネル オブジェクトを維持する必要があります。新しいリクエストが届くと、アルゴリズムは現在の時間と最後のリクエスト時間の差に基づいてファネルの容量の増加を計算します。容量がバケットの最大容量より小さい場合、リクエストの通過が許可され、容量が減ります。それ以外の場合、リクエストは拒否されます。

具体的な実装コードは以下のとおりです。

-- 获取令牌
local function acquire_token(key, rate, capacity, now)
  local current_capacity = redis.call("hget", key, "capacity")
  local last_time = redis.call("hget", key, "last_time")

  if current_capacity == redis.error_reply or current_capacity == ngx.null then
    current_capacity = capacity
    redis.call("hset", key, "capacity", current_capacity)
  else
    current_capacity = tonumber(current_capacity)
  end

  if last_time == redis.error_reply or last_time == ngx.null then
    last_time = now
    redis.call("hset", key, "last_time", last_time)
  else
    last_time = tonumber(last_time)
  end

  local delta_time = now - last_time
  local expected_capacity = delta_time * rate / 1000 + current_capacity
  local actual_capacity = math.min(expected_capacity, capacity)

  if actual_capacity >= 1 then
    redis.call("hset", key, "capacity", actual_capacity - 1)
    redis.call("hset", key, "last_time", now)
    return 1
  end

  return 0
end

-- 调用获取令牌操作
local result = acquire_token(KEYS[1], ARGV[1], ARGV[2], ARGV[3])
return result
ログイン後にコピー

このうち、KEYS[1]は電流制限Key、ARGV[1]はファンネルの加水率、ARGV[2]を表します。 ] はファンネルの容量を表し、ARGV [3] は現在時間を表します。

概要

Redis が提供する分散型電流制限メカニズムは、同時アクセスを効果的に制御し、システムの安定性を確保できます。ビジネス ニーズに応じて電流制限アルゴリズムとしてトークン バケット アルゴリズムまたはファネル アルゴリズムを選択し、Redis のオーダード セット (zset) と Lua スクリプトを通じて実装できます。電流制限メカニズムを適用する場合、ユーザー エクスペリエンスへの悪影響を回避するために、特定のビジネス シナリオとトラフィック特性に基づいてアルゴリズム パラメーターを合理的に構成する必要があることに注意してください。

以上がRedisの分散型電流制限機構の実装方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート