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

ZOZOTOWNの検索APIにキャッシュを導入、実装時の工夫や効果について

Satto
March 22, 2023

 ZOZOTOWNの検索APIにキャッシュを導入、実装時の工夫や効果について

Satto

March 22, 2023
Tweet

Other Decks in Technology

Transcript

  1. © ZOZO, Inc. 株式会社ZOZO 技術本部 検索基盤部 検索基盤ブロック 佐藤 由弥 •

    2020年4月新卒として入社(今年4月で4年目) • 入社当時はJava未経験 ◦ 検索マイクロサービスの開発や運用業務を通じて習得 • 最近の主な業務は検索ページのフロントエンドリプレイス ◦ レガシーコードをJavaに置き換え • 扱う言語やサービス:Java・Python・VBS・Elasticsearch・BigQuery • 趣味:ゲーム、最近はホグワーツに入学 2
  2. © ZOZO, Inc. Agenda 1. ZOZOTOWNの検索について 2. キャッシュの導入 3. 実装時の工夫

    4. まとめ 5. おまけ(フロントエンドリプレイスの話) 3
  3. © ZOZO, Inc. Agenda 1. ZOZOTOWNの検索について 2. キャッシュの導入 3. 実装時の工夫

    4. まとめ 5. おまけ(フロントエンドリプレイスの話) 4
  4. © ZOZO, Inc. 検索システムとして大切な要素 10 今日話すこと • 速度 ◦ 検索APIにキャッシュ導入

    • 精度 • 可用性 • 再現性などなど 本資料ではここを深掘る
  5. © ZOZO, Inc. Agenda 1. ZOZOTOWNの検索について 2. キャッシュの導入 3. 実装時の工夫

    4. まとめ 5. おまけ(フロントエンドリプレイスの話) 11
  6. © ZOZO, Inc. 19 キャッシュ導入による効果(工夫を含めた最終的な効果) • 速度改善に効果あり ◦ 最終的に殆どのエンドポイントで 50ms~100msほどレイテンシが低下

    ◦ 特に効果があったエンドポイントはp99で94%改善 • 安定した速度で検索結果の提供が可能に ◦ レイテンシの振れ幅が少なくなり安定した 例)世代別ランキングAPIのレイテンシの様子 ※ この後紹介する様々な工夫を取り入れた後の 最終的なレイテンシの低下を表しています 90%以上改善
  7. © ZOZO, Inc. Agenda 1. ZOZOTOWNの検索について 2. キャッシュの導入 3. 実装時の工夫

    4. まとめ 5. おまけ(フロントエンドリプレイスの話) 20
  8. © ZOZO, Inc. 21 実装時の工夫 • エンドポイントごとにTTLを最適化 ◦ エンドポイントごとにTTLを延長してレイテンシを計測 ◦

    最適な値になるまで上記を繰り返す • キャッシュキーの最適化 ◦ セールの開始時にキャッシュが切り替わるように キャッシュキーにタイムセクションを追加 ◦ Cache Stampedeの対策 • キャッシュのGZIP圧縮 ◦ 検索結果をそのままキャッシュすると ネットワークI/Oやストレージが逼迫 ここを深掘る リンク:https://techblog.zozo.com/entry/implement-cache-in-search-microservice 割愛:詳細はテックブログ参照ください
  9. © ZOZO, Inc. 22 キャッシュのGZIP圧縮の概要 • どんな課題があった? ◦ 登録するキャッシュは、商品の様々な情報を含むためデータサイズが大きい ◦

    RedisのネットワークI/Oやストレージの使用量が増加 • なにが嬉しい? ◦ Redisに保存するデータを圧縮することで、 ネットワークI/Oやストレージの使用量を減らし、検索APIの高速化を図る • この後の話 ◦ 実際のJavaのコードを交えて、どのようにGZIP圧縮したか詳細を説明
  10. © ZOZO, Inc. 23 Spring bootからRedisにキャッシュを保存するまでの流れ Redisはインメモリデータストアのため、オブジェクトをデータ形式に変換して保存が必要 扱うRedisクライアント:spring-boot-starter-data-redis https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data- redis

    • シリアライズ/デシアライズは JdkSerializationRedisSerializerクラスで行われる • オブジェクトのシリアライズを可能にするには 追加する Redisクライアント Redis シリアライズ 検索結果オブジェクト バイト配列 キャッシュ保存 デシリアライズ キャッシュ読み取り バイト配列 検索結果オブジェクト 同 じ 検索API Icon made by flaticon from https://www.flaticon.com/
  11. © ZOZO, Inc. 24 キャッシュのGZIP圧縮 シリアライズ gzip 圧縮 約60%~80%圧縮 GZIP圧縮の流れ

    • serialize() ◦ オブジェクトをシリアライズするメソッド ◦ isGzipEnabledでGZIP実行有無を制御 • compress() ◦ バイト配列をGZIP圧縮するメソッド ◦ GZIPOutputStreamにByteArrayOutputStreamを 渡すことで出力先はバイト配列になる 検索結果オブジェクト バイト配列 圧縮されたバイト配列 Icon made by flaticon from https://www.flaticon.com/
  12. © ZOZO, Inc. 25 キャッシュのGZIP圧縮 シリアライズ gzip 圧縮 約60%~80%圧縮 GZIP圧縮の流れ

    • serialize() ◦ オブジェクトをシリアライズするメソッド ◦ isGzipEnabledでGZIP実行有無を制御 • compress() ◦ バイト配列をGZIP圧縮するメソッド ◦ GZIPOutputStreamにByteArrayOutputStreamを 渡すことで出力先はバイト配列になる 検索結果オブジェクト バイト配列 圧縮されたバイト配列 Icon made by flaticon from https://www.flaticon.com/
  13. © ZOZO, Inc. 26 キャッシュのGZIP圧縮 シリアライズ gzip 圧縮 約60%~80%圧縮 GZIP圧縮の流れ

    • serialize() ◦ オブジェクトをシリアライズするメソッド ◦ isGzipEnabledでGZIP実行有無を制御 • compress() ◦ バイト配列をGZIP圧縮するメソッド ◦ GZIPOutputStreamにByteArrayOutputStreamを 渡すことで出力先はバイト配列になる 検索結果オブジェクト バイト配列 圧縮されたバイト配列 Icon made by flaticon from https://www.flaticon.com/
  14. © ZOZO, Inc. 27 キャッシュのGZIP圧縮 GZIP解凍の流れ gzip 解凍 デシリアライズ •

    deserialize() ◦ Redisから取得した圧縮データを復元するためのメソッド ◦ バイト配列からオブジェクトに変換 • decompress() ◦ 圧縮されたバイト配列を解凍するメソッド ◦ データの解凍と解凍されたデータをバイト配列に書き込む ◦ 一連の流れは煩雑化しやすいので IOUtilsクラスのcopyメソッドを使い簡略化 検索結果オブジェクト バイト配列 圧縮されたバイト配列 Icon made by flaticon from https://www.flaticon.com/
  15. © ZOZO, Inc. 28 キャッシュのGZIP圧縮 GZIP解凍の流れ gzip 解凍 デシリアライズ •

    deserialize() ◦ Redisから取得した圧縮データを復元するためのメソッド ◦ バイト配列からオブジェクトに変換 • decompress() ◦ 圧縮されたバイト配列を解凍するメソッド ◦ データの解凍と解凍されたデータをバイト配列に書き込む ◦ 一連の流れは煩雑化しやすいので IOUtilsクラスのcopyメソッドを使い簡略化 検索結果オブジェクト バイト配列 圧縮されたバイト配列 Icon made by flaticon from https://www.flaticon.com/
  16. © ZOZO, Inc. 29 キャッシュのGZIP圧縮 GZIP解凍の流れ gzip 解凍 デシリアライズ •

    deserialize() ◦ Redisから取得した圧縮データを復元するためのメソッド ◦ バイト配列からオブジェクトに変換 • decompress() ◦ 圧縮されたバイト配列を解凍するメソッド ◦ データの解凍と解凍されたデータをバイト配列に書き込む ◦ 一連の流れは煩雑化しやすいので IOUtilsクラスのcopyメソッドを使い簡略化 検索結果オブジェクト バイト配列 圧縮されたバイト配列 Icon made by flaticon from https://www.flaticon.com/
  17. © ZOZO, Inc. 30 キャッシュのGZIP圧縮 • spring-boot-starter-data-redis ◦ RedisTemplateが用意されている ◦

    Redisとのデータ操作が簡略化 • RedisTemplate ◦ デフォルトシリアライザーの JdkSerializationRedisSerializerをラップ したクラスに差し替える Redisを扱うための依存関係 RedisTemplateにてラップしたクラスに差し替える 元のRedisTemplate ※ テンプレートが異なる場合、適宜差し替え場所を変える
  18. © ZOZO, Inc. 31 キャッシュ圧縮による効果 • ElastiCacheメモリ使用率が約1/3に減少 • ネットワーク通信量が約1/7に減少 懸念していたCPU使用率は変化なし

    ◦ 約200KBの文字列で構成されたレスポンス情報の圧縮なので サイズが小さく負荷がかからなかった ◦ リソースが十分に与えられたPod上で実行されているため 影響が少なかった キャッシュ圧縮によって、以下の効果が得られた ElastiCacheメモリ使用率 ネットワーク通信量 CPU使用率 約1/3減少 約1/7減少
  19. © ZOZO, Inc. Agenda 1. ZOZOTOWNの検索について 2. キャッシュの導入 3. 実装時の工夫

    4. まとめ 5. おまけ(フロントエンドリプレイスの話) 32
  20. © ZOZO, Inc. 33 まとめ/学んだこと まとめ • 速度改善の一環で検索APIにキャッシュを導入 • 殆どのエンドポイントで50~100msほどレイテンシが低下

    • GZIPによるキャッシュ圧縮/解凍の実装方法を紹介 • ストレージやネットワーク使用量が低下 学んだこと • Java完全理解 ◦ ほぼ未経験でしたが、実装をある程度任せてもらえたので理解が深まった • レイテンシをより意識するように • 闇雲な改善は良くない ◦ 計測→仮説→実装の流れが大切
  21. © ZOZO, Inc. Agenda 1. ZOZOTOWNの検索について 2. キャッシュの導入 3. 実装時の工夫

    4. まとめ 5. おまけ(フロントエンドリプレイスの話) 34
  22. © ZOZO, Inc. 35 おまけ(フロントエンドリプレイスの話) これまでのZOZOTOWNの課題 • Webサーバの技術スタックがレガシー ◦ Classic

    ASP・jQuery・ES5 ◦ 他言語でよくある便利機能は自作が必要で開発速度が鈍化 • ビューロジックが独自テンプレートエンジンで実現 ◦ コードが独特で癖があり実装コストが高い ◦ ビューとAPI側にビジネスロジックが分散 リプレイス後のZOZOTOWN ※ 説明のため簡略化しています