AbemaTVはただのSSR じゃねぇんだよ

AbemaTVはただのSSR じゃねぇんだよ

2018/07/06 Frontrend Vol.12 - サービスの誕生と成長

発表者:
- SSRについて @kubosho
- CDNについて @ktknest

https://frontrend.connpass.com/event/90107/

54f295d3b29f826b92ff7d6bbc365997?s=128

Kenichi Kato

July 06, 2018
Tweet

Transcript

  1. AbemaTVはただのSSR じゃねぇんだよ @kubosho @ktknest 2018/07/06 Frontrend Vol.12 - サービスの誕生と成長

  2. ここ数年のWebアプリケーションにおけるSSRとは • SSR = Special Super Rare Server Side Rendering

    • サーバー側で初期表示に必要なHTMLツリーを作って返すこと • 狭義では、Reactの renderToString() で作ったHTML文字列を、Expressの res.send() で返すこと
  3. ただのSSRじゃねぇ? どういうことだ? 

  4. ありそうな話 • 新規にWebサービスを立ち上げて、そこでSSR + SPA構成にしました! • SPAをやめてSSRだけにしました! • SPAをしているWebサービスの構成を変えるついでに SSRもするようにしました!

  5. AbemaTVの場合 • 新規に何かサービスを作ったわけではない • SSRに加え、従来と同様のSPAも継続している • 既存のコード設計やデータフロー、使うライブラリなどはあまり変えずに SSRした

  6. SSR実装について

  7. なぜAbemaTVではSSRをするようにしたか • SSRをすることにより、ユーザーにとって意味のあるコンテンツが速く表示されるよ うにしたかった • ページ全体をSSRすることにより、ページをよりマシンリーダブルにする ◦ スプラッシュ画面はSSRをしていたがページの情報量が不足している ◦ 検索エンジンのクローラーに、より情報を読み込ませる目的があった

  8. ページ全体をSSRするようにした効果 • サービス名や番組名で検索したとき *.abema.tv から始まるページが 上位に出やすくなった ◦ SSRをしているページ(※1)でユーザーにとって意味があるコンテンツがより速 く表示されるようになった(※2)ことが関係している? ▪

    ※1 トップ・エピソード一覧・エピソード詳細ページが対象 ▪ ※2 指標で言えばSpeed IndexやFirst Meaningful Paint Timeなど ◦ ページの内容が初期表示時に読み込まれるようになって、検索エンジンのク ローラーに認識されやすくなった?
  9. デモ

  10. SSR実装でハマったところ

  11. 開発時にバックエンド側でエラーが多発した • 元々SSRすることを想定して作られていなかった ◦ ブラウザ上でしか動かないコードが多かった ◦ window や localStorage などのプロパティを触っている箇所でエラーが出

    た • モジュールをインポートする際に余計なものが読み込まれていた ◦ 必要なものだけを読み込むようにした
  12. バックエンドとクライアントで描画の差異があった • バックエンド側でタイトルや説明文などのメタデータしか返してなかった ◦ コンポーネントを描画するためのデータが足 りてなかった • 結果 Warning: Expected

    server HTML to contain a matching <div> in <div> が多発した ◦ console.log() やHTMLのソースを見て、コンポーネント描画に必要なデータ を返すようにした ◦ SSRできないものは componentDidMount() が実行された後に描画するよう にした
  13. まとめ

  14. まとめ • SSRをするようにしたらページの表示速度が速くなって良かった ◦ 速くなったことによりユーザー体験が上がったと思う ◦ SEOという意味でも効果があった • SPA +

    SSR構成をやる場合は、最初からやったほうが途中で導入するより楽 ◦ 最初からブラウザとバックエンド両方で動くように考慮できそう • 課題もまだあるけど引き続き潰していきたい ◦ ページの表示高速化はまだやれるところがある
  15. CDN導入について

  16. 以前のAbemaTVとCDN Cloud LB Cloud CDN Kubernetes Engine Nginx Node.js https://abema.tv

  17. SSR化にあたっての課題 • デスクトップとモバイルで異なるHTMLやJS/CSSを配信したい ◦ Cloud CDNではVary: User-Agentによる条件分岐はできない ◦ SSR化するには、これが可能な CDNへの移行が必要になった

    デスクトップ モバイル 全く異なる
  18. Cloud LB Kubernetes Engine Nginx for Fastly Node.js https://abema.tv 現在のAbemaTVとCDN

    Fastly
  19. Fastlyを選んだ理由 • 次世代CDNの豊富な機能 ◦ インスタントパージでキャッシュ即削除 ◦ Varnishベースのため、VCLで柔軟なカスタマイズができる ◦ HTTP/2 Server

    Push が使える • 社内での先行事例あり (https://www.superchoice.bet/) ◦ 各種設定を始め、VCLカスタムやノウハウを参考にできそう • 一度は使ってみたかった(チーム一同) ◦ とても大事!
  20. Fastly移行の課題

  21. TLS 1.0/1.1 が利用できなくなる • AbemaTVの推奨環境で影響がないか確認 • Desktop / iOS 9+

    / Android 5+ OK • Android 4.4 ◦ 標準ブラウザ NG → サポート外とする ◦ WebView(Chromium 30) OK FYI: [Android4系端末のTLS1.1&1.2対応について](https://qiita.com/ntsk/items/9f31fc7b44c04ea45e0b)
  22. UA別のキャッシュ振り分け • Varnish: 設定方法 • Varnish: UAやファイル種類に応じて識別ヘッダーをセット • Varnish: 識別ヘッダーをVaryヘッダーにセット

    • Node.js: 識別ヘッダーを使って内部の分岐に利用
  23. Varnish: 設定方法 • FastlyではVCLを直接記述する方法が以下用意されている ◦ カスタムVCL: 独自のVCLファイルを作成することができる ◦ VCLスニペット: カスタムVCLを使わずに、小さなVCLロジックを挿入できる

    • AbemaTVではカスタムVCLを利用 ◦ 要件上は、VCLスニペットでも表現可能 ◦ Fastlyの全設定をTerraformを通して反映しており、 TerraformがVCLスニペット未対応 ◦ 今後の拡張性も考慮 UA別のキャッシュ振り分け
  24. Varnish: UAやファイル種類に応じて識別ヘッダーをセット 公式のガイドをほぼそのまま使用 https://docs.fastly.com/guides/vcl/delivering-different-content-to-different-devices • X-UA-Device: desktop, tablet, smartphone, native,

    na • X-UA-Vendor: generic, apple, android, etc... 画像リソースなどは UA別にする必要がないので一律 X-UA-Device: na とする UA別のキャッシュ振り分け
  25. Varnish: 識別ヘッダーをVaryヘッダーにセット UA別のキャッシュ振り分け Vary: …, X-UA-Device, X-UA-Vendor として、別々にキャッシュさせる

  26. Node.js: 識別ヘッダーを使って内部の分岐に利用 UA別のキャッシュ振り分け - X-UA-Device, X-UA-Vendror が共にある場合 - デスクトップ or

    モバイルや、iOS or Android の判定に利用する - SSR結果を変え、Varyヘッダーによりキャッシュもそれぞれで行われる - X-UA-Device, X-UA-Vendror のどちらかがない場合 - リクエスト情報のUserAgentを見て判定を行う(従来通り) - 移行直前や切り戻しで、 Fastlyを経由しないケースにも対応するため
  27. オリジンシールドによるヒット率の向上(未遂) • オリジンサーバーへのアクセスをシールドPOP経由にする仕組み ◦ エッジPOPからのリクエストはシールド POP経由になる • 但し、国内限定では目立った効果がないとのこと ◦ Fastly社からの設定レビューでアドバイスをもらう

    ◦ エッジサーバーが少ない故(日本では数箇所) ◦ 結果、無効にした https://docs.fastly.com/ja/guides/performance-tuning/shielding.html
  28. オリジンサーバーの要件 • 従来のURL https://abema.tv とは別のURLで提供する ◦ https://abema.tv はFastly用になるため • 通常のアクセスはできないようにする

    ◦ 認証用のリクエストヘッダーを定義 ◦ FastlyのVarnish設定で、オリジンサーバーへのリクエスト時に追加する ◦ オリジンサーバー側でチェックし、無効な場合は 401を返す • Cloud CDNを無効にする ◦ 二重CDNにならないように
  29. 稼働状態からの移行方法 • Cloud LBで従来のURLとオリジンサーバー用のURLを設定 ◦ ① 従来のURL: Cloud CDNを有効 -

    Nginx ◦ ② オリジンサーバー用の URL: Cloud CDNを無効 - Nginx for Fastly • https://abema.tv のDNS設定で、切り替え・切り戻しを行う ◦ GCP宛: ①で受け、Cloud CDN経由で配信する ◦ Fastly宛: Fastlyで受け、②からリソースを取得し、 Fastly経由で配信する
  30. 現在のAbemaTVとCDN(詳細版 - Cloud CDN) Cloud LB Cloud CDN Kubernetes Engine

    Nginx Node.js Nginx for Fastly Fastly https://abema.tv
  31. 現在のAbemaTVとCDN(詳細版 - Fastly) Cloud LB Cloud CDN Kubernetes Engine Nginx

    Node.js https://abema.tv Nginx for Fastly Fastly 認証用のリクエストヘッダーを付与
  32. \ 無事に移行完了 /

  33. 結果 • キャッシュヒット率がAvg 90%以上 ◦ 思ったよりも高い数値だった • 1週間ほどの検証期間も問題なく経過 ◦ その後、SSRを有効化

  34. 今後の予定 • より細かい分類によるキャッシュの最適化 ◦ 課金プランごとに一部表記が異なる等 ▪ 現在のSSRはどちらにも対応できる形にし、 Clientで再描画を行っている • ブラウザ毎の配信JSの最適化

    ◦ サポート状況に合わせたファイルを配信する • 切り戻し手段の再考 ◦ 現時点では、以前の構成にすぐ戻せる形にしている ◦ 普段使わないファイル群が残ったままになる ▪ メンテが煩雑化、いざ戻した際も動作が保証しきれない
  35. ご清聴ありがとうございました ☕