アメブロ: Isomprhicアプリケーションのパフォーマンス・チューニング
by
HOU Bin
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Slide 1
Slide 1 text
ISOMORPHIC APPLICATIONͷ ύϑΥʔϚϯεɾνϡʔχϯά Ξϝϒϩ ި @ CYBERAGENT
Slide 2
Slide 2 text
ࣗݾհ ިɹʢίɹώϯʣɹ 32࠽ ▸ ത࢜ʢֶʣ ▸ ग़ɿதࠃɾྒྷೡʢ౦ํʣ ▸ גࣜձࣾαΠόʔΤʔδΣϯτ Ξϝʔόϒϩά ϑϩϯτϦχϡʔΞϧͷج൫ɾӡ༻Λ୲ ▸ 20144݄ɹגࣜձࣾαΠόʔΤʔδΣϯτɹ৽ଔೖࣾ 20145݄ɹϓϥοτϑΥʔϜɹαʔόʔΤϯδχΞʢJavaʣ 20154݄ɹ৽نϓϩδΣΫτɹαʔόʔΤϯδχΞʢGoʣ 20159݄ɹAmeba Ownd ɹɹ ϑϩϯτΤϯδχΞʢAngularJSʣ 20161݄ɹΞϝʔόϒϩάɹɹϑϩϯτΤϯδχΞʢReact + Node.jsʣɹ ▸ https://twitter.com/houbin217jz ▸ https://github.com/kouhin
Slide 3
Slide 3 text
ΞϝʔόϒϩάɾSPϦχϡʔΞϧ ▸ 20168݄ϦϦʔε ▸ ༰ɿ ▸ 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/
Slide 4
Slide 4 text
ΞϝʔόϒϩάɾSPϦχϡʔΞϧ ISOMORPHIC APPLICATIONύʔϑΥʔϚϯεɾνϡʔχϯά ▸ όοΫΤϯυͷΩϟογϡ ▸ Ԇϩʔυ & ίʔυׂ ▸ Service Worker & ΞηοτͷϓϦΩϟογϡ)
Slide 5
Slide 5 text
όοΫΤϯυ ͷΩϟογϡʂ
Slide 6
Slide 6 text
όοΫΤϯυͷΩϟογϡ ͳͥόοΫΤϯυͷΩϟογϡ͕ॏཁͳͷ͔ - 1 ▸ SSRͷύϑΥʔϚϯε͕ྑ͘ͳ͍ʂ ▸ ݪҼɿैདྷSPA͚ͷٕज़ΛαʔόʔͰ࣮ݱ ϨϯμϦϯάॲཧ͕ෳࡶ Perf (SSR React) < Perf (Template, e.g. Handlebars.js)
Slide 7
Slide 7 text
ϨϯμϦϯάॲ ཧ͕ෳࡶͰɺαʔ όʔʹͱͬͯύ ϑΥʔϚϯε͕ ѱ͍
Slide 8
Slide 8 text
όοΫΤϯυͷΩϟογϡ ͳͥΩϟογϡ͕ॏཁͳͷ͔ - 2 ▸ αʔόʔͷύϑΥʔϚϯεಛʹॏཁ ▸ ཧ༝: ͯ͢ͷϢʔβʔʹαʔϏεΛఏڙ SPA͕ಈ͔ͳͯ͘ - Өڹൣғ֘ϢʔβʔͷΈ - ैདྷͷSSRͱ΄΅ಉ͘͡ӾཡͰ ͖Δɻ
Slide 9
Slide 9 text
όοΫΤϯυͷΩϟογϡ ͳͥΩϟογϡ͕ॏཁͳͷ͔ - 3 ▸ Ωϟογϡ͕ޮ͖͍͢ ▸ ཧ༝: SEOΛॏࢹ͢ΔӾཡܥͷγεςϜ ί͘Μɺί͘ΜɺISOMORPHICͷ͜ͱΛฉ͖͍ͨͰ͚͢Ͳ ͲΜͳγεςϜͰ͔͢ ͏ͪͷཧγεςϜͰ͢ ͑ͬͬʁʁͲ͏ͯ͠ISOMORPHICͳͷʁ ΧοίΠΠ͔Β ͦΕISOMORPHICΛΊͨ΄͏͕͍͍
Slide 10
Slide 10 text
όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Λચ͍ग़͢ ▸ ԿΛΩϟογϡ͢Δ ▸ Ωϟογϡอଘ͢ΔλΠϛϯά ▸ Ωϟογϡআ͢ΔλΠϛϯά ▸ Local Cache VS Cache Server
Slide 11
Slide 11 text
όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ ΞϝϒϩSSRͷྲྀΕ ▸ PathϚονϯάɺίϯϙωϯ τͱඞཁͳॲཧΛऔΓग़͢ ▸ Redux Store४උ: APIίʔϧ ΛؚΊɺඞཁͳσʔλॲཧ Λߦ͏‼ ▸ Redux Store + ReactDOMServer.renderTo String()‼ = HTML ▸ Q1. ԿΛΩϟογϡ͢Δ ߋ৽ස͕͍Object ReactDOMServer .renderToString() ͷ݁Ռ
Slide 12
Slide 12 text
όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ ԿΛΩϟογϡ͢Δ: ReactDOMServer.renderToString() ▸ ΫϥΠΤϯτʹΑͬͯಈతʹมΘΔ༰͕͋ΔͷͰɺੜ͞ΕͨHTMLΛͦͷ· ·͑ͳ͍ ReactDOMServer.renderToString() Template Create Template Template + Client Info (e.g. user-agent) = HTML Cache
Slide 13
Slide 13 text
όοΫΤϯυͷΩϟογϡ ͪͳΈʹ ▸ ΞϝϒϩͰҰ൪࠷ॳʹHTML(ReactDOMServer .renderToString) ͷΩϟογϡΛͪΌΜͱ࣮͕ͨ͠ɺAPI/ ObjectͷΩϟογϡʹ͍ͭͯ͋·Γॏࢹ͠ͳ͔ͬͨɻ ▸ 6݄ͷτϐοΫεͷ͖͔͚ͬͰAPI/ObjectΛਫ਼ࠪ͠ɺΩϟο γϡΛ͖ͪΜͱ࣮ͯ͠ɺ͔ͳΓྑ͍݁Ռ͕ग़ͨɻ
Slide 14
Slide 14 text
όοΫΤϯυͷΩϟογϡ ϐʔΫଳͷฏۉϨεϙϯελΠϜ Before: 26ms After: 17ms API/Object Cache࣮લޙͷൺֱ
Slide 15
Slide 15 text
όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q2. ΩϟογϡอଘλΠϛϯά ▸ ΞΫηε͢Δͱ͖ʹɺΩϟογϡ͕ݟ͔ͭΒͳ͔ͬͨΒɺ ॲཧͯ͠Ωϟογϡอଘ͢Δɻ
Slide 16
Slide 16 text
όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q3. ΩϟογϡআλΠϛϯά ▸ هࣄΛߋ৽͞ΕͨΒɺهࣄIDΛΒͬͯهࣄͷΩϟο γϡΛআ͢ΕOK ͜Εμϝʂʂ
Slide 17
Slide 17 text
όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Q3. Ωϟογϡ͔ΒআλΠϛϯά ▸ هࣄΛߋ৽͞ΕͨΒɺهࣄIDΛΒͬͯهࣄͷΩϟογϡΛআ͢ΕOK ʢ͜Εμϝʂʣ ▸ هࣄͷߋ৽ ˠɹهࣄϖʔδͷΩϟογϡΛআ ▸ هࣄͷߘ ˠɹهࣄҰཡͷΩϟογϡΛআ ˠɹهࣄৄࡉͷϦϯΫΛߋ৽͠ͳ͍ͱ͍͚ͳ͍ͷͰɺهࣄৄࡉͷΩϟογϡΛআ͢Δඞཁ͕͋Δ ▸ εΩϯɾϓϩϑΟʔϧͷߋ৽ ˠɹϒϩΨʔͷશϖʔδͷΩϟγϡΛআ ࣮ෳࡶʹͳΔ͠ɺ ສ͕ҰΩϟογϡͷআ͕࿙ΕͨΒɺ͜Θ͍ʂʂʂʂʂ
Slide 18
Slide 18 text
όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ 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
Slide 19
Slide 19 text
▸ Q3. Ωϟογϡ͔ΒআλΠϛϯά ▸ τϥϯβΫγϣϯ όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ߋ৽ user_a DELETE /cache? ameba_id = user_a user_b API Server Node.js Server Cache Ӿཡ Rendering Evict Cache /ameba_id Save Ωϟογϡআ ࣦഊʂ
Slide 20
Slide 20 text
▸ 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
Slide 21
Slide 21 text
όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ 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
Slide 22
Slide 22 text
όοΫΤϯυͷΩϟογϡ ΞϝϒϩͷόοΫΤϯυΩϟογϡͷઃܭ ▸ Ωϟογϡͷઃܭͷ·ͱΊ ▸ HTMLςϯϓϨʔτ + APIͷσʔλΩϟογϡ ▸ Namespace (AmebaId + Version) ͰΩϟογϡอଘɾΞ ΫςΟϒతͳআ(Versionߋ৽) ▸ On-memory cache + Cache Server 2֊
Slide 23
Slide 23 text
όοΫΤϯυͷΩϟογϡ Ξϝϒϩ όοΫΤϯυΩϟογϡͷશମਤ
Slide 24
Slide 24 text
όοΫΤϯυͷΩϟογϡ ݁Ռ1: NEW RELICͰهࣄৄࡉͷΩϟογϡঢ়گ Cache Hit!
Slide 25
Slide 25 text
όοΫΤϯυͷΩϟογϡ ݁Ռ2: NEW RELICͰهࣄҰཡͷΩϟογϡঢ়گ Cache Hit!
Slide 26
Slide 26 text
όοΫΤϯυͷΩϟογϡ ݁Ռ3: DATADOGͷMEMCACHED HIT RATE
Slide 27
Slide 27 text
Ԇϩʔυ LAZY LOAD
Slide 28
Slide 28 text
Ԇϩʔυ Ԇϩʔυ ▸ దͳλΠϛϯάͰదͳॲཧΛߦ͏ ▸ SSR → SPA ▸ ϖʔδͷ্ → ϖʔδͷԼ ▸ ίʔυͷԆධՁ: ίʔυׂ
Slide 29
Slide 29 text
Ԇϩʔυ Ԇϩʔυ: 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
Slide 30
Slide 30 text
Ԇϩʔυ Ԇϩʔυ: ϖʔδͷ্ → ϖʔδͷԼ
Slide 31
Slide 31 text
Ԇϩʔυ ͔ͤͬ͘αʔόʔ͔ΒϑϩϯτʹདྷͨͷͰɺ CHROME DEV TOOLͰύϑΥʔϚϯεΛΈͯΈΑ͏ʂ ϖʔδʹؔͳ͍Ϟ δϡʔϧϩʔυ͠ ͯ͠·ͬͯɺJSධՁ ͕࣌ؒ͘ͳͬͨ
Slide 32
Slide 32 text
ίʔυׂ ίʔυׂͷϝϦοτ ▸ ඞཁͳ͍ίϯϙωϯτΛϩʔυ͠ͳ͍Α͏ʹ ▸ JSධՁ͕࣌ؒ͘ͳΔ ▸ main.jsେԽΛ͙ ▸ ৽͍͠ػೳΛͲΜͲΜՃͯ͠OK
Slide 33
Slide 33 text
ίʔυׂ ίʔυׂͷํ๏ ▸ Webpack ▸ ׂཻɿAtomicσβΠϯ ͷ Organismsຖ ▸ ׂ͞ΕͨBundleͷαΠζΛݮΒ͢ϓϥάΠϯ ▸ ModuleConcatenationPlugin ▸ AggressiveMergingPlugin
Slide 34
Slide 34 text
ίʔυׂ ίʔυׂͷํ๏ɿWEBPACK ▸ https://webpack.js.org/guides/code-splitting ▸ require.ensure, bundle loader, Dynamic imports() ▸ ΞϝϒϩɿDynamic imports() Lazy Loadʹ͍ͨ͠߹: const loadExample = () => import(‘./ExampleComponent’)
Slide 35
Slide 35 text
ίʔυׂ ίʔυׂͷํ๏ɿཻ ▸ AtomicσβΠϯ: Organismsຖ هࣄҰཡTemplate AtomicσβΠϯ
Slide 36
Slide 36 text
ίʔυׂ ίʔυׂͷํ๏ɿཻ ▸ AtomσβΠϯ: Organisms୯Ґ هࣄҰཡTemplate rrr--lazyDynamic Import()ʹରԠࡁΈ
Slide 37
Slide 37 text
ίʔυׂ ݁Ռ1ɿ࣮ࡍͷಈ͖
Slide 38
Slide 38 text
ίʔυׂ ݁Ռ2ɿJSධՁ࣌ؒ
Slide 39
Slide 39 text
ίʔυׂ ίʔυׂͷҰ൪େ͖͍σϝϦοτ ▸ ݱ࣌ͰWebpackͷ࠶Ϗϧυ͕͔ͳΓ͍ʂ ▸ ϩʔΧϧͷ։ൃϞʔυͰίʔυΛमਖ਼ͨ͠Βɺ10s - 20s ͔͔Δ ▸ ղܾํ๏ɿϩʔΧϧͰίʔυׂΛແޮʹ͢Δ ▸ babel-plugin-dynamic-import-webpack babel-plugin-remove-webpack
Slide 40
Slide 40 text
ίʔυׂͯ͠ɺΞηοτ ͷαΠζΓେ͖͍ʂʂ
Slide 41
Slide 41 text
SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER ▸ લఏɿHTTPSʂ ▸ Ξϝϒϩ2017 – େنαʔϏεhttpsԽ ~ All GreenΛ ࢦͯ͠ ~ https://developers.cyberagent.co.jp/blog/archives/7743
Slide 42
Slide 42 text
SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER ▸ service-worker.jsΠϯετʔϧλΠϛϯά ▸ AMPϖʔδʹΞΫηε ▸ ΞϝϒϩSPϖʔδʹΞΫηε
Slide 43
Slide 43 text
SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER - ΤϯτϦ ▸ AMPϖʔδɿඞཁͳΞηοτΛϓϦϩʔυɾΩϟογϡ Install-service-worker.html service-worker.js (installer) service-worker.js (CDN) ΫϩευϝΠϯ importScripts Assets
Slide 44
Slide 44 text
SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER - ΤϯτϦ ▸ ΞϝϒϩSPϖʔδɿΞηοτΛΩϟογϡ service-worker.js (installer) service-worker.js (CDN) ΫϩευϝΠϯ importScripts Assets
Slide 45
Slide 45 text
SERVICE WORKER & ΞηοτͷϓϦΩϟογϡ) SERVICE WORKER - ࣮ ▸ Webpack + Workbox https://github.com/GoogleChrome/workbox
Slide 46
Slide 46 text
݁Ռʁ
Slide 47
Slide 47 text
No content
Slide 48
Slide 48 text
কདྷͷల কདྷͷల ▸ React 16 & SSR ▸ HTTP/2 & ίʔυׂ ▸ PWA & Service Worker
Slide 49
Slide 49 text
কདྷͷల REACT 16 & SSR ▸ Ұ൪ظ͍ͯ͠ΔͷSSRύϑΥʔϚϯεͷվળ React 15 ϚΠϯεϨουΛϒϩο Ϋ͞ΕΔͷͰɺ ݱࡏϚϧνϓϩηεͰ ϨϯμϦϯά͍ͯ͠Δ
Slide 50
Slide 50 text
কདྷͷల REACT 16 ▸ Ұ൪ظ͍ͯ͠ΔͷSSRύϑΥʔϚϯεͷվળ React 16
Slide 51
Slide 51 text
▸ ݱঢ়ɿChromeͳͲಉ࣌ʹૹ৴͢ΔϦΫΤετ6ͭ·Ͱ ʹ੍ݶ͞Ε͍ͯΔ͔Βɺׂ͞ΕͨJSϑΝΠϧΛಉ࣌ʹϩʔ υ͢ΔࡍʹϒϩοΫ͞Εͯ͠·͏ɻ ▸ ࠓޙɿHTTP/2 ετϦʔϜͷଟॏԽΛར༻͠ɺύϑΥʔϚϯ ε্ কདྷͷల HTTP/2 & ίʔυׂ
Slide 52
Slide 52 text
কདྷͷల PWA & SERVICE WORKER ▸ ݱঢ়: Service Worker = ϓϦΩϟογϡ ▸ ࠓޙ ▸ Add to Home Screen ▸ App ShellϞσϧ ▸ ΦϑϥΠϯϞʔυ ▸ ௨
Slide 53
Slide 53 text
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠