View
770
Download
6
Category
Preview:
Citation preview
Изоморфные React-приложения:производительность и масштабирование
Денис Измайлов
Почему от классического Single Page Application необходимо отказаться?
Как изоморфные приложения отразятся на Вашей зарплате?
Что вы будете делатьна этих выходных?
Идеально1. React 14
2. webpack
3. ES6
4. Node.js
5. Express / koa
6. Isomorphic (Universal) apps
Часть 1
Web стал очень большим
Искусство
Разработка под Web
Наука
Раньше было просто• Создал страницу
• Добавил пару скриптов
• Отправил в Production
Раньше было просто
Сервер
Браузер
Раньше было просто
Сервер
Браузер
Делал всё
Раньше было просто
Сервер
Браузер- HTML - [CSS, JavaScript]
Делал всё
Это работало
Single PageApplications
(SPA)
Single Page Application
Сервер
Браузер
Single Page Application
Сервер
Браузер
Страница существует?Авторизация нужна? Доступ есть?
Single Page Application
Сервер
Браузер
Страница существует?Авторизация нужна? Доступ есть?
- Tiny HTML, [CSS] - JavaScript bundle
Single Page ApplicationПлюсы
• Легко начать • webpack
• <div id=“root” />
• React, Redux
• build
Single Page ApplicationПлюсы
• Легко начать
• Богатый функционал
webpack, <div id=“root” />, React, Redux
Single Page ApplicationПлюсы
• Легко начать
• Богатый функционал
• Быстро дорабатывать
webpack, <div id=“root” />, React, Redux
Single Page ApplicationПлюсы
• Легко начать
• Богатый функционал
• Быстро дорабатывать
• Отзывчивый UI
webpack, <div id=“root” />, React, Redux
Single Page ApplicationПлюсы
• Легко начать
• Богатый функционал
• Быстро дорабатывать
• Отзывчивый UI
• Удобно кэшировать
webpack, <div id=“root” />, React, Redux
- Wow. И не одного минуса?
Single Page ApplicationМинусы
• Долгая загрузка • JavaScript bundle up to 3-5 Mb
• первое обращение
• исполнение
• память
Single Page ApplicationМинусы
• Долгая загрузка
• Сложность поддержки
• side-эффекты
• memory leak
1st request, CPU, mem
Single Page ApplicationМинусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница, один URL
1st request, CPU, mem
side-эффекты, memory leaks
Single Page ApplicationМинусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница, один URL
• Legacy Browsers
1st request, CPU, mem
side-эффекты, memory leaks
- Разве это минусы?
Single Page ApplicationМинусы
• Долгая загрузка
для бизнеса
снижение UX
Single Page ApplicationМинусы
• Долгая загрузка
• Сложность поддержки
для бизнеса
снижение UX
риски
Single Page ApplicationМинусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница
для бизнеса
снижение UX
риски
проблемы SEO
Single Page ApplicationМинусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница
• Один URL
для бизнеса
снижение UX
риски
проблемы SEO
проблемы SMM
Single Page ApplicationМинусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница
• Один URL
• Legacy Browsers
для бизнеса
снижение UX
риски
проблемы SEO
проблемы SMM
потеря ЦА
Single Page ApplicationМинусы
• Долгая загрузка
• Сложность поддержки
• Пустая страница
• Один URL
• Legacy Browsers
для бизнеса
снижение UX
риски
проблемы SEO
проблемы SMM
потеря ЦА
Расходы
Single Page ApplicationМинусы
для бизнеса
снижение UX
риски
проблемы SEO
проблемы SMM
потеря ЦА
Расходы
- WAT? Что делать?
Взять лучшее из обоих миров
Изоморфные приложения
Изоморфные приложения
By isomorphic we mean that any given line of code (with notable exceptions) can execute both on the client and the server.
Charlie Robbins,18 Oct 2011
Шаблоны Стили Локализация Конфигурация Routes
Права доступа Модели Схемы Валидация Сервисы
Изоморфные приложения
server.jsNode.js
worker.js
client.jsBrowser
admin.js
Бизнес-логика Компоненты API-интерфейсы Actions, Reducers Static Files
Браузер
Изоморфные приложения
Front-end сервер
Back-end сервер
Database
Javaetc
Браузер
Изоморфные приложения
Front-end сервер
Back-end сервер
Database
Javaetc
Браузер
Изоморфные приложения
Front-end сервер
Back-end сервер
Database
Javaetc
- HTML - [critical CSS] - …
Front-end клиент
Изоморфные приложения
Front-end сервер
Back-end сервер
Database
Javaetc
- HTML - [critical CSS] - JS Bundle
Front-end клиент
Изоморфные приложения
Front-end сервер
Back-end сервер
Database
Javaetc
- HTML - [critical CSS] - JS Bundle
Front-end клиент
Изоморфные приложения
Front-end сервер
• Единая среда исполнения
• Общая кодовая база
• Полный контроль
• Экосистема
- Но как?
Server-Side Rendering(SSR)
Server-Side Rendering• Сборка React-приложения в HTML-код на Front-end сервере
• Моментальное отображение в браузере, ещё до загрузки JS
• Когда JS загрузится, React только добавит обработчики событий
• А это очень быстро
Server-Side RenderingКод на сервере выглядит очень просто:
import ReactDOMServer from 'react-dom/server';import Application from './components/application';const body = ReactDOMServer.renderToString( <Application />);
Server-Side Rendering1. Пользователь видит страницу
мгновенно
2. Отсутствие дополнительных запросов на получение данных
3. Страница может работать даже без JS
4. Полноценная URL-навигация и мета-тэги
5. Сохранение всех возможностей современного JavaScript
Часть 2
Производительность и масштабирование
Масштабирование
Масштабированиефункциональное
Server-Side RenderingВсё супер, когда данные есть:
import ReactDOMServer from 'react-dom/server';import Application from './components/application';const initialState = { siteName: 'HighLoad++ 2015' };const body = ReactDOMServer.renderToString( <Application state={initialState} />);
Server-Side RenderingВсё супер, когда данные есть:
import ReactDOMServer from 'react-dom/server';import Application from './components/application';const initialState = { siteName: 'HighLoad++ 2015' };const body = ReactDOMServer.renderToString( <Application state={initialState} />);
Но если их надо получать извне?
Server-Side RenderingКак получить асинхронный State:
1. Вручную для каждой страницы
2. Facebook Relay
3. redux-catch-promise
Асинхронный StateВручную для каждой страницы:
• Получить State, необходимый для страницы
• ReactDOMServer.renderToString()
Асинхронный StateFacebook Relay:
1. The framework for building data-driven React applications
2. Declarative. Colocation. Mutations.
3. https://github.com/facebook/relay/issues/136
4. 1Q2016
Асинхронный Stateredux-catch-promise:
• Redux - state container для React
• Redux: the best for isomorphic apps, MoscowJS 25https://youtu.be/Uyk_8WWna6s
• redux-catch-promise - это middleware для Redux
Асинхронный Stateredux-catch-promise:
1. Вешаем callback для захвата Promise-экшнов
2. Делаем рендер приложения
3. Делаем запрос к БД, диспатчим Promise
4. После рендера - имеем все эти промисы, ожидаем их завершения
5. Повторный рендер, с данными
Асинхронный Stateredux-catch-promise:
1. Примеры и исходный код:https://github.com/DenisIzmaylov/redux-catch-promise
2. Установка:
npm install redux-catch-promise
Производительность
Производительность
Тестовый стенд:
MacBook Pro 15” Retina (Early 2013)
2.4 GHz Intel Core i7
ПроизводительностьРазмер страницы: 56 238 байт
ПроизводительностьРазмер страницы: 56 238 байт
ПроизводительностьРазмер страницы: 56 238 байт
ПроизводительностьРазмер страницы: 56 238 байт
ПроизводительностьРазмер страницы: 56 238 байт
ПроизводительностьРазмер страницы: 56 238 байт
Производительность
Для теста используем:
ab -n 100 http://localhost:3000/profile
Производительность
Для теста используем:
ab -n 100 http://localhost:3000/profile
Запускаем…
Производительность
Для теста используем:
ab -n 100 http://localhost:3000/profile
Запускаем…
Time per request: 61.850 ms
Производительность
61.850 ms
Это много или мало?
Производительность
61.850 ms
Тот же шаблон в Handlebars:
8.385 ms
86% less
Производительность1. Идём в Google - ничего полезного.
2. Пробуем спросить Twitter - тишина:
Производительность
Ок, а что если?
NODE_ENV=production
Запускаем…
Производительность
Ок, а что если?
NODE_ENV=production
Запускаем…
Time per request: 37.943 ms(vs 61.850 ms)
39% less
Производительность
Вроде лучше.
Производительность
Вроде лучше.
Но всё ещё не торт.
Ищем дальше
GitHub issues
Производительность
• “Server rendering is slower with npm react”https://github.com/facebook/react/issues/812
Производительность
• “Server rendering is slower with npm react”https://github.com/facebook/react/issues/812Решение:явно подключать react/dist/react.min.js
ПроизводительностьСоздаём node_modules/react.js:if (process.env.NODE_ENV === 'production') {
module.exports = require('react/dist/react.min.js'); } else { module.exports = require('react/dist/react.js'); }
ПроизводительностьСоздаём node_modules/react.js:if (process.env.NODE_ENV === 'production') {
module.exports = require('react/dist/react.min.js'); } else { module.exports = require('react/dist/react.js'); }
Как это изменило результат?
Производительность
Server rendering is slower with npm react
react/dist/react.min.js
Запускаем…
Производительность
Server rendering is slower with npm react
react/dist/react.min.js
Запускаем…
Time per request: 38.253 ms(vs 37.943 ms)0.08% more
Производительность
Server rendering is slower with npm react
react/dist/react.min.js
Запускаем…
Time per request: 38.253 ms(vs 37.943 ms)0.08% moreFAILED
0
17,5
35
52,5
70
38,25337,943
8,385
61,85
React SSR Handlebars productionreact.js.min
Результаты
0
17,5
35
52,5
70
38,25337,943
8,385
61,85
React SSR Handlebars productionreact.js.min
Результаты39% less
Часть 3
Продвинутые решения
Продвинутые решения
1. Precompilation + Cache 2. Rendering Separation 3. React DOM Stream 4. Facebook BigPipe 5. HAProxy
Precompilation + Cache
• UI = f(state)
• f = React Component
• state = path + ...
Простое решение: redis
First render: redis + kue + workers
Rendering Separation
React DOM Stream
• Flushing the Document Early • “Streams make this library as much as 47%
faster in sending down a full page than ReactDOM.renderToString, and user perceived performance gains can be even greater.”
• Target - 108KB page on Heroku • Time To First Byte (TTFB) - 65% less • Time To Last Byte (TTLB) - 37% less • https://github.com/aickin/react-dom-stream
Facebook BigPipe• Сборка страницы в процессе загрузки • Загружается параллельно • Устойчивость к ошибкам
Facebook BigPipe• Сборка страницы на в процессе загрузки • Всё, что необходимо - загружается параллельно • Устойчивость к ошибкам
Facebook BigPipe
HAProxy
• Обратитесь к DevOps
• Несколько экземпляров
Заключение
Полезные материалы1. Supercharging page load (100 Days of Google Dev)
https://youtu.be/d5_6yHixpsQ
2. Making Netflix.com Faster http://techblog.netflix.com/2015/08/making-netflixcom-faster.html
3. New technologies for the new LinkedIn home page https://engineering.linkedin.com/frontend/new-technologies-new-linkedin-home-page
4. Improving performance on Twitter.com https://blog.twitter.com/2012/improving-performance-on-twittercom
5. Scaling Isomorphic Javascript Code http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/
Полезные материалы6. From AngularJS to React: The Isomorphic Way
https://blog.risingstack.com/from-angularjs-to-react-the-isomorphic-way/
7. Isomorphic JavaScript: The Future of Web Apps http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/
8. React server side rendering performance http://www.slideshare.net/nickdreckshage/react-meetup
9. The Lost Art of Progressive HTML Rendering http://blog.codinghorror.com/the-lost-art-of-progressive-html-rendering/
Рекомендации• Присоединяйтеськ сообществу MoscowJShttp://moscowjs.ru/
• Улучшайте английский, не читайте советских газет
• Читайте оригиналы и технические блоги
• Активно внедряйте в свою жизнь Twitter и GitHub
Послесловие
«Большинство проблем алгоритмов можно решить сменой структуры данных»,
Андрей Ситник
“Changes is our work”,Jake Archibald, Google
Почему от классического Single Page Application необходимо отказаться?
Спасибо за внимание
Денис Измайлов
@DenisIzmaylov
https://github.com/DenisIzmaylov
https://fb.com/denis.izmaylov
Приложение 1
Recommended