Slide 1

Slide 1 text

Google Cloud の新サービス 「Memorystore for Redis Cluster 」導入事例 :「Memorystore for Memcached」からの 移行と運用 株式会社 WFS エンジニア 檜垣颯汰

Slide 2

Slide 2 text

檜垣颯汰 グリー株式会社に2022年6月新卒入社。株式会社 WFSにてプロダクトのサーバーエンジニアとして 開発、運用、保守に幅広く従事。2024年9月より サーバーリードとしてチームを牽引している。 株式会社 WFS サーバーエンジニア 2

Slide 3

Slide 3 text

アジェンダ ● プロダクトの課題:Memorystore for Memcached ● Memorystore for Memcached 移行先の検討 ● Memorystore for Redis Cluster 導入試験 ● Memorystore for Redis Cluster 負荷検証 ● Memorystore for Redis Cluster の本番運用について ● まとめ ● 今後の展望 3

Slide 4

Slide 4 text

プロダクトの課題: Memorystore for Memcached 4

Slide 5

Slide 5 text

プロダクトの前提 ● Google Kubernetes Engine (GKE) + PHP + Apache ● キャッシュサーバーとして Memorystore for Memcached を使用 ● 極力全体メンテナンスを行わない運用 5

Slide 6

Slide 6 text

プロダクトの課題 キャッシュサーバーとして Memorystore for Memcached を使用 以下の問題を抱えていた ● メンテナンスで最大数時間停止する ● 台数変更の運用コストが高い ● フェイルオーバーできない 6

Slide 7

Slide 7 text

課題 1 メンテナンスで最大数時間停止する メンテナンスウィンドウは最低 3 時間必要 > ウィンドウの期間は 3〜8 時間の間でユーザーが構成できます。 https://cloud.google.com/memorystore/docs/memcached/about-maintenance#duration-faq 実際にメンテナンスを行なった際は 3 時間を少し超えて完了した 7

Slide 8

Slide 8 text

課題 2 台数変更の運用コストが高い ノードの増減時はクライアント側のノードリストを手動で変更する必要がある ● Memorystore for Memcached はヘルスチェックが取れない ノード数を増減させると、キースペースが再分散されてしまいキャッシュミスが起 こってしまうため慎重なオペレーションが必要 8

Slide 9

Slide 9 text

課題 3 フェイルオーバーができない Memcached にはプライマリ・レプリカという概念が存在しない ノードが落ちた時、手動で対応しない限り同じノードにアクセスし続けてしまう ● Memorystore for Memcached はヘルスチェックが取れない 9

Slide 10

Slide 10 text

プロダクトの課題(再掲) キャッシュサーバーとして Memorystore for Memcached を使用 以下の問題を抱えていた ● メンテナンスで最大数時間停止する ● 台数変更の運用コストが高い ● フェイルオーバーできない 10

Slide 11

Slide 11 text

プロダクトの課題(再掲) キャッシュサーバーとして Memorystore for Memcached を使用 以下の問題を抱えていた ● メンテナンスで最大数時間停止する ● 台数変更の運用コストが高い ● フェイルオーバーできない 11 Memorystore for Memcached からの移行を検討

Slide 12

Slide 12 text

Memorystore for Memcached 移行先の検討 12

Slide 13

Slide 13 text

移行先候補 (1) Memorystore for Redis ● ○ すでにランキングなどで使用しているので移行が楽 ● × プライマリのスケールアウトができず、CPUが頭打ちになる懸念あり 13

Slide 14

Slide 14 text

移行先候補 (2) 自前でキャッシュサーバーを立てる ● ○ 細かい制御ができる ● × メンテナンスコストが高い 14

Slide 15

Slide 15 text

移行先候補 (3) Memorystore for Redis Cluster ● ○ 水平スケール・フェイルオーバー の運用コストが少ない ● △ リリースしたばかりのため、他社事例が 0 15

Slide 16

Slide 16 text

● 水平スケール・フェイルオーバー によりサービスの可用性を向上できる ● 運用コストを最小限に抑えられる 上記をともに満たす Memorystore for Redis Cluster を検討 移行先の検討 16 クライアント (PHPサーバー) プライマリ  レプリカ

Slide 17

Slide 17 text

Memorystore for Redis Cluster 導入試験 17

Slide 18

Slide 18 text

導入試験 Memorystore for Redis Cluster によって 既存の課題が解決するかどうかを 実際の運用にそって検証 18

Slide 19

Slide 19 text

プロダクトの課題(再掲) 1. メンテナンスで最大数時間停止する 2. 台数変更の運用コストが高い 3. フェイルオーバーできない 19

Slide 20

Slide 20 text

課題 1: メンテナンスで最大数時間停止する メンテナンスはダウンタイムなしと記載あり https://cloud.google.com/memorystore/docs/cluster/about-maintenance#scheduled_maintenance ● メンテナンスをテストすることはできない 20

Slide 21

Slide 21 text

課題 2: 台数変更の運用コストが高い 公式ドキュメントによると、無停止でスケーリングできる 21 https://cloud.google.com/memorystore/docs/cluster/about-scaling-instance-capacity

Slide 22

Slide 22 text

課題 2: 台数変更の運用コストが高い また、Web UI 上で簡単に台数変更ができる クライアント側で台数の変更を意識しなくて良い 22

Slide 23

Slide 23 text

課題 2: 台数変更の運用コストが高い 負荷をかけずに ● 3台 → 5台(増台) ● 5台 → 3台(減台) は5分以内で完了した 23

Slide 24

Slide 24 text

課題 2: 台数変更の運用コストが高い 負荷をある程度(10000 コネクション、15000 コマンド/s 程度) かけて増台・減台 5 分以内に完了し、15 分程度でコネクションが分散された Redis コマンドは接続エラーなどで0 ~ 数件失敗 24

Slide 25

Slide 25 text

課題 2: 台数変更の運用コストが高い 負荷の高い状況(32000 コネクション、50000 コマンド/s 程度) だと 2 時間経過のち、失敗 →本番では使用しないタイミングで 台数変更を行う運用に 25

Slide 26

Slide 26 text

課題 3: フェイルオーバーできない 公式では数十秒〜数分と記載あり https://cloud.google.com/memorystore/docs/cluster/ha-and-replicas#failover_and_node_rep air_duration ● フェイルオーバーをテストすることはできない 26

Slide 27

Slide 27 text

導入試験結論 1. メンテナンスで最大数時間停止する 2. 台数変更の運用コストが高い 3. フェイルオーバーできない 27

Slide 28

Slide 28 text

導入試験結論 1. △ メンテナンスで最大数時間停止する 2. ○ 台数変更の運用コストが高い 3. △ フェイルオーバーできない 一部導入後でないと実際に確認できないものはありつつも、 課題の解決が望める 28

Slide 29

Slide 29 text

ロールバックの準備 前述の結論の通り、移行が確実に成功するとは言い切れない 本番リリース時に問題が発生した場合に備え、ロールバックできるようにした 29

Slide 30

Slide 30 text

ロールバックの準備 具体的には ● 一時的にキャッシュサーバーが使用不可になっても問題ないように処理を 改善 ● その上で、キャッシュサーバーの使用可否をプロダクト独自の管理ツール から設定できるように実装し、ロールバックなど切り替えの場面で使用で きるようにした 30

Slide 31

Slide 31 text

Memorystore for Redis Cluster Memorystore for Memcached ロールバックの流れ 31 クライアント (PHPサーバー) Memorystore for Redis Cluster にアクセスしている状態

Slide 32

Slide 32 text

DB ロールバックの流れ 32 社内管理ツール 管理ツールから使用可否を設定 canUse = false Memorystore for Redis Cluster Memorystore for Memcached クライアント (PHPサーバー) クライアント (PHPサーバー)

Slide 33

Slide 33 text

DB ロールバックの流れ 33 社内管理ツール キャッシュ使用時にDBから使用可否を判断 canUse = false Memorystore for Redis Cluster Memorystore for Memcached クライアント (PHPサーバー) クライアント (PHPサーバー) APCu

Slide 34

Slide 34 text

DB ロールバックの流れ 34 社内管理ツール canUse = false ならアクセスを止める canUse = false Memorystore for Redis Cluster Memorystore for Memcached クライアント (PHPサーバー) ❌ クライアント (PHPサーバー) APCu

Slide 35

Slide 35 text

DB ロールバックの流れ 35 社内管理ツール 設定をデプロイし、止めたまま向き先を変える canUse = false Memorystore for Redis Cluster Memorystore for Memcached クライアント (PHPサーバー) ❌ クライアント (PHPサーバー) APCu

Slide 36

Slide 36 text

DB ロールバックの流れ 36 社内管理ツール canUse = true にし、切り替え完了 canUse = true Memorystore for Redis Cluster Memorystore for Memcached クライアント (PHPサーバー) クライアント (PHPサーバー) APCu

Slide 37

Slide 37 text

Memorystore for Redis Cluster 負荷検証 37

Slide 38

Slide 38 text

Memorystore for Redis Cluster 負荷検証 導入試験で課題の解決が見込めた プロダクトのユースケースを満たせるか負荷試験で検証 38

Slide 39

Slide 39 text

負荷試験の目標 ● API サーバー が 5000 RPS 以上捌けること ● Memorystore for Redis Cluster が 50000 コマンド/s 以上捌けること ● その他メトリクスに問題が生じないこと ○ CPU 使用率 ○ メモリ使用量 ○ コネクション数 など ● プロダクトの挙動に問題が生じないこと 39

Slide 40

Slide 40 text

負荷試験の目標:その他 プロダクトの挙動に問題が生じないこと ● 負荷試験でのロジックやデータ不整合などのエラーが 0 件 ● API サーバーのレイテンシが許容される範囲内であること 40

Slide 41

Slide 41 text

負荷試験での設定 Redis ライブラリとして phpredis を使用 41

Slide 42

Slide 42 text

API サーバー ● GKE API pod: 1000台 ● Apache MaxRequestWorkers: 25 Redis Cluster ● persistent connection: true ● シャード: 3台(必要あれば増台) ● レプリカ: シャードごとに 1台 その他負荷試験の設定 42 クライアント (PHPサーバー) プライマリ  レプリカ

Slide 43

Slide 43 text

persistent connection 永続的接続 PHPの worker プロセスが終了するまでコネクションを継続する persistent connection = false だと 毎回 PHP と Redis Cluster でコネクションを貼るため、I/O 帯域を圧迫しや すい 43

Slide 44

Slide 44 text

PHP API サーバー(Pod) コネクションのイメージ 44 Apache worker Apache worker Apache worker PHP API サーバー(Pod) … … プライマリ/レプリカ

Slide 45

Slide 45 text

45 コネクション起因のエラー persistent connection = false

Slide 46

Slide 46 text

46 persistent connection = false 新規コネクション 1000/s 程度

Slide 47

Slide 47 text

47 エラーは 0 persistent connection = true

Slide 48

Slide 48 text

48 persistent connection = true ピークで 500/s の時もあるが、一瞬 なので影響なし

Slide 49

Slide 49 text

Redis Cluster 負荷試験 結果 49

Slide 50

Slide 50 text

50 5000 RPS~を捌いている 一部 worker が落ちた

Slide 51

Slide 51 text

51 おおよそ 30000 弱 を推移

Slide 52

Slide 52 text

52 特に reject は無し

Slide 53

Slide 53 text

53 CPUに余裕はある

Slide 54

Slide 54 text

54 70000 コマンド/s 程度

Slide 55

Slide 55 text

負荷試験の目標:その他 プロダクトの挙動に問題が生じないこと ● 負荷試験でのエラーが 0 件 ● API サーバーのレイテンシが許容の範囲内 以上より、問題ないと判断 55

Slide 56

Slide 56 text

負荷試験の目標(再掲) ● API Server が 5000 RPS 以上捌けること ● Memorystore for Redis Cluster が 50000 コマンド/s 以上捌けること ● その他メトリクスに問題が生じないこと ○ CPU 使用率 ○ メモリ使用量 ○ コネクション数 ● プロダクトの挙動に問題が生じないこと 56

Slide 57

Slide 57 text

負荷試験の目標(再掲) ● ○ API Server が 5000 RPS 以上捌けること ● ○ Memorystore for Redis Cluster が 50000 コマンド/s 以上捌けること ● △ その他メトリクスに問題が生じないこと ○ ○ CPU 使用率 ○ ○ メモリ使用量 ○ △ コネクション数 ● ○ プロダクトの挙動に問題が生じないこと 57

Slide 58

Slide 58 text

コネクション数の問題 persistent connection によって、コネクション数が上限を超える ● 2024年 3月時点では、10000 がコネクション上限だった 58

Slide 59

Slide 59 text

コネクション数の問題 persistent connection によって、コネクション数が上限を超える ● 2024年 3月時点では、10000 がコネクション上限だった ● 本番想定として、 500 pod ✖ 25 worker + α ~ 最大 15000 コネクショ ン程度は見込まれたため、削減する必要があった 59

Slide 60

Slide 60 text

コネクションのイメージ(再掲) コネクション数 🟰 Pod 台数 ✖ Pod 1台あたりのworker数 でおおよそ見積もることができる 60 PHP API サーバー(Pod) Apache worker Apache worker Apache worker PHP API サーバー(Pod) … … プライマリ/レプリカ

Slide 61

Slide 61 text

コネクション数の問題:対策案 ● HPA(Horizontal Pod Autoscaler)のCPU utilization target を上げる ● persistent connection = false にする ● Pod 1台あたりの Apache Worker 数を減らす 61

Slide 62

Slide 62 text

コネクション数の問題:対策案 1 HPAのCPU utilization target を上げる コネクション数 = Pod 台数 × Pod 1台あたりのworker数 Pod 台数 を減らせば良い 62

Slide 63

Slide 63 text

コネクション数の問題:対策案 1 HPAのCPU utilization target を上げる 具体例:4000 RPS, podあたりworker数が 25 の場合 63 CPU target Pod 1台のRPS Pod 台数 コネクション数 before 25 % 5 800 20000 after 50 % 10 400 10000

Slide 64

Slide 64 text

コネクション数の問題:対策案 1 HPAのCPU utilization target を上げる CPU target を上げると その分動作が不安定になる可能性があるため 様子を見ながら上げるしかない 64

Slide 65

Slide 65 text

コネクション数の問題:対策案 2 persistent connection をやめる 都度繋ぎ直しになるので、コネクション数は劇的に減る ただ、前述の通りネットワーク帯域を圧迫するため、推奨できない 65

Slide 66

Slide 66 text

コネクション数の問題:対策案 3 Pod 1台あたりの Apache Worker 数を減らす コネクション数 = Pod 台数 × Pod 1台あたりの worker 数 Pod 1台あたりの worker 数を減らせば良い 66

Slide 67

Slide 67 text

コネクション数の問題:対策案(再掲) ● HPA の CPU utilization target を上げる ● persistent connection をやめる ● Pod 1台あたりの Apache Worker 数を減らす 67

Slide 68

Slide 68 text

コネクション数の問題:対策案(再掲) ● △ HPA の CPU utilization target を上げる ● △ persistent connection をやめる ● ○ Pod 1台あたりの Apache Worker 数を減らす 68

Slide 69

Slide 69 text

コネクション数の問題:対策案(再掲) ● △ HPA の CPU utilization target を上げる ● △ persistent connection をやめる ● ○ Pod 1台あたりの Apache Worker 数を減らす 69 ここに朗報が 飛び込む

Slide 70

Slide 70 text

MaxClients の上限解放 2024年 4月 Max Clients(コネクションの最大値) 10000 → 最大 64000 まで引き上げられた 負荷試験では 30000 コネクション で目標値に到達していたため、十分と判断した 70 https://cloud.google.com/memorystore/docs/cluster/quotas

Slide 71

Slide 71 text

負荷試験の目標(再掲) ● ○ API Server が 5000 RPS 以上捌けること ● ○ その他メトリクスに問題が生じないこと ○ ○ CPU 使用率 ○ ○ メモリ使用量 ○ ○ コネクション数 ● ○ プロダクトの挙動に問題が生じないこと 71

Slide 72

Slide 72 text

負荷試験の目標(再掲) ● ○ API Server が 5000 RPS 以上捌けること ● ○ その他メトリクスに問題が生じないこと ○ ○ CPU 使用率 ○ ○ メモリ使用量 ○ ○ コネクション数 ● ○ プロダクトの挙動に問題が生じないこと 72 負荷試験の目標を 達成できた!

Slide 73

Slide 73 text

Memorystore for Redis Cluster の本番運用について 73

Slide 74

Slide 74 text

リリース時 redis-highmem-medium 3 シャード シャードごとに 1 レプリカ カナリアリリースで少しずつリリースした 74 クライアント (PHPサーバー) プライマリ  レプリカ

Slide 75

Slide 75 text

75 各項目特に問題なし

Slide 76

Slide 76 text

76 メモリ使用率が異常に高い

Slide 77

Slide 77 text

メモリ使用量の増加 負荷試験では予期できなかった phpredis がデフォルトで圧縮が効いていなかったことが一番の原因 ● memcached ライブラリではデフォルトで2KB以上のデータは圧縮されている https://www.php.net/manual/ja/memcached.configuration.php#ini.memcached.compression-threshold 77

Slide 78

Slide 78 text

メモリ使用量の増加への対処 1. シャード数の引き上げ (3台 → 6台) 2. 大きすぎるキャッシュデータを削減 3. キャッシュデータ保存時に圧縮処理を入れる 78

Slide 79

Slide 79 text

メモリ使用量の増加への対処 大きすぎるキャッシュデータの削減 redis-cli -h --memkeys -i 1 redis-cli の機能を用いて調査 ※ -i オプションで一定間隔で sleep が走るため、付けることを推奨 79

Slide 80

Slide 80 text

メモリ使用量の増加への対処 大きすぎるキャッシュデータの削減 以下のように結果が表示される [03.22%] Biggest string found so far 'user_cache' with 10000 bytes 上記の調査結果を元に、削減 80

Slide 81

Slide 81 text

メモリ使用量の増加への対処 キャッシュデータ保存時に圧縮処理を入れる 1KB 以上のキャッシュアイテムを gzencode で圧縮 81 if (len($setValue) > $this->config->threshold()) { $setValue = $this->gzencode($setValue, $level); } $result = $this->redisCluster->set($key, $setValue, $expiration);

Slide 82

Slide 82 text

メモリ使用量の増加への対処 結果として、3 シャードでも耐えられる程度まで削減できた 82

Slide 83

Slide 83 text

まとめ 83

Slide 84

Slide 84 text

まとめ 新サービス Memorystore for Redis Cluster のリリースに成功した 導入試験・負荷試験・ロールバック検証によって安心してリリースできた メモリ使用量などの問題がありつつも、台数変更などのオペレーションが楽に 行えるため、迅速に対応できた 総合的に可用性や保守性が増し、運用コストが削減できた 84

Slide 85

Slide 85 text

今後の展望 85

Slide 86

Slide 86 text

今後の展望: 短期的展望 リトライ機構の導入 Redis Cluster ノードのポートが変わった際、persistent connection で古い ノードにアクセスし続けてしまうという問題がある ➡ リトライ時にコネクションをつなぎ直すことで回避する 86

Slide 87

Slide 87 text

今後の展望: 中期的展望 台数増減の自動化 現状 シャード数を変更する際に、 無停止だと数秒 〜 数分 接続エラーが出てしまう リトライの導入などでエラーがほぼ出ないようになれば、可能性はある プロダクトでは最小台数の 3台 で運用できているため、 現状は必要としていない 87

Slide 88

Slide 88 text

今後の展望: 長期的展望 Valkey の動向を注視 Redis の fork 先である Valkey の マネージドサービス Memorystore for Valkey が 2024 年 8 月末 プレビューでリリースされた Redis/Redis Cluster はライセンスなどの懸念があるため、Valkey の動向も注 視していく https://redis.io/blog/redis-adopts-dual-source-available-licensing/ 88

Slide 89

Slide 89 text

89

Slide 90

Slide 90 text

ご清聴ありがとうございました 90

Slide 91

Slide 91 text

No content