アメブロ: Isomprhicアプリケーションのパフォーマンス・チューニング
by
HOU Bin
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
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
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠