Upgrade to Pro — share decks privately, control downloads, hide ads and more …

コロプラ社のRedis事情/ColoplTech-04-01

 コロプラ社のRedis事情/ColoplTech-04-01

※資料内の参照リンクを選択し閲覧する場合は、ダウンロードをお願いいたします

\積極的に技術発信を行なっております/
▽ Twitter/COLOPL_Tech
https://twitter.com/colopl_tech

▽ connpassページ
http://colopl.connpass.com

▽ COLOPL Tech Blog
http://blog.colopl.dev

COLOPL Inc.

April 27, 2022
Tweet

More Decks by COLOPL Inc.

Other Decks in Technology

Transcript

  1. 2009年に Salvatore Sanfilippo が開発 メモリ上で動作する Key Value Store Remote Dictionary

    Server の略らしい 特徴 • インメモリーなので高速(ミリ秒未満) • 主にデータの共有キャッシュとして使われる • Key Value Store だけじゃない ◦ Sorted Set (ランキングなどに使う) ◦ Pubsub(Queueなどに使う) ◦ Streams(チャットなどに使う) Redis とは
  2. Administration Redis Enterprise Cloud Durable Redis Enterprise Cloud Volatile Redis

    Enterprise Cloud ロストしたくないデータ用(カウンターなど) シャーディング あり データ永続化 あり レプリカ あり ロストしてもいいデータ用(キャッシュなど) シャーディング あり データ永続化 なし レプリカ なし Kubernetes Cluster アーキテクチャー API Servers GKE Pods Twemproxy 内部管理用(管理ツール → Podへの通知に使う) シャーディング なし データ永続化 なし レプリカ なし
  3. Redis Array (Client Sharding) on VM API Server PHP PHP

    PHP … 第1世代(~2017) • アプリ側で分散ロジックを実装 • 接続先はアプリ側の設定ファイルで管理
  4. Redis (Client Sharding) on VM 問題 • IPアドレスをアプリの設定ファイルにベタ打ちで更新が大変 • 一台でも落ちるとマニュアル復旧

    • スケールインやアウトするのが大変 • スケールするとデータが消える 第1世代(~2017)
  5. Redis Cluster on K8s • ダウンタイムなしでスケールが可能に • Sharding のロジックが Cluster

    側に移行によりアプリ側のメンテナンス性 UP Cluster Mode API Servers GKE Pods PHP PHP PHP … 第2世代(2017~2019)
  6. Redis Cluster on K8s ops / sec nodes 理想 現実

    request / sec connections 第2世代(2017~2019) 独自調査 Redis Benchmark (https://redis.io) 問題 • Node 数を増やしてもパフォーマンスが線形に伸びない(左の図) • Connection 数が増えるとパフォーマンスが下がる(右の図)
  7. Twemproxy + GCP Memory Store 第3世代(2019~2020) GCP Memory Store とは

    • Google Cloud 社のマネージド Redis • 自動フェイルオーバー • 簡単レプリケーション
  8. Twemproxy + GCP Memory Store Twemproxy とは • Twitter 社が開発した

    Redis Proxy • 機能 ◦ Sharding ◦ Connection Pooling ◦ Command Pipelining Twemproxy API Servers GKE Pods PHP PHP PHP … 第3世代(2019~2020)
  9. 第3世代(2019~2020) Twemproxy イメージ Twemproxy PHP PHP PHP PHP コネクション数 x3

    コネクション数 x1 PHP GET k1 GET k2 INCR k3 PHP GET k1 GET k2 INCR k3 BEFORE AFTER − 1 Pod 1 Connection − 1 Process 1 Connection localhost:6379 K8s Pod K8s Pod
  10. Twemproxy + GCP Memory Store 問題 ダウンタイムなしでスケールできない Memory Store が

    Failover するのに数秒〜数分かかる 第3世代(2019~2020)
  11. Twemproxy + Redis Enterprise Cloud Twemproxy localhost:6379 API Servers GKE

    Pods PHP Redis Enterprise Cloud PHP PHP … 第4世代(2021~) • Failover が速い(最大1分と書いてあるが実際は1秒以内) • スケールしてもデータが消えない(約1秒ダウンする)
  12. 残ってる問題 • Redis Enterprise Cloud ◦ 日本語のサポートがない ◦ ポート割り振りがランダムで使いにくい •

    Twemproxy ◦ 2016 以降メンテされてない(最近メンテナーが現れたが、更新は少なめ) ◦ PhpRedis との相性が悪い ▪ Twemproxy には一部独自エラーがあるが、 PhpRedis はそれを受け取っても 握りつぶしてしまう(false を返す) • 現在は Twemproxy 側を改造して対応 • PhpRedis に修正プルリク提出中(次のバージョンで入れてくれるかも?) https://github.com/phpredis/phpredis/pull/1832 第4世代(2021~)
  13. Administration Redis Enterprise Cloud Durable Redis Enterprise Cloud Volatile Redis

    Enterprise Cloud Kubernetes Cluster アーキテクチャー API Servers GKE Pods Twemproxy
  14. • Laravel Framework の PhpRedis のラッパークラス • 欲しい機能がいくつか足りなかったので拡張 1. Twemproxy

    対応 2. 切断時の自動リトライ 3. ちゃんとしたエラーハンドリング PhpRedisConnection の拡張
  15. 1)Twemproxy 対応 • Twemproxy 経由だと、FLUSH / KEYS / SCAN が使えない

    • Twemproxy 専用のアダプターを作成して以下の実装を加える a. 上記コマンドに実行時はTwemproxy の API を叩いて接続先一覧を取得 b. 一台一台、Twemproxy を経由せず、単体の Redis として接続 してコマンド実行 • どれも頻繁に使うコマンドではないのでパフォーマンスは気にしない Twemproxy PHP-FPM
  16. 2)切断時の自動リトライ • Redis Enterprise は Failover 時に数秒切断するがすぐ復旧する • なので基本的には Retry

    すれば通る • ということで、Exponential Backoff + Jitter な Retry を実装 ※ 最近 PhpRedis 側に同等の機能が実装されたので廃止予定 https://github.com/phpredis/phpredis#retry-and-backoff
  17. 3)ちゃんとしたエラーハンドリング • PhpRedis は一部のエラーを throw してくれない • なぜか false を返す

    • 本当のエラーは Redis::getLastError() の中に入っている • コマンド実行部分を拡張してエラーがないかチェックするコードを追加 >>> $redis->set('abc', '_'); => trueる >>> $redis->incr('abc'); => false >>> $redis->getLastError(); => "ERR value is not an integer or out of range\0"
  18. レスポンスキャッシング Timeout はそこそこ頻繁に発生する • トイレに入った時 • エレベーターに乗った時 • WiFi →

    Cellular (家を出た時など) • 公共 WiFi (駅など) 大体 Request の 0.01%(1万リクエストに1回) はリトライ処理
  19. レスポンスキャッシング(シーケンス図) POST /battle/finish Idempotency-Key: <UUID> クライアント API サーバー Redis SET

    <user_id>:<UUID> POST /battle/finish Idempotency-Key: <UUID> Retry-Count: 1 ❌ GET <user_id>:<UUID> Retry-Count 検知 キャッシュ参照 タイムアウト 思い届かず 200 OK 208 Already Reported Idempotency-Key 検知 レスポンスを キャッシュに保存 リトライ!
  20. まとめ コロプラでは • Redis Enterprise Cloud を使っています ◦ Failover が高速で障害にならないから

    ◦ データを維持したスケーリングができるから • Twemproxy を経由して Redis に接続しています ◦ Redis のコネクション数を減らすため • 上記を快適に使えるようにフレームワークを改造しました ◦ Twemproxy 対応、リトライ処理 など • 上記があることで Redis をフル活用した開発ができています ◦ レスポンスキャッシュ など