Kong Gatewayで流量制限をする際にはRate Limiting Pluginを使うが、これはOSS版とEnterprise版(Rate Limiting Advanced Plugin)で機能差がある。
機能比較した結果を一部抜粋したものが以下となる。
機能 | Rate Limiting Plugin | Rate Limiting Advanced Plugin |
---|---|---|
ライセンス | OSS | Konnect PremiumかEnterpriseのライセンス要 |
アルゴリズム | 固定ウィンドウ | スライディングウィンドウ、固定ウィンドウ |
カウントポリシー | local, cluster, redis(*) | local, cluster, redis |
*:Redis単体のみ。ClusterやSentinelは未サポート。
アルゴリズムの説明はこちらのブログが詳しいので、詳細が必要な場合は参考にするとよい。
ポリシーについては以下公式ドキュメントの記述を意訳したものとなる。
種類 | 長所 | 短所 |
---|---|---|
local |
パフォーマンスへの影響は最小限 | 精度は低くなる。ローカルで持つため、複数ノードでDataPlaneを構成した場合、LBで均等に分散しないと偏りが生じるリスクあり |
cluster |
ControlPlaneのDBを使うため追加コンポーネントなしで正確にカウントできる | 各リクエスト毎にDBへのRead/Writeが発生するため、性能影響大(ただしsync_rate で調整可)。またDB-Less構成では利用不可
|
redis |
正確かつcluster よりも性能影響低 |
Redis のインストールが必要。local と比べると性能影響大 |
上記より以下が言える。
- 流量制御で正確さが求められ、かつ高トラフィックを捌くようなケースではRedisが最適
- 上記のようなケースでは必然的にRedisの冗長性も求められるため、Redis Sentinelなどが必要
ということで、厳し目の流量制御が必要な場合はRate Limiting Advanced PluginでRedis Sentinel or Clusterが必要となる。
前置きが長くなったが、今回は硬くて正確な流量制限が必要な場合に取る構成となる、Rate Limiting Advanced PluginとRedis Sentinelを組み合わせた構成の作り方を確認する。
(SentinelにするかClusterにするかは迷ったが、こちらを参考にSentinelの方が良さげだったのでSentinelを選択した)
検証環境
今回は以下の環境で検証した。
- EKS
- Kong Gateway Enterprise 3.6 (Helmで構築済み)
RedisはKong Gatewayと同じクラスタ内に構築し、Service
でアクセスするようにする。
検証
Redis Sentinelの構築
BitnamiにあるHelm Chartが使えそうなのでこれを使う。
最初にBitnamiのリポジトリを追加する。
helm repo add bitnami https://charts.bitnami.com/bitnami
インストールする。
helm upgrade -i redis bitnami/redis --set sentinel.enabled=true -n redis --create-namespace --wait --debug
インストールが終わるとStatefulSetでRedis Podが展開されていることが分かる。
$ kubectl get pod -n redis
NAME READY STATUS RESTARTS AGE
redis-node-0 2/2 Running 0 40m
redis-node-1 2/2 Running 0 40m
redis-node-2 2/2 Running 0 39m
動作確認のため、試しに繋いでみる。
redis-cli
を使うためにredisのPodを起動する。
kubectl run redis --image redis -n default
Redisのパスワードを取得する。
REDIS_PASSWORD=$(kubectl get secret -n redis redis -o jsonpath={.data.redis-password} | base64 -d)
Redis Sentinelに対し、マスターがどれかを聞いてみる。
kubectl exec -it -n default redis -- redis-cli -a $REDIS_PASSWORD -h redis.redis.svc -p 26379 sentinel get-master-addr-by-name mymaster
以下のような出力が得られれば接続に成功している。
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1) "redis-node-0.redis-headless.redis.svc.cluster.local"
2) "6379"
Service/Routeの作成
Kong GatewayのService/Routeを設定する。
ここではバックエンドのサービスはhttpbin.orgとし、Proxyにパス/myhttpbin
でアクセス出来るようにする。
構築はKong ManagerからUIで行ってもいいが、ここではdeck
コマンドを利用するものとする。
まずdeck
用のYAMLを作成する。
cat <<EOF > ./svc-rt.yaml
_format_version: "3.0"
_workspace: redis-test
services:
- host: httpbin.org
name: httpbin-svc
port: 443
protocol: https
routes:
- name: httpbin-rt
paths:
- /myhttpbin
preserve_host: false
protocols:
- http
- https
request_buffering: true
response_buffering: true
strip_path: true
EOF
ここでは便宜上新しくWorkspace
としてredis-test
を作成している。
作成したYAMLを適用する。
deck gateway sync ./svc-rt.yaml
念の為動作確認としてhttpbin.org/user-agent
にProxy経由でアクセスしてみる。
PROXY=<Kong GatewayのProxyのアドレス>
curl $PROXY/myhttpbin/user-agent
問題なければ以下のような出力が得られる。
{
"user-agent": "curl/8.6.0"
}
Rate Limit Advanced Pluginの設定
ここでは作成したRouteに対してRate Limit Advanced Pluginを設定する。
Pluginの設定はこちらでもdeck
コマンドを利用して設定する。
deck
コマンドでPluginを設定する場合、先程のService/RouteのYAMLに追記する形で書くか、deck file add-plugins
というコマンドで既存の設定に別途Pluginだけ追加する方法がある。
ここではdeck file add-plugins
を使うやり方で設定する。
Pluginの設定ファイルを以下で作成する。
cat <<EOF > ./plugin-rate-limiting-adv.yaml
_format_version: "1.0"
add-plugins:
- selectors:
- $..routes[*]
overwrite: true
plugins:
- name: rate-limiting-advanced
config:
limit:
- 5
window_size:
- 30
identifier: ip
sync_rate: 0
namespace: redis
strategy: redis
redis:
sentinel_role: master
sentinel_addresses:
- redis.redis:26379
sentinel_master: mymaster
sentinel_password: $REDIS_PASSWORD
password: $REDIS_PASSWORD
EOF
細かい書き方については公式ドキュメントを参照して欲しい。
Rate Limitingの設定として、ウィンドウサイズを30秒、1つのウィンドウのアクセスの上限を5回とし、同期のタイミング(sync_rate
)を0に設定して常時同期するようにした。
Redisに関する設定はsentinel_role
、sentinel_addresses
、sentinel_master
が必須パラメータであり、Helmでデフォルトで入れると認証も必要となるのでパスワードもあわせて設定した。
Service/Routeに足す形で作成したPluginの設定を適用する。
deck file add-plugins -s svc-rt.yaml plugin-rate-limiting-adv.yaml | deck gateway sync -
コマンドを補足すると、-s svc-rt.yaml
でPluginを追加するソースのファイルを指定し、deck file add-plugins
はデフォルトで標準出力にYAMLを吐くので、それをdeck gateway sync
に渡している。(最後の-
はパイプで渡された標準出力をファイルとして渡している)
動作確認
実際にRedisに記録されることを確認する。
Rate Limiting Advanced Pluginを設定したパスにリクエストをいくつか発行する。
for((i=0; i<20; i++)); do curl -i $PROXY/myhttpbin/user-agent; sleep .5; done
Redisの中を確認する。
kubectl exec -it -n default redis -- redis-cli -a $REDIS_PASSWORD -h redis.redis.svc -p 6379 keys "*"
以下のようにRedis内にキーが作られていることが確認できる。
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1) "1720000830:30:redis"
これにより、アクセスの状況がRedisに残っている事が確認できた。