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

MAUが1年で292%に成長した「aumoのおでかけ比較サイト」における取り組み

 MAUが1年で292%に成長した「aumoのおでかけ比較サイト」における取り組み

GREE Tech Conference 2023で発表された資料です。
https://techcon.gree.jp/2023/session/TrackA-2

gree_tech
PRO

October 13, 2023
Tweet

More Decks by gree_tech

Other Decks in Technology

Transcript

  1. MAUが1年で292%に成長した
    「aumoのおでかけ比較サイト」
    における取り組み
    アウモ株式会社
    エンジニア
    関谷恒甫
    栗本拓弥

    View Slide

  2. 目次
    ● 発表者紹介
    ● aumoについて
    ● フロントエンドをRailsのテンプレートエンジンからNuxt.jsに
    移行した話
    ● フロントエンドにNGINXのリバースプロキシを設置してキャッ
    シュを導入した話
    ● まとめ
    2

    View Slide

  3. 自己紹介
    3
    ● 名前:関谷恒甫
    ● 所属:アウモ株式会社
    ● 担当:メディアチームにおける開発全般
    ● 経歴:
    ○ 2020年4月:グリーに新卒入社
    ○ 2020年4月:アウモに配属
    ○ 2020年6月:WFSに配属
    ○ 2021年12月:アウモに配属

    View Slide

  4. 自己紹介
    ● 名前:栗本拓弥
    ● 所属:アウモ株式会社
    ● 担当:メディアチームにおける開発全般
    ● 経歴:
    ○ 2022年4月:グリーに新卒入社
    ○ 2022年4月:アウモに配属
    4

    View Slide

  5. aumoについて

    View Slide

  6. サービスの全体像

    View Slide

  7. メディア事業

    View Slide

  8. メディア事業の提供サービス

    View Slide

  9. 新規事業の取り組み

    View Slide

  10. SaaS事業

    View Slide

  11. SaaS事業の提供サービス

    View Slide

  12. SaaS 事業の機能紹介 

    View Slide

  13. Fintech

    View Slide

  14. Fintech事業の概要

    View Slide

  15. マーケティングソリューション

    View Slide

  16. マーケティングソリューションの概要

    View Slide

  17. おでかけ比較サイトのフロントエンドを
    Railsのテンプレートエンジンから
    Nuxt.jsに移行した話
    17

    View Slide

  18. 何をやったのか
    ● aumo.jpの一覧ページ(例 aumo.jp/areas/241)のフロントエンドを、
    Railsのテンプレートエンジン(slim)からNuxt.jsに移行した。
    18

    View Slide

  19. 19
    gourmet.aumo.jp
    aumo.jp
    なぜやるのか
    ● aumoではaumo.jpドメインと3つのサブドメイン(gourmet.aumo.jp,
    leisure.aumo.jp, travel.aumo.jp)で一覧
    ページを運営しています。

    View Slide

  20. なぜやるのか
    (歴史的経緯のため)ドメインによって
    フロントエンドの実装が異なる
    ● サブドメイン
    ○ Nuxt.js
    ● aumo.jp
    ○ Railsテンプレートエンジン
    20

    View Slide

  21. なぜやるのか
    ● 一覧ページを開発する際は基本的にドメイン4つ全てが開発の対象
    ○ サブドメインではNuxt.jsのコンポーネントを使い回すことができる
    が、aumo.jpドメインではそれらを使えないので、テンプレートエン
    ジンのコードも書く必要がある。。。
    21

    View Slide

  22. なぜやるのか
    ● 一覧ページを開発する際は基本的にドメイン4つ全てが開発の対象
    ○ サブドメインではNuxt.jsのコンポーネントを使い回すことができる
    が、aumo.jpドメインではそれらを使えないので、テンプレートエン
    ジンのコードも書く必要がある。。。
    22
    2度手間!!!

    View Slide

  23. 移行の流れ
    ※アウモでは業務時間の1~2割程度を、各自がやりたい開発改善等の
     時間に当てて良いということになってるので、その仕組みを今回は
     利用しました。
    23
    1. アプリケーションコード変更
    2. インフラ変更
    3. リリース

    View Slide

  24. 移行の流れ
    1. アプリケーションコード変更
    2. インフラ変更
    3. リリース
    24

    View Slide

  25. アプリケーションコードの変更
    ● テンプレートエンジンのコードを、Nuxtに書き換える。
    ● 基本的には既存のNuxtのコンポーネントを使い回す。
    ● aumo.jpドメインのみに存在するUI等がある場合に、コンポーネントを新規
    作成or修正。
    ● デザインが同じでもaumo.jpドメインとサブドメインで仕様が違う可能性があ
    るので、コードを一つ一つ確認し差分があった場合は、PMと適時仕様をすり
    合わせる。
    25

    View Slide

  26. 移行の流れ
    1. アプリケーションコード変更
    2. インフラ変更
    3. リリース
    26

    View Slide

  27. インフラの変更
    ● aumo.jpドメインには一覧ページ(https://aumo.jp/areas/241)だけで
    なく、記事ページ(https://aumo.jp/articles/145272)も存在する。
    ● 一覧ページへのアクセスのみをNuxtサーバに転送するように変更する必要
    がある。
    ○ ALBのリスナールールを編集して、特定のパスパターン
    (例 /areas/*)の時のみリクエストを転送するように設定。
    27

    View Slide

  28. インフラ構成の変更
    28
    BEFORE

    View Slide

  29. インフラ構成の変更
    29
    BEFORE AFTER

    View Slide

  30. 移行の流れ
    1. アプリケーションコード変更
    2. インフラ変更
    3. リリース
    30

    View Slide

  31. リリース
    ここまでは順調だったが。。。
    31

    View Slide

  32. リリース1回目
    レスポンス速度が悪化する
    32

    View Slide

  33. リリース1回目
    レスポンス速度が悪化する
    原因
    ● コード変更に伴い、リリースのタイミングでAPI側
    で既存のキャッシュが使えなくなり、
    Elasticsearchへのアクセスが増えて負荷が上
    がった。
    対策
    ● 元々Elasticsearchの負荷が高めだったので、
    この機会にスケールアップを実施。
    33

    View Slide

  34. リリース2回目
    相変わらずレスポンス速度が遅い状態が続く
    34

    View Slide

  35. リリース2回目
    相変わらずレスポンス速度が遅い状態が続く
    原因
    ● aumo.jpからリクエストが転送される分、Nuxtサーバへのリクエストが
    増えたから?
    対策
    ● サーバー台数を増やしてみる。
    35

    View Slide

  36. リリース3回目
    相変わらずレスポンス速度が遅い状態が続く
    36

    View Slide

  37. リリース3回目
    相変わらずレスポンス速度が遅い状態が続く
    原因
    ● パフォーマンスチューニングをほとんど行っておらず、API側でN+1のク
    エリが複数発生していたから?
    対策
    ● N+1のクエリをひたすら潰す。
    37

    View Slide

  38. リリース4回目
    相変わらずレスポンス速度が遅い状態が続く
    38

    View Slide

  39. リリース4回目
    相変わらずレスポンス速度が遅い状態が続く
    原因
    ● 不明。何も思いつかず。
    対策
    ● レスポンスが遅い原因が不明のままなので、問題を切り分けてみる。
    ● aumo.jpドメインのレスポンスのみが遅いのかサブドメインのレスポンス
    も遅いのかを見分けるために、aumo.jpとサブドメインで使うコンテナを
    分ける。
    39

    View Slide

  40. リリース5回目
    aumo.jpドメインへのリクエストのみが遅く、
    サブドメインへのリクエストは正常なことが判明
    40

    View Slide

  41. アクセスログの調査
    アクセスログをよく見てみる
    ● 最初の数分は問題なさそうだが、チラホラ遅い
    レスポンスが混ざっている。
    ● その後は全部のレスポンスが遅くなる。
    ● 遅いレスポンスをよく見ると、エリア番号が大き
    い傾向があることに気づく。
      
      
    41

    View Slide

  42. アクセスログの調査
    アクセスログをよく見てみる
    ● 最初の数分は問題なさそうだが、チラホラ遅い
    レスポンスが混ざっている。
    ● その後は全部のレスポンスが遅くなる。
    ● 遅いレスポンスをよく見ると、エリア番号が大き
    い傾向があることに気づく。
      
      
    42

    View Slide

  43. アクセスログの調査
    43
    アクセスログをよく見てみる
    ● 最初の数分は問題なさそうだが、チラホラ遅い
    レスポンスが混ざっている。
    ● その後は全部のレスポンスが遅くなる。
    ● 遅いレスポンスをよく見ると、エリア番号が大き
    い傾向があることに気づく。
      
       
    エリア番号が関係してそうなコード  を
    探す。

    View Slide

  44. 問題のコード
    44
    computed: {
    targetAreaRegion () {
    return this.allRegions.find((region) =>
    region.prefectures.some((pref) =>
    pref.areas.some((area) =>
    Number(area.id) === Number(this.targetArea)
    )
    )
    )
    }
    }
    allRegions = [{
    id: 1,
    name: '北海道・東北',
    prefectures: [{
    id: 1,
    name: '北海道',
    areas: [{
    id: 1,
    name: '札幌市'
    }, ...],
    }, ...]
    }, ...]
    ・allRegionsはregion->prefecture->areaという階層構造になっていて、階層構造を上か
    らiterateしていき、targetArea(例 札幌市)が属するregion(例 北海道・東北地方)を探す。
    ・areaは全部で1600個程あるので、targetAreaが配列の後ろの方にある場合は探すのに
    時間がかかる。
    ・computedプロパティでキャッシュしてるので大丈夫だと思っていたが。。。

    View Slide

  45. Nuxt.jsをSSRで利用する時の落とし穴
    45
    原因
    ● Nuxt.jsをSSRで利用する場合は、computedプロパティが
    キャッシュされない。
    https://github.com/nuxt/nuxt/issues/2447
    対策
    ● 計算が重い処理はcomputedプロパティではなく、storeに保存すること
    で、レンダリング中に処理が走るのを1回だけにする。

    View Slide

  46. リリース成功!!!
    46
    リリース6回目

    View Slide

  47. 学んだ点
    ● ログは超大事。生のアクセスログ、ALBのメトリクス、ECSのメトリクスなど色
    んなログを見るべき。
    ● テストが充実してないと、リファクタリングのハードルが上がる。
    ● リファクタリングは辛いので、設計の段階でなるべく先まで見通して、リファクタ
    リングをそもそもしなくて済むようにできるのがベスト。
    より詳細が知りたい方は、テックブログを見てください!
    https://techblog.aumo.co.jp/articles/2233
    47

    View Slide

  48. おでかけ比較サイトのフロントエンドにNGINXのリ
    バースプロキシを設置して
    キャッシュを導入した話
    48

    View Slide

  49. 何をやったのか
    ● 一覧ページを表示しているNuxtサーバの前段に
    NGINXリバースプロキシを置いて、ページキャッシュを導入した。
    49
    既存の構成
    リクエストが来るたび
    大量のAPIを叩いていた
    リバプロ導入した構成
    1回目のリクエストは
    従来通り
    2回目以降のリクエストは
    NGINXがキャッシュを返す

    View Slide

  50. なぜやるのか
    ● SEO対策として一覧ページのコンテンツをリッチにして、
    MAUが大きく成長した! が、、
    50
    追加したコンテンツ例

    View Slide

  51. なぜやるのか
    ● SEO対策として一覧ページのコンテンツをリッチにして、
    MAUが大きく成長した! が、、
    51
    追加したコンテンツ例
    MAUの推移

    View Slide

  52. なぜやるのか
    ● しかし、ページがリッチになるにつれてレスポンス速度が遅くなってしまって
    いた
    52

    View Slide

  53. なぜやるのか
    レスポンス速度の悪化によりCoreWebVitalの指標が低下してしまった
    ● CoreWebVitalとは
    ○ Googleが定めるWebサイトのUXを測る重要な指標のこと。
    ○ PageSpeed Insightsというサイトで誰でも計測できる
    ● CoreWebVitalの主な指標
    ○ Time to First Byte (TTFB):
    ■ レスポンスの最初のByteが返るまでの時間
    ○ First Contentful Paint (FCP):
    ■ 視覚コンテンツの初期表示時間
    ○ Largest Contentful Paint (LCP):
    ■ 最大コンテンツの表示時間
    53

    View Slide

  54. なぜやるのか
    54
    ● CoreWebVitalが不合格だらけなので、これを改善することで、
    MAUがさらに成長するかもしれない

    View Slide

  55. なぜやるのか
    55
    ● CoreWebVitalが不合格だらけなので、これを改善することで、
    MAUがさらに成長するかもしれない
    ちくしょう。
    速度改善だ!

    View Slide

  56. なぜやるのか
    ● 今後コンテンツがさらにリッチになっても、レスポンス速度の悪化を招かな
    いようにしたい。
    ● Nuxtのレスポンスを丸々キャッシュする「ページキャッシュ」を
    導入すると、キャッシュ済みページへのアクセスは一瞬で返せる。
    56

    View Slide

  57. なぜやるのか
    ● 今後コンテンツがさらにリッチになっても、レスポンス速度の悪化を招かな
    いようにしたい。
    ● Nuxtのレスポンスを丸々キャッシュする「ページキャッシュ」を
    導入すると、キャッシュ済みページへのアクセスは一瞬で返せる。
    57
    ちくしょう。
    ページキャッシュだ!

    View Slide

  58. ページキャッシュ導入の流れ
    1. NGINXリバースプロキシ設置
    2. NGINXでページキャッシュ導入
    3. リリース
    58

    View Slide

  59. ページキャッシュ導入の流れ
    1. NGINXリバースプロキシ設置
    2. NGINXでページキャッシュ導入
    3. リリース
    59

    View Slide

  60. NGINXリバースプロキシ設置 - インフラ構成 -
    BEFORE

    View Slide

  61. NGINXリバースプロキシ設置 - インフラ構成 -
    61
    BEFORE AFTER

    View Slide

  62. ページキャッシュ導入の流れ
    1. NGINXリバースプロキシ設置
    2. NGINXでページキャッシュ導入
    3. リリース
    62

    View Slide

  63. ページキャッシュ導入の流れ
    1. NGINXリバースプロキシ設置
    2. NGINXでページキャッシュ導入
    1. 数千件の特定URLをキャッシュする
    2. SPとPCでキャッシュを分ける
    3. リリース
    63

    View Slide

  64. ページキャッシュ導入の流れ
    1. NGINXリバースプロキシ設置
    2. NGINXでページキャッシュ導入
    1. 数千件の特定URLをキャッシュする
    2. SPとPCでキャッシュを分ける
    3. リリース
    64

    View Slide

  65. NGINXでページキャッシュ導入
    65
    要件1
    ● 数千件の特定URLをキャッシュする
    対応
    ● mapディレクティブで対象パスを制限
    ○ 条件分岐というとif文が頭に浮かびますが、NGINXではif文は邪悪と言わ
    れておりなるべく使わないべきとされています。
    そこで、mapディレクティブで条件分岐を行うようにしました。

    View Slide

  66. NGINXでページキャッシュ導入
    66
    ● mapディレクティブで対象パスを制限
    map $host$request_uri $is_target_path {
    default 0;
    include /etc/nginx/cache_target_path.map;
    }
    aumo.jp/prefectures/13/scenes/8 1;
    aumo.jp/prefectures/27/categories/a12 1;
    gourmet.aumo.jp/areas/466/categories/a15 1;
    /etc/nginx/cache_target_path.map

    View Slide

  67. ページキャッシュ導入の流れ
    1. NGINXリバースプロキシ設置
    2. NGINXでページキャッシュ導入
    1. 数千件の特定URLをキャッシュする
    2. SPとPCでキャッシュを分ける
    3. リリース
    67

    View Slide

  68. NGINXでページキャッシュ導入
    68
    要件2
    ● SPとPCでキャッシュを分ける
    対応
    ● キャッシュキーにPCかSPかの情報を含める

    View Slide

  69. NGINXでページキャッシュ導入
    69
    ● キャッシュキーにPCかSPかの情報を含める
    ○ PCかSPかの情報をもつ$deviceをmapディレクティブで用意する
    ○ キャッシュキー(proxy_cache_key)に$deviceを加える
    ■ キャッシュキーの例:aumo.jp/areas/13:sp
    location / {
    ......
    proxy_cache_key $host$uri:$device;
    ......
    }

    View Slide

  70. ページキャッシュ導入の流れ
    1. NGINXリバースプロキシ設置
    2. NGINXでページキャッシュ導入
    3. リリース
    70

    View Slide

  71. リリース後の効果計測
    71
    ● レスポンス速度
    ○ 0.00秒でレスポンスを返している!

    View Slide

  72. 72
    ● CoreWebVital指標
    ○ 合格!!
    リリース後の効果計測
    指標
 定義
 キャッシュ前
 目標値
 キャッシュ後

    全体
 不合格
 合格
 合格

    LCP
 メインコンテンツの読み込み速度
 4.3s
 2.5s
 1.7s

    FID

    操作を行ってから応答が発生するま
    での遅延時間

    489ms
 100ms
 なし

    CLS
 読み込み時のレイアウトのずれ
 0
 0
 0

    TTFB
 サーバー初期応答時間
 2.8s
 0.8s
 0.5s

    FCP
 視覚コンテンツの初期表示時間
 3.7s
 1.8s
 1.3s

    INP
 コンテンツの反応速度
 3,943ms
 200ms
 2,263ms


    View Slide

  73. 73
    ● MAU
    ○ MAUが成長!
    リリース後の効果計測

    View Slide

  74. キャッシュについてのまとめ
    74
    ● 速度改善にも種類がある
    ○ バックエンド: DBアクセスのキャッシュ、N+1
    ○ フロントエンド: ページキャッシュ、CDN
    ● ページキャッシュを導入すれば、ページがリッチになってもレスポンス速度が速
    いまま変化しない
    より詳細が知りたい方は、テックブログを見てください!
    https://techblog.aumo.co.jp/articles/2278

    View Slide

  75. このセッションのまとめ
    75
    ● フロントエンドをRailsのテンプレートエンジンからNuxt.jsに移行することで
    開発工数削減ができた。
    ● フロントエンドにNGINXのリバースプロキシを設置してキャッシュを導入する
    ことでレスポンス速度の改善ができた。
    ● これからもサービスの質を高めて、より多くの人に使ってもらえるサービスに成
    長させていきます!

    View Slide

  76. ご成長(静聴)ありがとうございました!
    76

    View Slide

  77. 77

    View Slide