Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

ここ数年のWebアプリケーションにおけるSSRとは ● SSR = Special Super Rare Server Side Rendering ● サーバー側で初期表示に必要なHTMLツリーを作って返すこと ● 狭義では、Reactの renderToString() で作ったHTML文字列を、Expressの res.send() で返すこと

Slide 3

Slide 3 text

ただのSSRじゃねぇ? どういうことだ? 

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

SSR実装について

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

ページ全体をSSRするようにした効果 ● サービス名や番組名で検索したとき *.abema.tv から始まるページが 上位に出やすくなった ○ SSRをしているページ(※1)でユーザーにとって意味があるコンテンツがより速 く表示されるようになった(※2)ことが関係している? ■ ※1 トップ・エピソード一覧・エピソード詳細ページが対象 ■ ※2 指標で言えばSpeed IndexやFirst Meaningful Paint Timeなど ○ ページの内容が初期表示時に読み込まれるようになって、検索エンジンのク ローラーに認識されやすくなった?

Slide 9

Slide 9 text

デモ

Slide 10

Slide 10 text

SSR実装でハマったところ

Slide 11

Slide 11 text

開発時にバックエンド側でエラーが多発した ● 元々SSRすることを想定して作られていなかった ○ ブラウザ上でしか動かないコードが多かった ○ window や localStorage などのプロパティを触っている箇所でエラーが出 た ● モジュールをインポートする際に余計なものが読み込まれていた ○ 必要なものだけを読み込むようにした

Slide 12

Slide 12 text

バックエンドとクライアントで描画の差異があった ● バックエンド側でタイトルや説明文などのメタデータしか返してなかった ○ コンポーネントを描画するためのデータが足 りてなかった ● 結果 Warning: Expected server HTML to contain a matching
in
が多発した ○ console.log() やHTMLのソースを見て、コンポーネント描画に必要なデータ を返すようにした ○ SSRできないものは componentDidMount() が実行された後に描画するよう にした

Slide 13

Slide 13 text

まとめ

Slide 14

Slide 14 text

まとめ ● SSRをするようにしたらページの表示速度が速くなって良かった ○ 速くなったことによりユーザー体験が上がったと思う ○ SEOという意味でも効果があった ● SPA + SSR構成をやる場合は、最初からやったほうが途中で導入するより楽 ○ 最初からブラウザとバックエンド両方で動くように考慮できそう ● 課題もまだあるけど引き続き潰していきたい ○ ページの表示高速化はまだやれるところがある

Slide 15

Slide 15 text

CDN導入について

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

Cloud LB Kubernetes Engine Nginx for Fastly Node.js https://abema.tv 現在のAbemaTVとCDN Fastly

Slide 19

Slide 19 text

Fastlyを選んだ理由 ● 次世代CDNの豊富な機能 ○ インスタントパージでキャッシュ即削除 ○ Varnishベースのため、VCLで柔軟なカスタマイズができる ○ HTTP/2 Server Push が使える ● 社内での先行事例あり (https://www.superchoice.bet/) ○ 各種設定を始め、VCLカスタムやノウハウを参考にできそう ● 一度は使ってみたかった(チーム一同) ○ とても大事!

Slide 20

Slide 20 text

Fastly移行の課題

Slide 21

Slide 21 text

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)

Slide 22

Slide 22 text

UA別のキャッシュ振り分け ● Varnish: 設定方法 ● Varnish: UAやファイル種類に応じて識別ヘッダーをセット ● Varnish: 識別ヘッダーをVaryヘッダーにセット ● Node.js: 識別ヘッダーを使って内部の分岐に利用

Slide 23

Slide 23 text

Varnish: 設定方法 ● FastlyではVCLを直接記述する方法が以下用意されている ○ カスタムVCL: 独自のVCLファイルを作成することができる ○ VCLスニペット: カスタムVCLを使わずに、小さなVCLロジックを挿入できる ● AbemaTVではカスタムVCLを利用 ○ 要件上は、VCLスニペットでも表現可能 ○ Fastlyの全設定をTerraformを通して反映しており、 TerraformがVCLスニペット未対応 ○ 今後の拡張性も考慮 UA別のキャッシュ振り分け

Slide 24

Slide 24 text

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別のキャッシュ振り分け

Slide 25

Slide 25 text

Varnish: 識別ヘッダーをVaryヘッダーにセット UA別のキャッシュ振り分け Vary: …, X-UA-Device, X-UA-Vendor として、別々にキャッシュさせる

Slide 26

Slide 26 text

Node.js: 識別ヘッダーを使って内部の分岐に利用 UA別のキャッシュ振り分け - X-UA-Device, X-UA-Vendror が共にある場合 - デスクトップ or モバイルや、iOS or Android の判定に利用する - SSR結果を変え、Varyヘッダーによりキャッシュもそれぞれで行われる - X-UA-Device, X-UA-Vendror のどちらかがない場合 - リクエスト情報のUserAgentを見て判定を行う(従来通り) - 移行直前や切り戻しで、 Fastlyを経由しないケースにも対応するため

Slide 27

Slide 27 text

オリジンシールドによるヒット率の向上(未遂) ● オリジンサーバーへのアクセスをシールドPOP経由にする仕組み ○ エッジPOPからのリクエストはシールド POP経由になる ● 但し、国内限定では目立った効果がないとのこと ○ Fastly社からの設定レビューでアドバイスをもらう ○ エッジサーバーが少ない故(日本では数箇所) ○ 結果、無効にした https://docs.fastly.com/ja/guides/performance-tuning/shielding.html

Slide 28

Slide 28 text

オリジンサーバーの要件 ● 従来のURL https://abema.tv とは別のURLで提供する ○ https://abema.tv はFastly用になるため ● 通常のアクセスはできないようにする ○ 認証用のリクエストヘッダーを定義 ○ FastlyのVarnish設定で、オリジンサーバーへのリクエスト時に追加する ○ オリジンサーバー側でチェックし、無効な場合は 401を返す ● Cloud CDNを無効にする ○ 二重CDNにならないように

Slide 29

Slide 29 text

稼働状態からの移行方法 ● Cloud LBで従来のURLとオリジンサーバー用のURLを設定 ○ ① 従来のURL: Cloud CDNを有効 - Nginx ○ ② オリジンサーバー用の URL: Cloud CDNを無効 - Nginx for Fastly ● https://abema.tv のDNS設定で、切り替え・切り戻しを行う ○ GCP宛: ①で受け、Cloud CDN経由で配信する ○ Fastly宛: Fastlyで受け、②からリソースを取得し、 Fastly経由で配信する

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

現在のAbemaTVとCDN(詳細版 - Fastly) Cloud LB Cloud CDN Kubernetes Engine Nginx Node.js https://abema.tv Nginx for Fastly Fastly 認証用のリクエストヘッダーを付与

Slide 32

Slide 32 text

\ 無事に移行完了 /

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

今後の予定 ● より細かい分類によるキャッシュの最適化 ○ 課金プランごとに一部表記が異なる等 ■ 現在のSSRはどちらにも対応できる形にし、 Clientで再描画を行っている ● ブラウザ毎の配信JSの最適化 ○ サポート状況に合わせたファイルを配信する ● 切り戻し手段の再考 ○ 現時点では、以前の構成にすぐ戻せる形にしている ○ 普段使わないファイル群が残ったままになる ■ メンテが煩雑化、いざ戻した際も動作が保証しきれない

Slide 35

Slide 35 text

ご清聴ありがとうございました ☕