Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
MAUが1年で292%に成長した「aumoのおでかけ比較サイト」における取り組み
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
gree_tech
PRO
October 13, 2023
Technology
2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
MAUが1年で292%に成長した「aumoのおでかけ比較サイト」における取り組み
GREE Tech Conference 2023で発表された資料です。
https://techcon.gree.jp/2023/session/TrackA-2
gree_tech
PRO
October 13, 2023
More Decks by gree_tech
See All by gree_tech
変わるもの、変わらないもの :OSSアーキテクチャで実現する持続可能なシステム
gree_tech
PRO
0
4.6k
マネジメントに役立つ Google Cloud
gree_tech
PRO
0
60
今この時代に技術とどう向き合うべきか
gree_tech
PRO
3
2.7k
生成AIを開発組織にインストールするために: REALITYにおけるガバナンス・技術・文化へのアプローチ
gree_tech
PRO
0
420
安く・手軽に・現場発 既存資産を生かすSlack×AI検索Botの作り方
gree_tech
PRO
0
420
生成AIを安心して活用するために──「情報セキュリティガイドライン」策定とポイント
gree_tech
PRO
1
2.2k
あうもんと学ぶGenAIOps
gree_tech
PRO
0
530
MVP開発における生成AIの活用と導入事例
gree_tech
PRO
0
560
機械学習・生成AIが拓く事業価値創出の最前線
gree_tech
PRO
0
440
Other Decks in Technology
See All in Technology
2026.06.13_AI時代に事業会社が「SIer出身エンジニア」を求める理由 / Why Businesses Seek Engineers with a System Integrator Background in the AI Era
jumtech
0
1.1k
【セミナー資料】Claude Code をセキュアに使うための考え方と設定の勘どころ / Claude Code Webinar 20260616
masahirokawahara
1
230
Claude Codeをどのように キャッチアップしているか
oikon48
12
7.8k
2026TECHFRESH畢業分享會 - AI 時代的人生存檔點
line_developers_tw
PRO
0
970
LayerXにおけるセキュリティ管理の現在地と次の一手
tosho
0
160
エラーバジェットのアラートのタイミングを考える.pdf
kairim0
0
140
RAG を使わないという選択肢
tatsutaka
1
220
自律型AIエージェントは何を破壊するのか
kojira
0
160
「エンジニア進化論」2028年の開発完全自動化、エンジニアはどう進化するか
cyberagentdevelopers
PRO
6
5.1k
MCP Appsを作ってみよう
iwamot
PRO
4
610
あなたの AI ワークスペースに、 専門コーダーを連れてくる - Amazon Quick Desktop 最新情報
kawaji_scratch
1
130
2026TECHFRESH畢業分享會 - Lightning Talk - 打造精準高效的 MCP 設計模式與測試實務
line_developers_tw
PRO
0
970
Featured
See All Featured
Building AI with AI
inesmontani
PRO
1
1.1k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
330
The Invisible Side of Design
smashingmag
302
52k
SEO for Brand Visibility & Recognition
aleyda
0
4.6k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
240
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
300
GitHub's CSS Performance
jonrohan
1033
470k
First, design no harm
axbom
PRO
2
1.2k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Transcript
MAUが1年で292%に成長した 「aumoのおでかけ比較サイト」 における取り組み アウモ株式会社 エンジニア 関谷恒甫 栗本拓弥
目次 • 発表者紹介 • aumoについて • フロントエンドをRailsのテンプレートエンジンからNuxt.jsに 移行した話 • フロントエンドにNGINXのリバースプロキシを設置してキャッ
シュを導入した話 • まとめ 2
自己紹介 3 • 名前:関谷恒甫 • 所属:アウモ株式会社 • 担当:メディアチームにおける開発全般 • 経歴:
◦ 2020年4月:グリーに新卒入社 ◦ 2020年4月:アウモに配属 ◦ 2020年6月:WFSに配属 ◦ 2021年12月:アウモに配属
自己紹介 • 名前:栗本拓弥 • 所属:アウモ株式会社 • 担当:メディアチームにおける開発全般 • 経歴: ◦
2022年4月:グリーに新卒入社 ◦ 2022年4月:アウモに配属 4
aumoについて
サービスの全体像
メディア事業
メディア事業の提供サービス
新規事業の取り組み
SaaS事業
SaaS事業の提供サービス
SaaS 事業の機能紹介
Fintech
Fintech事業の概要
マーケティングソリューション
マーケティングソリューションの概要
おでかけ比較サイトのフロントエンドを Railsのテンプレートエンジンから Nuxt.jsに移行した話 17
何をやったのか • aumo.jpの一覧ページ(例 aumo.jp/areas/241)のフロントエンドを、 Railsのテンプレートエンジン(slim)からNuxt.jsに移行した。 18
19 gourmet.aumo.jp aumo.jp なぜやるのか • aumoではaumo.jpドメインと3つのサブドメイン(gourmet.aumo.jp, leisure.aumo.jp, travel.aumo.jp)で一覧 ページを運営しています。
なぜやるのか (歴史的経緯のため)ドメインによって フロントエンドの実装が異なる • サブドメイン ◦ Nuxt.js • aumo.jp ◦
Railsテンプレートエンジン 20
なぜやるのか • 一覧ページを開発する際は基本的にドメイン4つ全てが開発の対象 ◦ サブドメインではNuxt.jsのコンポーネントを使い回すことができる が、aumo.jpドメインではそれらを使えないので、テンプレートエン ジンのコードも書く必要がある。。。 21
なぜやるのか • 一覧ページを開発する際は基本的にドメイン4つ全てが開発の対象 ◦ サブドメインではNuxt.jsのコンポーネントを使い回すことができる が、aumo.jpドメインではそれらを使えないので、テンプレートエン ジンのコードも書く必要がある。。。 22 2度手間!!!
移行の流れ ※アウモでは業務時間の1~2割程度を、各自がやりたい開発改善等の 時間に当てて良いということになってるので、その仕組みを今回は 利用しました。 23 1. アプリケーションコード変更 2. インフラ変更 3.
リリース
移行の流れ 1. アプリケーションコード変更 2. インフラ変更 3. リリース 24
アプリケーションコードの変更 • テンプレートエンジンのコードを、Nuxtに書き換える。 • 基本的には既存のNuxtのコンポーネントを使い回す。 • aumo.jpドメインのみに存在するUI等がある場合に、コンポーネントを新規 作成or修正。 • デザインが同じでもaumo.jpドメインとサブドメインで仕様が違う可能性があ
るので、コードを一つ一つ確認し差分があった場合は、PMと適時仕様をすり 合わせる。 25
移行の流れ 1. アプリケーションコード変更 2. インフラ変更 3. リリース 26
インフラの変更 • aumo.jpドメインには一覧ページ(https://aumo.jp/areas/241)だけで なく、記事ページ(https://aumo.jp/articles/145272)も存在する。 • 一覧ページへのアクセスのみをNuxtサーバに転送するように変更する必要 がある。 ◦ ALBのリスナールールを編集して、特定のパスパターン (例
/areas/*)の時のみリクエストを転送するように設定。 27
インフラ構成の変更 28 BEFORE
インフラ構成の変更 29 BEFORE AFTER
移行の流れ 1. アプリケーションコード変更 2. インフラ変更 3. リリース 30
リリース ここまでは順調だったが。。。 31
リリース1回目 レスポンス速度が悪化する 32
リリース1回目 レスポンス速度が悪化する 原因 • コード変更に伴い、リリースのタイミングでAPI側 で既存のキャッシュが使えなくなり、 Elasticsearchへのアクセスが増えて負荷が上 がった。 対策 •
元々Elasticsearchの負荷が高めだったので、 この機会にスケールアップを実施。 33
リリース2回目 相変わらずレスポンス速度が遅い状態が続く 34
リリース2回目 相変わらずレスポンス速度が遅い状態が続く 原因 • aumo.jpからリクエストが転送される分、Nuxtサーバへのリクエストが 増えたから? 対策 • サーバー台数を増やしてみる。 35
リリース3回目 相変わらずレスポンス速度が遅い状態が続く 36
リリース3回目 相変わらずレスポンス速度が遅い状態が続く 原因 • パフォーマンスチューニングをほとんど行っておらず、API側でN+1のク エリが複数発生していたから? 対策 • N+1のクエリをひたすら潰す。 37
リリース4回目 相変わらずレスポンス速度が遅い状態が続く 38
リリース4回目 相変わらずレスポンス速度が遅い状態が続く 原因 • 不明。何も思いつかず。 対策 • レスポンスが遅い原因が不明のままなので、問題を切り分けてみる。 • aumo.jpドメインのレスポンスのみが遅いのかサブドメインのレスポンス
も遅いのかを見分けるために、aumo.jpとサブドメインで使うコンテナを 分ける。 39
リリース5回目 aumo.jpドメインへのリクエストのみが遅く、 サブドメインへのリクエストは正常なことが判明 40
アクセスログの調査 アクセスログをよく見てみる • 最初の数分は問題なさそうだが、チラホラ遅い レスポンスが混ざっている。 • その後は全部のレスポンスが遅くなる。 • 遅いレスポンスをよく見ると、エリア番号が大き い傾向があることに気づく。
41
アクセスログの調査 アクセスログをよく見てみる • 最初の数分は問題なさそうだが、チラホラ遅い レスポンスが混ざっている。 • その後は全部のレスポンスが遅くなる。 • 遅いレスポンスをよく見ると、エリア番号が大き い傾向があることに気づく。
42
アクセスログの調査 43 アクセスログをよく見てみる • 最初の数分は問題なさそうだが、チラホラ遅い レスポンスが混ざっている。 • その後は全部のレスポンスが遅くなる。 • 遅いレスポンスをよく見ると、エリア番号が大き
い傾向があることに気づく。 エリア番号が関係してそうなコード を 探す。
問題のコード 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プロパティでキャッシュしてるので大丈夫だと思っていたが。。。
Nuxt.jsをSSRで利用する時の落とし穴 45 原因 • Nuxt.jsをSSRで利用する場合は、computedプロパティが キャッシュされない。 https://github.com/nuxt/nuxt/issues/2447 対策 • 計算が重い処理はcomputedプロパティではなく、storeに保存すること
で、レンダリング中に処理が走るのを1回だけにする。
リリース成功!!! 46 リリース6回目
学んだ点 • ログは超大事。生のアクセスログ、ALBのメトリクス、ECSのメトリクスなど色 んなログを見るべき。 • テストが充実してないと、リファクタリングのハードルが上がる。 • リファクタリングは辛いので、設計の段階でなるべく先まで見通して、リファクタ リングをそもそもしなくて済むようにできるのがベスト。 より詳細が知りたい方は、テックブログを見てください!
https://techblog.aumo.co.jp/articles/2233 47
おでかけ比較サイトのフロントエンドにNGINXのリ バースプロキシを設置して キャッシュを導入した話 48
何をやったのか • 一覧ページを表示しているNuxtサーバの前段に NGINXリバースプロキシを置いて、ページキャッシュを導入した。 49 既存の構成 リクエストが来るたび 大量のAPIを叩いていた リバプロ導入した構成 1回目のリクエストは
従来通り 2回目以降のリクエストは NGINXがキャッシュを返す
なぜやるのか • SEO対策として一覧ページのコンテンツをリッチにして、 MAUが大きく成長した! が、、 50 追加したコンテンツ例
なぜやるのか • SEO対策として一覧ページのコンテンツをリッチにして、 MAUが大きく成長した! が、、 51 追加したコンテンツ例 MAUの推移
なぜやるのか • しかし、ページがリッチになるにつれてレスポンス速度が遅くなってしまって いた 52
なぜやるのか レスポンス速度の悪化によりCoreWebVitalの指標が低下してしまった • CoreWebVitalとは ◦ Googleが定めるWebサイトのUXを測る重要な指標のこと。 ◦ PageSpeed Insightsというサイトで誰でも計測できる •
CoreWebVitalの主な指標 ◦ Time to First Byte (TTFB): ▪ レスポンスの最初のByteが返るまでの時間 ◦ First Contentful Paint (FCP): ▪ 視覚コンテンツの初期表示時間 ◦ Largest Contentful Paint (LCP): ▪ 最大コンテンツの表示時間 53
なぜやるのか 54 • CoreWebVitalが不合格だらけなので、これを改善することで、 MAUがさらに成長するかもしれない
なぜやるのか 55 • CoreWebVitalが不合格だらけなので、これを改善することで、 MAUがさらに成長するかもしれない ちくしょう。 速度改善だ!
なぜやるのか • 今後コンテンツがさらにリッチになっても、レスポンス速度の悪化を招かな いようにしたい。 • Nuxtのレスポンスを丸々キャッシュする「ページキャッシュ」を 導入すると、キャッシュ済みページへのアクセスは一瞬で返せる。 56
なぜやるのか • 今後コンテンツがさらにリッチになっても、レスポンス速度の悪化を招かな いようにしたい。 • Nuxtのレスポンスを丸々キャッシュする「ページキャッシュ」を 導入すると、キャッシュ済みページへのアクセスは一瞬で返せる。 57 ちくしょう。 ページキャッシュだ!
ページキャッシュ導入の流れ 1. NGINXリバースプロキシ設置 2. NGINXでページキャッシュ導入 3. リリース 58
ページキャッシュ導入の流れ 1. NGINXリバースプロキシ設置 2. NGINXでページキャッシュ導入 3. リリース 59
NGINXリバースプロキシ設置 - インフラ構成 - BEFORE
NGINXリバースプロキシ設置 - インフラ構成 - 61 BEFORE AFTER
ページキャッシュ導入の流れ 1. NGINXリバースプロキシ設置 2. NGINXでページキャッシュ導入 3. リリース 62
ページキャッシュ導入の流れ 1. NGINXリバースプロキシ設置 2. NGINXでページキャッシュ導入 1. 数千件の特定URLをキャッシュする 2. SPとPCでキャッシュを分ける 3.
リリース 63
ページキャッシュ導入の流れ 1. NGINXリバースプロキシ設置 2. NGINXでページキャッシュ導入 1. 数千件の特定URLをキャッシュする 2. SPとPCでキャッシュを分ける 3.
リリース 64
NGINXでページキャッシュ導入 65 要件1 • 数千件の特定URLをキャッシュする 対応 • mapディレクティブで対象パスを制限 ◦ 条件分岐というとif文が頭に浮かびますが、NGINXではif文は邪悪と言わ
れておりなるべく使わないべきとされています。 そこで、mapディレクティブで条件分岐を行うようにしました。
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
ページキャッシュ導入の流れ 1. NGINXリバースプロキシ設置 2. NGINXでページキャッシュ導入 1. 数千件の特定URLをキャッシュする 2. SPとPCでキャッシュを分ける 3.
リリース 67
NGINXでページキャッシュ導入 68 要件2 • SPとPCでキャッシュを分ける 対応 • キャッシュキーにPCかSPかの情報を含める
NGINXでページキャッシュ導入 69 • キャッシュキーにPCかSPかの情報を含める ◦ PCかSPかの情報をもつ$deviceをmapディレクティブで用意する ◦ キャッシュキー(proxy_cache_key)に$deviceを加える ▪ キャッシュキーの例:aumo.jp/areas/13:sp
location / { ...... proxy_cache_key $host$uri:$device; ...... }
ページキャッシュ導入の流れ 1. NGINXリバースプロキシ設置 2. NGINXでページキャッシュ導入 3. リリース 70
リリース後の効果計測 71 • レスポンス速度 ◦ 0.00秒でレスポンスを返している!
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
73 • MAU ◦ MAUが成長! リリース後の効果計測
キャッシュについてのまとめ 74 • 速度改善にも種類がある ◦ バックエンド: DBアクセスのキャッシュ、N+1 ◦ フロントエンド: ページキャッシュ、CDN
• ページキャッシュを導入すれば、ページがリッチになってもレスポンス速度が速 いまま変化しない より詳細が知りたい方は、テックブログを見てください! https://techblog.aumo.co.jp/articles/2278
このセッションのまとめ 75 • フロントエンドをRailsのテンプレートエンジンからNuxt.jsに移行することで 開発工数削減ができた。 • フロントエンドにNGINXのリバースプロキシを設置してキャッシュを導入する ことでレスポンス速度の改善ができた。 • これからもサービスの質を高めて、より多くの人に使ってもらえるサービスに成
長させていきます!
ご成長(静聴)ありがとうございました! 76
77