BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース GitHubがRedisを使用してレートリミットをスケールアップ

GitHubがRedisを使用してレートリミットをスケールアップ

原文(投稿日:2021/04/06)へのリンク

GitHubのエンジニアであるRobert Mosolgo氏は昨日、Redisのシャーディングとレプリケーションを使用したレートリミッタを使ってGitHub APIをスケールアップした方法について、詳細に説明した記事を投稿した。GitHubは以前のMemcachedベースのレートリミッタから、Redisベースのものに移行した。Mosolgo氏によると、新しい実装では信頼性の向上、クライアントの問題解決、GitHubのサポート負荷の低減が実現されている。

旧アーキテクチャのおもな問題は、他のアプリケーションキャッシュがMemcachedインスタンスをレートリミッタと共有している、という事実に関わるものだった。その問題は、2つの形で表面化した。ひとつは、GitHubが単一のMemcachedを共有する構成から、データセンタ毎に1インスタンスという構成へスイッチしようとしていたことだ。この変更により、クライアント要求が別のデータセンタにルートされると、レートリミッタが奇妙な動作を見せるようになった。もうひとつは、Memcachedが一杯になると(それが他のアプリケーションキャッシュによる場合でも)、アクティブなレートリミッタデータが排除される場合のあったことだ。これによって、エンドユーザがレートリミットを回避可能になるという、望ましくない状況が発生していた。

GitHubの選択したソリューションは、専用のシャーディングされたRedisクラスタに切り替える、というものだった。これは、"より適切な永続化システムを備えるとともに、シャーディングやレプリケーションのセットアップが簡単"である、という理由からだ。シャーディングはクライアント側で実行され、各クライアントはリクエスト毎に、読み取りと書き込みを行うRedisクラスタを選択する。単一のプライマリ(書き込み用)といくつかのレプリカ(読み込み用)が、それぞれクラスタを構成する。ストレージロジックはRedis上のLuaスクリプトで実装されており、オペレーションのアトミック性(atomicity)を保証する。

Mosologo氏は、チームが選択肢から除外した、その他のソリューションについても言及している。

検討の結果、不採用とした選択肢のひとつは、MySQLを使用した当社のKVストア(GitHub::KV)をストレージに使用する、というものでした。すでに負荷の高いMySQLプライマリに、これ以上トラフィックを追加したくない、というのがその理由です。通常のGET要求にはレプリカを使用して行うのですが、レート制限を更新するにはプライマリへの書き込みも必要になるからです。別のストレージバックエンドを選択することで、MySQLへの書き込みトラフィックの(大幅な)増加を回避することができました。

移行作業の中で、分散処理に関連する2つのバグが実装から見つかった。ひとつのバグは、返却されるレートリミットの"リセットタイムスタンプ"に、要求間で"揺らぎ"を生じさせていた。もうひとつのバグは、一部のクライアントの要求がタイムリミット超過として拒否されたにも関わらず、応答のヘッダにはリクエストクオータがまだ有効であると記される、というものだった。最終的にチームは、2つのパターンを組み合わせることで、両方のバグを修正した。ひとつは、一部の追加値について、実行時に複数回計算するのではなく、Redisデータベースに保存するようにしたことだ。この変更によってレートリミッタのストレージ使用量が増加したが、その見返りとして、より一貫性を保証できるようになった。次に、クラスタ内の読み込みセカンダリ(read-secondaries)から受信した古い値を一貫して処理するように、アプリケーションの再構成を行った。実装上の問題は同じ論理トランザクション内に古い値と新しい値が混在していたことによるものだったため、修正は、要求毎にいずれかの値セットのみを使用するようにして、エンドユーザから見た一貫性を実現する、というものだった。

この記事に星をつける

おすすめ度
スタイル

BT