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

E704514df1d69d511c4c74771a40c8f5?s=128

COLOPL Inc.

April 27, 2022
Tweet

More Decks by COLOPL Inc.

Other Decks in Technology

Transcript

  1. コロプラ社の Redis 事情 尾山貴康 2022年4月27日(水)

  2. 自己紹介 • 尾山貴康 • 入社6年目(業界10年目) • サーバー基盤グループ ◦ 技術検証 ◦

    社内ライブラリのメンテ ◦ 開発チームのサポート
  3. もくじ • Redis とは • アーキテクチャー紹介 • 今のアーキテクチャーになった経緯 • 独自拡張した機能の紹介

    • 利用事例
  4. Redis とは

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

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

  7. Administration Redis Enterprise Cloud Durable Redis Enterprise Cloud Volatile Redis

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

  9. Redis Array (Client Sharding) on VM API Server PHP PHP

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

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

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

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

    Pods PHP PHP PHP …
  14. Twemproxy + GCP Memory Store 第3世代(2019~2020) GCP Memory Store とは

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

    Redis Proxy • 機能 ◦ Sharding ◦ Connection Pooling ◦ Command Pipelining Twemproxy API Servers GKE Pods PHP PHP PHP … 第3世代(2019~2020)
  16. 第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
  17. Twemproxy + GCP Memory Store 問題 ダウンタイムなしでスケールできない Memory Store が

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

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

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

    Enterprise Cloud Kubernetes Cluster アーキテクチャー API Servers GKE Pods Twemproxy
  21. 独自拡張した機能の紹介

  22. • Laravel Framework の PhpRedis のラッパークラス • 欲しい機能がいくつか足りなかったので拡張 1. Twemproxy

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

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

    すれば通る • ということで、Exponential Backoff + Jitter な Retry を実装 ※ 最近 PhpRedis 側に同等の機能が実装されたので廃止予定 https://github.com/phpredis/phpredis#retry-and-backoff
  25. 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"
  26. 利用事例

  27. レスポンスキャッシング

  28. レスポンスキャッシング レスポンスがタイムアウトするとめんどくさい問題 POST /battle/finish ユーザー API サーバー バトルインスタンス削除 200 OK

    timeout サーバー側では処理が終わっている クライアント側はエラる どうする?
  29. レスポンスキャッシング(過去の対応) 個別に対応 ↓ 実装、テストの工数増加 ユーザーをタイトルに戻す ↓ ユーザーイライラ 離脱率上昇 😭 機会損失

    😭
  30. レスポンスキャッシング Timeout はそこそこ頻繁に発生する • トイレに入った時 • エレベーターに乗った時 • WiFi →

    Cellular (家を出た時など) • 公共 WiFi (駅など) 大体 Request の 0.01%(1万リクエストに1回) はリトライ処理
  31. レスポンスキャッシング ということで以下の方法で対応 クライアントは Timeout したらとりあえずリトライする サーバーはGET以外のレスポンスを Redis にまるごと保存しておき、 同じリクエストがリトライされてきたら キャッシュされている情報をそのまま返す

  32. レスポンスキャッシング(シーケンス図) 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 検知 レスポンスを キャッシュに保存 リトライ!
  33. レスポンスキャッシング Redis をフルに活用することによって、 ユーザーが快適にプレイでき、 エンジニアにも負担が少ない実装を実現することができました。

  34. まとめ コロプラでは • Redis Enterprise Cloud を使っています ◦ Failover が高速で障害にならないから

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