Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

Chunked encoding を使った高速化の考察

4.852 Aufrufe

Veröffentlicht am

東京Node学園 #26の発表

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

Chunked encoding を使った高速化の考察

  1. 1. Copyright © DeNA Co.,Ltd. All Rights Reserved. chunked encoding を使った高速化の考察 東京Node学園26時限目 2017/6/28 渋川よしき
  2. 2. Copyright © DeNA Co.,Ltd. All Rights Reserved. 新刊でました! ■ 初版を買うなら今がチャンス!今すぐ本屋へ ■ ブラウザなどの通信まわり(JSとかCSSを 除く)のいろいろなトピックを思いつく限り 集めました ■ ブラウザ(利用者)視点で説明するようにして います。
  3. 3. Copyright © DeNA Co.,Ltd. All Rights Reserved. ■ ウェブ系の話題で、 「だよねーわかるわかる…」 と分かったふりをしたことがある人に オススメ! ■ アニメについて詳しくなりたい人は 弊社のハッカドールをご利用ください
  4. 4. Copyright © DeNA Co.,Ltd. All Rights Reserved. 今日の発表はReal World HTTP を読んでいる前提で進めます
  5. 5. Copyright © DeNA Co.,Ltd. All Rights Reserved. その前に
  6. 6. Copyright © DeNA Co.,Ltd. All Rights Reserved.
  7. 7. Copyright © DeNA Co.,Ltd. All Rights Reserved.
  8. 8. Copyright © DeNA Co.,Ltd. All Rights Reserved. Mithrilの最新動向も気になりますよね!
  9. 9. Copyright © DeNA Co.,Ltd. All Rights Reserved. Mithril 1.xのバージョンアップについて
  10. 10. Copyright © DeNA Co.,Ltd. All Rights Reserved. Mithril 0.2.x ■ 少ないAPI ■ 小さなダウンロードサイズ ■ 仮想DOMを使った高速な描画 ■ イベントハンドラと通信のコールバックを活用した描画タイミング制御
  11. 11. Copyright © DeNA Co.,Ltd. All Rights Reserved. Mithril 0.2.x : 21関数、2プロパティ ■ コア ⁃ m() ⁃ m.component() ⁃ m.prop() ⁃ m.withAttr() ■ ラウティング ⁃ m.mount() ⁃ m.route(elem, defualt, routes) ⁃ m.route(path, params, replaceHistory) ⁃ m.route() ⁃ m.route(element) ⁃ m.route.mode ⁃ m.route.param ⁃ m.route.buildQueryString() ⁃ m.route.parseQueryString() ■ データ ⁃ m.request() ⁃ m.deferred() ⁃ m.sync() ■ HTML ⁃ m.trust() ■ レンダリング ⁃ m.render() ⁃ m.redraw() ⁃ m.redraw.strategy() ⁃ m.startComputation() ⁃ m.endComputation() ■ テスト ⁃ m.deps()
  12. 12. Copyright © DeNA Co.,Ltd. All Rights Reserved. Mithril 1.x : 14関数、2プロパティ ■ コア ⁃ m() ⁃ m.component() ⁃ m.prop() ⁃ m.withAttr() ■ ラウティング ⁃ m.mount() ⁃ m.route(elem, defualt, routes) ⁃ m.route(path, params, replaceHistory)→m.route.set() ⁃ m.route()→m.route.get() ⁃ m.route(element)→m.route.link() ⁃ m.route.mode→m.route.prefix ⁃ m.route.param ⁃ m.route.buildQueryString()→m.buildQueryString() ⁃ m.route.parseQueryString()→m.parseQueryString() ■ データ ⁃ m.request() ⁃ m.deferred() ⁃ m.sync() ■ HTML ⁃ m.trust() ■ レンダリング ⁃ m.render() ⁃ m.redraw() ⁃ m.redraw.strategy() ⁃ m.startComputation() ⁃ m.endComputation() ■ テスト ⁃ m.deps() ■ 追加 ⁃ m.fragment() ⁃ m.version
  13. 13. Copyright © DeNA Co.,Ltd. All Rights Reserved. Mithril 1.xはマジキチ ■ 機能が減った ⁃ 関数の数が21→14 ⁃ ファイルサイズも減った ⁃ deferredがES6標準のPromiseに移行 ⁃ 描画タイミングコントロールなんて必要なかった ⁃ プロパティは外部に切り出されてちょっとリッチなストリームになった ■ 高速化したらしい ■ 設計のガイドラインからビューモデルが消えた ⁃ ドキュメントからビューモデルの文字が消えさった ■ ライフサイクルメソッドが整理された ■ なお、マイグレーションスクリプトで変換はほぼ自動でいける ⁃ http://mithril-ja.js.org/change-log.html#migrating-from-v02x
  14. 14. Copyright © DeNA Co.,Ltd. All Rights Reserved. Mithril 1.xを活かす設計 ■ 仮想DOMのパフォーマンス・チューニングがしやすく ⁃ 仮想DOMの内部設計がドキュメント化された。コードも読みやすい。 ■ コンポーネントは表示に特化 ⁃ ラウターリゾルバーを使ってデータ取得をコンポーネントの外に移動で きるように ■ データ取得部分はモデルに ⁃ ビューモデルの役割もモデルにマージ ⁃ ただ、通信の最適化とかこのあたりは今後革新がありそう (Mithrilにかぎらず、React、Vue、Riot、Angularとかでも) ■ 終了アニメーション ⁃ ライフサイクルメソッドがPromiseを返せる。終了を遅延できる。 ⁃ 0.2.xでは力技で実現するのは大変だった。
  15. 15. Copyright © DeNA Co.,Ltd. All Rights Reserved. ドキュメント(http://mithril-ja.js.org/)は翻訳済み
  16. 16. Copyright © DeNA Co.,Ltd. All Rights Reserved. 本もあるよ! ■ オライリーの電子書籍です ■ 0.2.x準拠 ■ 前ページの項目の差分に気をつけながら お読みいただければ ⁃ ビューモデルもモデルの一部に ⁃ 描画タイミングの制御はなくなった ⁃ モデル取得の司令はラウターリゾルバーに 持っていく方がたぶん良い ■ 精神的な部分は互換性があります! ■ そろそろ改訂したい気持ちがあります
  17. 17. Copyright © DeNA Co.,Ltd. All Rights Reserved. chunked encoding を使った高速化の考察 東京Node学園26時限目 2017/6/28 渋川よしき
  18. 18. Copyright © DeNA Co.,Ltd. All Rights Reserved. Transfer-Encoding: chunked ■ Real World HTTP P119を開いてください ■ Transfer-Encoding: chunked ■ HTTP/1.1で追加された機能 ■ ボディを細切れにして転送する ⁃ 最初にContent-Lengthで全体の長さを送らない ⁃ チャンクサイズ(16進数)と、その長さのボディという組を何回かに分 けて送る ⁃ 最後に長さゼロを送ると終了 ⁃ ボディサイズを最初に決めなくてもいい
  19. 19. Copyright © DeNA Co.,Ltd. All Rights Reserved. 質問: Transfer-Encoding: chunked を普段から意識していますか?
  20. 20. Copyright © DeNA Co.,Ltd. All Rights Reserved. 有効回答数: 19
  21. 21. Copyright © DeNA Co.,Ltd. All Rights Reserved. 有効回答数: 19 半数以上の人があまり意識してい ない
  22. 22. Copyright © DeNA Co.,Ltd. All Rights Reserved. 普段は意識しなくてもいい ■ どのプログラミング言語のHTTPクライアントAPIも、勝手に結合してくれる ■ bodyをストリームのようなAPIで読み込むと、場合によってはチャンクごとに 返ってくるかも? ■ 大抵HTTPクライアントを書く時は、JSONとかの細切れにパースできないデー タが欲しいだろうから、末尾までまるっと読み込みますよね?
  23. 23. Copyright © DeNA Co.,Ltd. All Rights Reserved. SSRは本当に早いのか? ■ SSRを使うと初回ロードが高速になるっていうけど ⁃ 本当に高速なの? ⁃ Node.jsのイベントループに負荷をかけるしスケールするか疑わしい(キ ャッシュしないと) ■ 最近のウェブのデータ量は大きい ⁃ JSも数100KB ⁃ CSSもでかい ⁃ 画像も多い。全部で数MBはある。
  24. 24. Copyright © DeNA Co.,Ltd. All Rights Reserved. HTTP リクエスト リクエスト 受信 DB アクセス HTML レンダ リング HTML パース 初回表示されるまでの流れ ファイル 転送 アセット リクエスト 表示
  25. 25. Copyright © DeNA Co.,Ltd. All Rights Reserved. HTTP リクエスト リクエスト 受信 DB アクセス HTML レンダ リング HTML パース 初回表示されるまでの流れ ファイル 転送 アセット リクエスト 表示 表示するにもいろいろ情報を集め る必要がある HTMLパースをするまで 必要なJS/CSS/画像がわからない リクエスト開始が遅い 実際にはここが一番支配 的になるはず CSS→画像も読み込まな いと必要なファイルが分 からない
  26. 26. Copyright © DeNA Co.,Ltd. All Rights Reserved. chunked encodingを使うアイディア ■ HTMLを読み込まないと必要なリソースがわからない・・・ ⁃ <script>タグと<link>タグ部分だけ先に読み込ませてしまえばいいのでは? ■ 期待する結果 HTTP リクエスト リクエスト 受信 DB アクセス HTML レンダ リング HTML パース ファイル 転送 アセット リクエスト 表示 HTML パース 高速化
  27. 27. Copyright © DeNA Co.,Ltd. All Rights Reserved. ■ 実験してみた:その1 ⁃ すみません。Goで書きました。 ⁃ HTTP/2を使っています。 ⁃ HTMLはまずヘッダーを返し、末尾のコンテンツは4秒後に返した ⁃ リソースはJS、async付きJS、defer付きJS、CSSの4種類を読み込み。サーバ ー側で、2秒に返信と6秒後に返信の2パターン8通り返してみた ⁃ コードはこちら
  28. 28. Copyright © DeNA Co.,Ltd. All Rights Reserved.
  29. 29. Copyright © DeNA Co.,Ltd. All Rights Reserved. 即座にヘッダー部だけ返し、 残りは4秒後に返している
  30. 30. Copyright © DeNA Co.,Ltd. All Rights Reserved. サーバーリクエストはその瞬間に スタートしている(レスポンスは サーバー側で2-6秒ブロック)
  31. 31. Copyright © DeNA Co.,Ltd. All Rights Reserved. スの<script>タグと<link>のスタイ ルシートの読み込みがブロックに なっていて、完了すると表示され る
  32. 32. Copyright © DeNA Co.,Ltd. All Rights Reserved. ■ 実験してみた:その2 ⁃ すみません。Goで書きました。 ⁃ HTTP/2を使っています。 ⁃ HTMLはまずヘッダーを返し、末尾のコンテンツは4秒後に返した ⁃ リソースはJS、async付きJS、defer付きJS、CSSの4種類を読み込み。 サーバー側で、2秒に返信と6秒後に返信の2パターン8通りのうち、6秒間 ブロッキングするJSとCSSを抜いた6パターンでアクセス ⁃ コードはこちら
  33. 33. Copyright © DeNA Co.,Ltd. All Rights Reserved.
  34. 34. Copyright © DeNA Co.,Ltd. All Rights Reserved. ブロッキングするJS/CSSが終わっ たこの段階(2秒後)で表示が開始 されている(この時点で読み込み 済みのCSSは利用される
  35. 35. Copyright © DeNA Co.,Ltd. All Rights Reserved.
  36. 36. Copyright © DeNA Co.,Ltd. All Rights Reserved. 後半のチャンクが到着したら再度 画面更新 window.addEventListener('load')イ ベントは最後のチャンクまで呼ば れたら実行される。
  37. 37. Copyright © DeNA Co.,Ltd. All Rights Reserved. 実験成功 ■ 先に返したヘッダー部分をパースしてChromeは必要なリクエストを取得した ⁃ chunked-encodingは高速化に使える ■ ドキュメントのロードイベントは全HTMLの読み込みが終わってから実行 ⁃ 先にJSをロードしても、documentオブジェクトがまだないので何も表示 もできなかった ■ アセットの種類によって優先度が変わっている ⁃ スの<script>タグだとhigh ⁃ <link>のCSSファイルはhighest ⁃ async/defer付きの<script>タグはlow ■ 優先度が高いアセットはダウンロード完了するまで表示がストップ
  38. 38. Copyright © DeNA Co.,Ltd. All Rights Reserved. ・・・実はHTTP/2では ■ chunked-encodingなんてものはありません→ ■ HTTP/2では各ファイルごとにストリームができる ⁃ ストリームは擬似的なTCPコネクション ⁃ ストリームには、データ片がフレームという単位で送信される ⁃ HEADERSフレーム(ヘッダー)やDATAフレーム(ボディ)などがある ⁃ 各ストリームを構成するフレームは終了ビットを立てない限りは同じ種 類のフレームを連続して送信できる 終了ビットの立ってないDATAフレームを断続的に送信することで chunked-encodingと同じことが実現できる!!! GoのAPIは同じFlusherインタフェースでHTTP/1.1と2の両対応 RFC 7540 : Section 8.1 HTTP/2 uses DATA frames to carry message payloads. The "chunked" transfer encoding defined in Section 4.1 of [RFC7230] MUST NOT be used in HTTP/2.
  39. 39. Copyright © DeNA Co.,Ltd. All Rights Reserved. 実はこの手法 ■ オライリーの続・ハイパフォーマンスWebサイト にも書いてありました。 ⁃ 第12章: ドキュメントのフラッシュ ■ やってみたらHTTP/2でもまだ有効というのが 今回の収穫 ■ ダウンロードのアセット間のブロッキングが 当時とは違って行われないことがわかりました ⁃ HTTP/2にすればアセットの順序とか考えずに トップスピードでダウンロード
  40. 40. Copyright © DeNA Co.,Ltd. All Rights Reserved. それ以外の高速化のアイディア ※一部妄想です
  41. 41. Copyright © DeNA Co.,Ltd. All Rights Reserved. HTTP/2時代のスクリプトの配布は? ■ 分割されたファイルをそのまま配信する方が良い ⁃ ファイル片ごとにキャッシュが効くので二回目以降のメリットが大きい ■ webpack/browserify/rollupとかは不要になる? ⁃ たぶんならない ⁃ tree shakingでファイルサイズ削減はあって損はないはず ⁃ npmとか余計なファイル入りまくりなのでそのままデプロイとか辛い ⁃ 単純にソースコードのままだと、子・孫のファイル取得に時間がかかる ⁃ 途中までは既存のバンドルツールと同じ処理をするが、最後にファイル 結合しないで、必要なすべてのファイルのimport文を並べたエントリー ポイントスクリプトファイルを生成するようになるのでは? 誰か作って!
  42. 42. Copyright © DeNA Co.,Ltd. All Rights Reserved. ボディをServer Side Renderingしないアイディア ■ 完全なSPAでは、JSのロードが終わってから、そのJSがサーバーにリクエスト を送るため、データのロードが開始するのが後ろ倒しになる ⁃ 結果として表示に時間がかかる ■ 前倒しにできないか? ⁃ 完全なHTMLのレンダリングをせずに、インラインJSタグを使ってJSONを 埋めむとか ⁃ あるいは、インラインのスクリプトはCSPでひっかかる可能性があるので いっそのこと/data.jsみたいなJSを読み込むようにして、そのスクリプト を動的生成するとか? • 安全なJSONP ■ SSRが速度に効くというの、JSライブラリがでかすぎただけでは? ⁃ MithrilとかMoon.jsを使えば初回表示も操作開始も爆速にできないか? ⁃ あとはchunked-encodingを使ってJSロードを早めればさらに高速に
  43. 43. Copyright © DeNA Co.,Ltd. All Rights Reserved. まとめ ■ chunked-encodingでダウンロード速度改善はHTTP/2時代にも有効 ■ アセットが巨大化していく時代にあっては効果が大きい ⁃ SSRをして、初回HTML生成までリードタイムが長い場合に 一番効果が大きそう ⁃ SSRしないけど、JSONを埋め込んでSPAの手法で高速化するときも有効 ■ chunked-encodingとかHTTP/2のフレームあたりの詳しい説明が知りたい方は Real World HTTPっていう本に書かれているらしいですよ!

×