アメブロ: Isomprhicアプリケーションのパフォーマンス・チューニング

F471f621a38e44a9f4b4959d441f350a?s=47 HOU Bin
September 08, 2017

アメブロ: Isomprhicアプリケーションのパフォーマンス・チューニング

Frontrend Vol.10 - 夏の終わりに納涼パフォーマンス話
https://frontrend.connpass.com/event/63971/
https://freshlive.tv/tech-conference/151511

アメブロ: Isomprhicアプリケーションのパフォーマンス・チューニング

株式会社サイバーエージェント
アメーバブログ
侯斌 ( @houbin217jz )

アメブロSP面で去年刷新から今まで行われたパフォーマンス・チューニングについて紹介致します。特にサーバーとクライエントのキャッシュ設計とチューニング、コード分割、Service Workerのことを詳しくお伝えします。

参考資料:

アメブロ2017: Isomorphic Web Appの進化編
https://developers.cyberagent.co.jp/blog/archives/9001/

アメブロ2017 – 大規模サービスhttps化 ~ All Greenを目指して ~
https://developers.cyberagent.co.jp/blog/archives/7743/

開発、リリース、運用のサイクルを回す――アメブロのフロントエンドにおけるモダンなDevOps環境作り
http://www.atmarkit.co.jp/ait/articles/1704/13/news017.html

React/Redux/Node.jsのSSR/SPAを速くする6つのチューニングポイント
http://www.atmarkit.co.jp/ait/articles/1706/08/news011.html

アメブロでReactやIsomorphic Web Applicationを採用した理由――その成果と構成技術
http://www.atmarkit.co.jp/ait/articles/1702/09/news011.html

No more ガタンッ――React/Redux、Atomic Design、CSS Modulesを取り入れたアメブロのフロントエンド開発の裏側
http://www.atmarkit.co.jp/ait/articles/1702/28/news017.html

アメブロ2016 ~ React/ReduxでつくるIsomorphic web app ~
https://developers.cyberagent.co.jp/blog/archives/636/

アメブロ2016 ~ Isomorphic JavaScriptの詳しい話
https://developers.cyberagent.co.jp/blog/archives/3513/

F471f621a38e44a9f4b4959d441f350a?s=128

HOU Bin

September 08, 2017
Tweet

Transcript

  1. ISOMORPHIC APPLICATIONͷ ύϑΥʔϚϯεɾνϡʔχϯά Ξϝϒϩ ި ඾ @ CYBERAGENT

  2. ࣗݾ঺հ ިɹ඾ʢί΢ɹώϯʣɹ 32࠽ ▸ ത࢜ʢ޻ֶʣ ▸ ग़਎ɿதࠃɾྒྷೡʢ౦๺஍ํʣ ▸ גࣜձࣾαΠόʔΤʔδΣϯτ
 Ξϝʔόϒϩά

    ϑϩϯτϦχϡʔΞϧͷج൫ɾӡ༻Λ୲౰ ▸ 2014೥4݄ɹגࣜձࣾαΠόʔΤʔδΣϯτɹ৽ଔೖࣾ
 2014೥5݄ɹϓϥοτϑΥʔϜɹαʔόʔΤϯδχΞʢJavaʣ
 2015೥4݄ɹ৽نϓϩδΣΫτɹαʔόʔΤϯδχΞʢGoʣ
 2015೥9݄ɹAmeba Ownd ɹɹ ϑϩϯτΤϯδχΞʢAngularJSʣ
 2016೥1݄ɹΞϝʔόϒϩάɹɹϑϩϯτΤϯδχΞʢReact + Node.jsʣɹ ▸ https://twitter.com/houbin217jz ▸ https://github.com/kouhin
  3. ΞϝʔόϒϩάɾSPϦχϡʔΞϧ ▸ 2016೥8݄ϦϦʔε ▸ ಺༰ɿ ▸ Javaϕʔε
 →ɹNode.js ▸ Server

    side renderingʢSSRʣ
 →ɹIsomorphic App (SSR + SPA)
 React + Redux + React Router ▸ σβΠϯϦχϡʔΞϧ ▸ ӡ༻ͳͲʢhttp://www.atmarkit.co.jp/ ait/articles/1704/13/news017.htmlʣ ΞϝʔόϒϩάɾSPϦχϡʔΞϧ https://developers.cyberagent.co.jp/blog/archives/636/
  4. ΞϝʔόϒϩάɾSPϦχϡʔΞϧ ISOMORPHIC APPLICATIONύʔϑΥʔϚϯεɾνϡʔχϯά ▸ όοΫΤϯυͷΩϟογϡ ▸ ஗Ԇϩʔυ & ίʔυ෼ׂ ▸

    Service Worker & ΞηοτͷϓϦΩϟογϡ)
  5. όοΫΤϯυ ͷΩϟογϡʂ

  6. όοΫΤϯυͷΩϟογϡ ͳͥόοΫΤϯυͷΩϟογϡ͕ॏཁͳͷ͔ - 1 ▸ SSRͷύϑΥʔϚϯε͕ྑ͘ͳ͍ʂ ▸ ݪҼɿैདྷSPA޲͚ͷٕज़ΛαʔόʔͰ࣮ݱ
 ϨϯμϦϯάॲཧ͕ෳࡶ
 Perf

    (SSR React) < Perf (Template, e.g. Handlebars.js)
  7. ϨϯμϦϯάॲ ཧ͕ෳࡶͰɺαʔ όʔʹͱͬͯύ ϑΥʔϚϯε͕ ѱ͍

  8. όοΫΤϯυͷΩϟογϡ ͳͥΩϟογϡ͕ॏཁͳͷ͔ - 2 ▸ αʔόʔͷύϑΥʔϚϯε͸ಛʹॏཁ ▸ ཧ༝: ͢΂ͯͷϢʔβʔʹαʔϏεΛఏڙ SPA͕ಈ͔ͳͯ͘΋


    - Өڹൣғ͸֘౰ϢʔβʔͷΈ
 - ैདྷͷSSRͱ΄΅ಉ͘͡ӾཡͰ ͖Δɻ
  9. όοΫΤϯυͷΩϟογϡ ͳͥΩϟογϡ͕ॏཁͳͷ͔ - 3 ▸ Ωϟογϡ͕ޮ͖΍͍͢ ▸ ཧ༝: SEOΛॏࢹ͢ΔӾཡܥͷγεςϜ ί΢͘Μɺί΢͘ΜɺISOMORPHICͷ͜ͱΛฉ͖͍ͨͰ͚͢Ͳ

    ͲΜͳγεςϜͰ͔͢ ͏ͪͷ؅ཧγεςϜͰ͢ ͑ͬͬʁʁͲ͏ͯ͠ISOMORPHICͳͷʁ ΧοίΠΠ͔Β ͦΕ͸ISOMORPHICΛ΍Ίͨ΄͏͕͍͍
  10. όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ ໰୊఺Λચ͍ग़͢ ▸ ԿΛΩϟογϡ͢Δ ▸ Ωϟογϡอଘ͢ΔλΠϛϯά ▸ Ωϟογϡ࡟আ͢ΔλΠϛϯά

    ▸ Local Cache VS Cache Server
  11. όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ ΞϝϒϩSSRͷྲྀΕ ▸ PathϚονϯάɺίϯϙωϯ τͱඞཁͳॲཧΛऔΓग़͢ ▸ Redux Store४උ:

    APIίʔϧ ΛؚΊɺඞཁͳσʔλॲཧ Λߦ͏‼ ▸ Redux Store + ReactDOMServer.renderTo String()‼ = HTML ▸ Q1. ԿΛΩϟογϡ͢Δ 
 
 
 ߋ৽ස౓͕௿͍Object
 
 
 ReactDOMServer
 .renderToString() ͷ݁Ռ
  12. όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ ԿΛΩϟογϡ͢Δ: ReactDOMServer.renderToString() ▸ ΫϥΠΤϯτʹΑͬͯಈతʹมΘΔ಺༰͕͋ΔͷͰɺੜ੒͞ΕͨHTMLΛͦͷ· ·࢖͑ͳ͍ ReactDOMServer.renderToString() Template

    Create Template Template + Client Info (e.g. user-agent) = HTML Cache
  13. όοΫΤϯυͷΩϟογϡ ͪͳΈʹ ▸ ΞϝϒϩͰ͸Ұ൪࠷ॳʹHTML(ReactDOMServer
 .renderToString) ͷΩϟογϡΛͪΌΜͱ࣮૷͕ͨ͠ɺAPI/ ObjectͷΩϟογϡʹ͍ͭͯ͋·Γॏࢹ͠ͳ͔ͬͨɻ ▸ 6݄ͷτϐοΫεͷ͖͔͚ͬͰAPI/ObjectΛਫ਼ࠪ͠ɺΩϟο γϡΛ͖ͪΜͱ࣮૷ͯ͠ɺ͔ͳΓྑ͍݁Ռ͕ग़ͨɻ

  14. όοΫΤϯυͷΩϟογϡ ໷ϐʔΫଳͷฏۉϨεϙϯελΠϜ Before: 26ms After: 17ms API/Object Cache࣮૷લޙͷൺֱ

  15. όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q2. ΩϟογϡอଘλΠϛϯά ▸ ΞΫηε͢Δͱ͖ʹɺΩϟογϡ͕ݟ͔ͭΒͳ͔ͬͨΒɺ ॲཧͯ͠Ωϟογϡอଘ͢Δɻ

  16. όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q3. Ωϟογϡ࡟আλΠϛϯά ▸ هࣄΛߋ৽͞ΕͨΒɺهࣄIDΛ΋ΒͬͯهࣄͷΩϟο γϡΛ࡟আ͢Ε͹OK ͜Ε͸μϝʂʂ

  17. όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q3. Ωϟογϡ͔Β࡟আλΠϛϯά ▸ هࣄΛߋ৽͞ΕͨΒɺهࣄIDΛ΋ΒͬͯهࣄͷΩϟογϡΛ࡟আ͢Ε͹OK ʢ͜Ε͸μϝʂʣ ▸ هࣄͷߋ৽


    ˠɹهࣄϖʔδͷΩϟογϡΛ࡟আ ▸ هࣄͷ౤ߘ
 ˠɹهࣄҰཡͷΩϟογϡΛ࡟আ
 ˠɹهࣄৄࡉͷϦϯΫΛߋ৽͠ͳ͍ͱ͍͚ͳ͍ͷͰɺهࣄৄࡉͷΩϟογϡΛ࡟আ͢Δඞཁ͕͋Δ ▸ εΩϯɾϓϩϑΟʔϧͷߋ৽
 ˠɹϒϩΨʔͷશϖʔδͷΩϟγϡΛ࡟আ ࣮૷͸ෳࡶʹͳΔ͠ɺ
 ສ͕ҰΩϟογϡͷ࡟আ͕࿙ΕͨΒɺ͜Θ͍ʂʂʂʂʂ
  18. όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q3. Ωϟογϡ͔Β࡟আλΠϛϯά ▸ Namespace (Ameba ID)ຖΛ࡟আ
 ▸

    Fallback: ΩϟογϡͷTTLΛઃఆ 
 ສ͕Ұ࡟আࣦഊͯ͠΋ɺTTLʹΑΓΩϟογϡΛࣦޮͤ͞Δ namespace: “staff”
 https://ameblo.jp/staff 
 https://ameblo.jp/staff/message-board.html
 https://ameblo.jp/staff/entry-12308025976.html
 https://ameblo.jp/staff/** DELETE /cache?amebaId=staff
  19. ▸ Q3. Ωϟογϡ͔Β࡟আλΠϛϯά ▸ τϥϯβΫγϣϯ໰୊ όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ߋ৽ user_a DELETE

    
 /cache?
 ameba_id = user_a user_b API Server Node.js Server Cache Ӿཡ Rendering Evict Cache /ameba_id Save Ωϟογϡ࡟আ
 ࣦഊʂ
  20. ▸ Q3. Ωϟογϡ͔Β࡟আλΠϛϯά ▸ τϥϯβΫγϣϯ໰୊ʢόʔδϣϯ෇͖ʣ όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ߋ৽ user_a DELETE

    
 /cache?
 ameba_id = user_a user_b API Server Node.js Server Cache Ӿཡ Rendering Update user_a/version: 4 Save to /user_a/3/ GET user_a/version: 3
  21. όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q4. Local Cache VS Cache Server ▸

    Node.jsͷΠϯελϯε਺͕ଟ͍ ▸ αʔϏε಺ʹॏෳϨϯμϦϯάͨ͘͠ͳ͍͔Β
 Ұ൪࠷ॳʹϦΫΤετΛड͚औͬͨαʔόʔ͕Ωϟογϡ͞Εͨ΋ͷΛଞͷαʔ όʔʹڞ༗Ͱ͖Δ → Cache Server͕ඞཁ ▸ On-memory͸ૣ͍Ͱ͔͢ΒɺΑ͘࢖ΘΕΔ΋ͷΛOn-memoryʹ΋อଘ͢Δ (LRU-cache) → Local Cache͕ඞཁ ▸ 2֊૚: On-memory Cache (LRU-cache) + Cache Server
  22. όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Ωϟογϡͷઃܭͷ·ͱΊ ▸ HTMLςϯϓϨʔτ + APIͷσʔλΩϟογϡ ▸ Namespace

    (AmebaId + Version) ͰΩϟογϡอଘɾΞ ΫςΟϒతͳ࡟আ(Versionߋ৽) ▸ On-memory cache + Cache Server 2֊૚
  23. όοΫΤϯυͷΩϟογϡ Ξϝϒϩ όοΫΤϯυΩϟογϡͷશମਤ

  24. όοΫΤϯυͷΩϟογϡ ݁Ռ1: NEW RELICͰهࣄৄࡉͷΩϟογϡঢ়گ Cache Hit!

  25. όοΫΤϯυͷΩϟογϡ ݁Ռ2: NEW RELICͰهࣄҰཡͷΩϟογϡঢ়گ Cache Hit!

  26. όοΫΤϯυͷΩϟογϡ ݁Ռ3: DATADOGͷMEMCACHED HIT RATE

  27. ஗Ԇϩʔυ LAZY LOAD

  28. ஗Ԇϩʔυ ஗Ԇϩʔυ ▸ ద੾ͳλΠϛϯάͰద੾ͳॲཧΛߦ͏ ▸ SSR → SPA ▸ ϖʔδͷ্

    → ϖʔδͷԼ ▸ ίʔυͷ஗ԆධՁ: ίʔυ෼ׂ
  29. ஗Ԇϩʔυ ஗Ԇϩʔυ: SSR → SPA ▸ SSRͷྲྀΕ ▸ PathϚονϯάɺίϯϙωϯ τͱඞཁͳॲཧΛऔΓग़͢

    ▸ Redux Store४උ: APIίʔϧ ΛؚΊɺඞཁͳσʔλॲཧ Λߦ͏ ▸ Redux Store + ReactDOMServer.renderTo String() = HTML https://github.com/kouhin/react-router-hook https://github.com/kouhin/rrr-lazy
  30. ஗Ԇϩʔυ ஗Ԇϩʔυ: ϖʔδͷ্ → ϖʔδͷԼ

  31. ஗Ԇϩʔυ ͔ͤͬ͘αʔόʔ͔ΒϑϩϯτʹདྷͨͷͰɺ
 CHROME DEV TOOLͰύϑΥʔϚϯεΛΈͯΈΑ͏ʂ ϖʔδʹؔ܎ͳ͍Ϟ δϡʔϧ΋ϩʔυ͠ ͯ͠·ͬͯɺJSධՁ ͕࣌ؒ௕͘ͳͬͨ

  32. ίʔυ෼ׂ ίʔυ෼ׂͷϝϦοτ ▸ ඞཁ͸ͳ͍ίϯϙωϯτΛϩʔυ͠ͳ͍Α͏ʹ ▸ JSධՁ͕࣌ؒ୹͘ͳΔ ▸ main.js๲େԽΛ๷͙ ▸ ৽͍͠ػೳΛͲΜͲΜ௥Ճͯ͠OK

  33. ίʔυ෼ׂ ίʔυ෼ׂͷํ๏ ▸ Webpack ▸ ෼ׂཻ౓ɿAtomicσβΠϯ ͷ Organismsຖ ▸ ෼ׂ͞ΕͨBundleͷαΠζΛݮΒ͢ϓϥάΠϯ

    ▸ ModuleConcatenationPlugin ▸ AggressiveMergingPlugin
  34. ίʔυ෼ׂ ίʔυ෼ׂͷํ๏ɿWEBPACK ▸ https://webpack.js.org/guides/code-splitting ▸ require.ensure, bundle loader, Dynamic imports()

    ▸ ΞϝϒϩɿDynamic imports()
 Lazy Loadʹ͍ͨ͠৔߹: 
 const loadExample = () => import(‘./ExampleComponent’)
  35. ίʔυ෼ׂ ίʔυ෼ׂͷํ๏ɿཻ౓ ▸ AtomicσβΠϯ: Organismsຖ هࣄҰཡTemplate AtomicσβΠϯ

  36. ίʔυ෼ׂ ίʔυ෼ׂͷํ๏ɿཻ౓ ▸ AtomσβΠϯ: Organisms୯Ґ هࣄҰཡTemplate rrr--lazy΋Dynamic Import()ʹରԠࡁΈ

  37. ίʔυ෼ׂ ݁Ռ1ɿ࣮ࡍͷಈ͖

  38. ίʔυ෼ׂ ݁Ռ2ɿJSධՁ࣌ؒ

  39. ίʔυ෼ׂ ίʔυ෼ׂͷҰ൪େ͖͍σϝϦοτ ▸ ݱ࣌఺ͰWebpackͷ࠶Ϗϧυ଎౓͕͔ͳΓ஗͍ʂ ▸ ϩʔΧϧͷ։ൃϞʔυͰίʔυΛमਖ਼ͨ͠Βɺ10s - 20s ͔͔Δ ▸

    ղܾํ๏ɿϩʔΧϧͰίʔυ෼ׂΛແޮʹ͢Δ ▸ babel-plugin-dynamic-import-webpack
 babel-plugin-remove-webpack

  40. ίʔυ෼ׂͯ͠΋ɺΞηοτ ͷαΠζ͸΍͸Γେ͖͍ʂʂ

  41. SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER ▸ લఏɿHTTPSʂ ▸ Ξϝϒϩ2017

    – େن໛αʔϏεhttpsԽ ~ All GreenΛ໨ ࢦͯ͠ ~
 https://developers.cyberagent.co.jp/blog/archives/7743
  42. SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER ▸ service-worker.jsΠϯετʔϧλΠϛϯά ▸ AMPϖʔδʹΞΫηε

    ▸ ΞϝϒϩSPϖʔδʹΞΫηε
  43. SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER - ΤϯτϦ ▸ AMPϖʔδɿඞཁͳΞηοτΛϓϦϩʔυɾΩϟογϡ


    <amp-install-serviceworker> Install-service-worker.html service-worker.js
 (installer) service-worker.js
 (CDN) ΫϩευϝΠϯ importScripts Assets
  44. SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER - ΤϯτϦ ▸ ΞϝϒϩSPϖʔδɿΞηοτΛΩϟογϡ

    service-worker.js
 (installer) service-worker.js
 (CDN) ΫϩευϝΠϯ importScripts Assets
  45. SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER - ࣮૷ ▸ Webpack

    + Workbox
 
 https://github.com/GoogleChrome/workbox
  46. ݁Ռ͸ʁ

  47. None
  48. কདྷͷల๬ কདྷͷల๬ ▸ React 16 & SSR ▸ HTTP/2 &

    ίʔυ෼ׂ ▸ PWA & Service Worker
  49. কདྷͷల๬ REACT 16 & SSR ▸ Ұ൪ظ଴͍ͯ͠Δͷ͸SSRύϑΥʔϚϯεͷվળ React 15 ϚΠϯεϨουΛϒϩο

    Ϋ͞ΕΔͷͰɺ ݱࡏϚϧνϓϩηεͰ ϨϯμϦϯά͍ͯ͠Δ
  50. কདྷͷల๬ REACT 16 ▸ Ұ൪ظ଴͍ͯ͠Δͷ͸SSRύϑΥʔϚϯεͷվળ React 16

  51. ▸ ݱঢ়ɿChromeͳͲ͸ಉ࣌ʹૹ৴͢ΔϦΫΤετ͸6ͭ·Ͱ ʹ੍ݶ͞Ε͍ͯΔ͔Βɺ෼ׂ͞ΕͨJSϑΝΠϧΛಉ࣌ʹϩʔ υ͢ΔࡍʹϒϩοΫ͞Εͯ͠·͏ɻ ▸ ࠓޙɿHTTP/2 ετϦʔϜͷଟॏԽΛར༻͠ɺύϑΥʔϚϯ ε޲্ কདྷͷల๬ HTTP/2

    & ίʔυ෼ׂ
  52. কདྷͷల๬ PWA & SERVICE WORKER ▸ ݱঢ়: Service Worker =

    ϓϦΩϟογϡ ▸ ࠓޙ ▸ Add to Home Screen ▸ App ShellϞσϧ ▸ ΦϑϥΠϯϞʔυ ▸ ௨஌
  53. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠