こんにちは。技術本部SRE部ZOZO-SREブロックに所属している杉山です。SRE部のテックリードとして、オンプレ/クラウドのインフラを担当しています。
ZOZOTOWNでは、既存システムのリプレイスプロジェクトを進めています。各サービスのマイクロサービス化は進んでいますが、バックエンドでは「WindowsServer + IIS」で稼働しているシステムがまだ多く残っています。そのリプレイスプロジェクトを進めるうえで重要なポイントとなる、セッションストアのリプレイス「セッションオフロードPhase 2」が完了しました。本記事では、リプレイスしていくうえでの工夫や課題への対応を紹介します。
セッションオフロードPhase 2について
プロジェクト概要
セッションオフロードプロジェクトは、CacheStoreリプレイスのPhase 1と、SessionStoreリプレイスのPhase 2で構成されています。
- Phase 1:CacheStoreのリプレイス
- Phase 2:SessionStoreのリプレイス
Phase 1:CacheStoreのリプレイス
Phase 1:CacheStoreのリプレイスについては、こちらの記事をご覧ください。
Phase 2:SessionStoreのリプレイス
セッションオフロードPhase 2は、WebサーバーであるIISのサーバー内セッションの機能を無効にし、外部SessionStoreにオフロードさせるリプレイスプロジェクトです。ZOZOTOWNが抱えていた、スケーリング運用やフロントエンドのリプレイスの課題を解決することを目的としています。
ZOZOTOWNが抱える、セッション管理の課題
以下のような課題がありました。
- スティッキーセッションのため、スケーリング運用に支障がある
- スティッキーセッションのため、サーバー負荷が偏る
- オフロードしないとフロントエンドリプレイスができない
それぞれの課題について、具体的に説明します。
1:スティッキーセッションのため、スケーリング運用に支障がある
ユーザーセッションにIISの機能であるセッションを利用しており、ユーザーセッションがWebサーバーに紐づきます。LoadBlancerでは、Cookie Persistenceと呼ばれる機能で振り分け先の固定が必要です。そのため、Webサーバーのスケーリング運用のうち「スケールイン」に注意が必要です。ユーザーのセッションが期限切れになるのを待ったり、夜中の時間帯を狙ってスケールインする必要があるなど、運用に支障がありました。
2:スティッキーセッションのため、サーバー負荷が偏る
ユーザーセッションごとにWebサーバーを固定する必要があるので、リクエストのロードバランシングで偏りが発生します。これにより、一部のサーバーは負荷が高くなってしまうこともありました。
3:オフロードしないとフロントエンドリプレイスができない
ユーザーセッションがWebサーバーに対してスティッキーなため、フロントエンドを段階的にモダンな技術でリプレイスするという手法が取れません。例えば、まずはトップページをコンテナ化しEKSで運用したいが、セッション情報が特定のWebサーバーに保存されているため、セッション情報を維持しにくいです。
Webサーバー内のセッションを、外部のデータストアにオフロードすることで、これらの課題を解決しユーザーリクエストがどのWebサーバーに割り振られてもセッションを維持できるようにする事が目的です。
リプレイス前後の構成
リプレイス前(左)は、WebサーバーのIIS内のセッションを、独自ライブラリを介して利用していました。リプレイス後(右)は、外部SessionStoreにセッションデータをオフロードし、独自ライブラリに実装したクライアントを用いて利用します。
また、リプレイス時のアプリケーションの改修コストを抑えるため、独自ライブラリ内でRedisクライアントをラップして実装しました。そして、アプリケーションコードの改修を最小限に抑えて、Redisへの接続に切り替えることができるようにしました。
採用技術について
Amazon Elasticache Redis
世間で広く使われている技術のRedisを採用しました。クラウドサービスとしては「Amazon Elasticache Redis」(以下、Redisという)の「Clusterモード有効」を採用しました。
Redisは、負荷特性に応じてClusterモードの有効/無効を選択できます。ホットキーの多い負荷特性の場合は、Clusterモード無効にして複数のリードレプリカとリーダーエンドポイント使う方が効果的な場合もあります。
セッションをオフロードすることでRedisは全Webサーバーから多くのリクエストを受けることになりますが、セッションデータはユーザー毎のデータなのでホットキーはありません。このことから、Clusterモード有効のRedis(以下、RedisClusterという)を利用してシャードのスケールアウトで負荷分散できるようにしました。
例えば、平常時は30シャード、セール時は40シャード、ZOZOTOWN最大の負荷となる冬セールは60シャード。というように、必要に応じてシャード数を増やし負荷分散させています。
RedisClusterのシャードとは
- シャード:1~6個のRedisノードで構成される集合の単位。
- ノード:Reidsノード単体のことで、「Primary / Replica」の種類がある。
本記事では、「シャード」をスケーリングの単位。「ノード」をRedisノードとして表現します。
冗長構成について
RedisClusterの各シャードは、プライマリノードの他に別AZのレプリカを持たせることができ、ノード障害時に「プライマリノードのフェイルオーバー」で自動復旧させることが可能です。検証では、プライマリノードのフェイルオーバーでの復旧は障害の内容にもよりますが、1分弱程度から数分でフェイルオーバーが実現できました。しかし、ユーザーセッションを取り扱うとても大事なシステムとなるため、弊社では30秒程度の復旧を目標としていました。
この要件を満たすために、シングルAZのRedisCluster(レプリカ無し)において、プライマリクラスター/セカンダリクラスターでAZ違いの2クラスター運用にしました。独自ヘルスチェックシステムをEKSで動かし、ノード障害発生時には速やかにクラスターフェイルオーバーを行う事で、約15秒~30秒程度でのフェイルオーバーを実現しました。
2クラスター運用としたことにより、メンテナンスの際にセカンダリを活用することで、ローリングでメンテナンスを実施可能になったことも1つのメリットとなっています。
続きはこちら