SlideShare a Scribd company logo
1 of 101
NodeJS Эффективное программирование  Юра Богданов технический директор и соучредитель Eventr
NodeJS ,[object Object],«Предоставить  естественную  неблокирующую ,  событийно-ориентированную инфраструктуру для написания программ с высокой конкурентностью» (с)  Ryan Dahl « to provide a purely evented, non-blocking infrastructure to script highly concurrent programs »
NodeJS ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Для чего   подходит NodeJS ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Event loop ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Время ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],I/O CPU
[object Object],[object Object],[object Object],Упрощенный пример сценария веб-приложения На самом деле, у нас много  I/O  и много логики
[object Object],[object Object],[object Object],CPU 30% I/O 70%
[object Object],[object Object],[object Object],I/O CPU занято монолит А что если...
Blocking I/O callback I/O I/O CPU CPU занято свободно Event Loop монолит А что если во время ожидания  I/O  заниматься друмиги полезными делами?
I/O Event loop Примерно так выглядит более реальный запрос: CPU+I/O
I/O CPU  callback I/O CPU Event loop Примерно так выглядит более реальный запрос:
Event loop Примерно так выглядит более реальный запрос: I/O CPU  Свободно для других задач callback I/O CPU
Event Loop mysql.query(‘SELECT count(*) FROM users’, function(err, count) { console.log(‘There are %d users in db’, count); }) console.log(‘Hello, ’); Отправка запроса в БД
Event Loop mysql.query(‘SELECT count(*) FROM users’, function(err, count) { console.log(‘There are %d users in db’, count); }) console.log(‘Hello, ’); Hello , Ожидание ответа БД...
Event Loop mysql.query(‘SELECT count(*) FROM users’, function(err, count) { console.log(‘There are %d users in db’, count); }) console.log(‘Hello, ’); Hello, There are 10231512 users in db Пришел ответ из БД
[object Object],[object Object],[object Object],db.query('SELECT * FROM users WHERE id=1’, function(err, user) {  // I/O 70ms var html = renderUser(user);  // CPU – 30ms })
[object Object],[object Object],[object Object],db.query('SELECT * FROM users WHERE id=1’,  function(err, user) {  // I/O 70ms var html = renderUser(user);  // CPU – 30ms } ) CPU 30% I/O 70%
Первый запрос Blocking I/O, 1  процесс
Второй запрос, после 10 ms ожидает выполнения первого Blocking I/O, 1  процесс
Третий запрос, после 50 ms ожидает выполнения первого и второго Blocking I/O, 1  процесс
Blocking I/O, 1  процесс Event loop, 1  процесс
Blocking I/O, 1  процесс Event loop, 1  процесс Время: 0 ms Пришел первый запрос, Запрашиваем  I/O,  освобождаемся , Ждем других запросов
Blocking I/O, 1  процесс Event loop, 1  процесс Время: 10 ms Пришел второй запрос, Запрашиваем  I/O,  освобождаемся , Ждем других запросов
Blocking I/O, 1  процесс Event loop, 1  процесс Время: 50 ms Пришел третий запрос, Запрашиваем  I/O,  освобождаемся , Ждем других запросов
Blocking I/O, 1  процесс Event loop, 1  процесс Время: 70 ms Пришел ответ на  I/O  первого запроса ,  запускаем  callback 1
Blocking I/O, 1  процесс Event loop, 1  процесс Время: 80 ms Пришел ответ на  I/O  второго запроса,  callback 2   ожидает  своей очереди
Blocking I/O, 1  процесс Event loop, 1  процесс Время: 1 0 0 ms с allback 1   завершился, запускаем  callback 2
Blocking I/O, 1  процесс Event loop, 1  процесс Время:  12 0 ms Пришел ответ на  I/O  третьего запроса,  callback 3   ожидает  своей очереди
Blocking I/O, 1  процесс Event loop, 1  процесс Время: 130 ms с allback 2   завершился, запускаем  callback 3
Blocking I/O, 1  процесс Event loop, 1  процесс Время: 160 ms callback 3   завершился Ждем других запросов
Время  CPU vs I/O RIA  трэнд
Приложение ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Приложение ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],require.paths.unshift(‘./library’) var MyModule = require(‘my_module’) var Sync = require(‘sync’)
Приложение ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],var MyModule = function() { // … } module.exports = MyModule
Приложение ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],require.paths.unshift(‘./library’) var MyModule = require(‘my_module’) var Sync = require(‘sync’) console.log(‘my module: ‘, MyModule);   +
Приложение ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],$ node my_app.js my module:  function (){}
Приложение ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],$ npm install mongoose
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Подключаем  HTTP  модуль
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Создаем  HTTP  сервер
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],«вешаем» сервер на 3080 порт
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Сервер создан, выводим сообщение
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Функция будет вызвана индивидуально для каждого запроса
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Отправляем  HTTP  заголовок
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Отправляем  HTTP  тело и закрываем сокет
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],$ node my_app.js
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],$ node my_app.js Server running at http://127.0.0.1:3080/
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],$ node my_app.js Server running at http://127.0.0.1:3080/ $ curl http://127.0.0.1:3080/
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],$ node my_app.js Server running at http://127.0.0.1:3080/ $ curl http://127.0.0.1:3080/ Hello, World $
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Hello  сразу,  World –  через 1 сек + + + +
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],$ node my_app.js Server running at http://127.0.0.1:3080/ $ curl http://127.0.0.1:3080/ Hello,
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],$ node my_app.js Server running at http://127.0.0.1:3080/ $ curl http://127.0.0.1:3080/ Hello, World! $ Через секунду
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Итератор, общий для всех запросов –  javascript  замыкание ( closure)
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],$ node my_app.js Server running at http://127.0.0.1:3080/ $ curl http://127.0.0.1:3080/ i = 0 $
HTTP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],$ node my_app.js Server running at http://127.0.0.1:3080/ $ curl http://127.0.0.1:3080/ i = 0 $ curl http://127.0.0.1:3080/ i = 1 $
Callback-driven  парадигма ,[object Object],[object Object],[object Object],[object Object],[object Object]
Callback-driven  парадигма function  asyncFunction ( arg1, arg2, argN,  callback ) { } Неблокирующая функция принимает  callback  последним аргументом
Callback-driven  парадигма function  asyncFunction ( arg1, arg2, argN,  callback ) { } function  callback ( err , result1, result2, resultN) { } Неблокирующая функция принимает  callback  последним аргументом Callback  принимает ошибку первым аргументом, остальные – результат
Callback-driven  парадигма function sum(a, b) { if (a > b) { throw new Error('a cannot be greater than b'); } return a + b; }
Callback-driven  парадигма function sum(a, b) { if (a > b) { throw new Error('a cannot be greater than b'); } return a + b; } f unction  asyncS um(a, b,  callback ) { if (a > b) { return callback(new Error('a cannot be greater than b')); } callback(null, a + b); } + + +
Callback-driven  парадигма function sum(a, b) { if (a > b) { throw new Error('a cannot be greater than b'); } return a + b; } f unction  asyncS um(a, b,  callback ) { if (a > b) { return callback(new Error('a cannot be greater than b')); } callback(null, a + b); } + + +
Callback-driven  парадигма try { var result = sum(2, 3); console.log('result = %d', result); } catch (err) { console.error(err); }
Callback-driven  парадигма try { var result = sum(2, 3); console.log('result = %d', result); } catch (err) { console.error(err); } asyncS um(2, 3, function(err, result){ if (err) return console.error(err); console.log('result = %d', result); }) + + +
Callback-driven  парадигма function getUser(id, callback) { }
Callback-driven  парадигма function getUser(id, callback) { } getUser(1234, function(err, user) { if (err) return console.error(err); console.log(‘user: ’, user); })
Callback-driven  парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); }) } + + +
Callback-driven  парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); dbConnect(config.host, function(err, db){ if (err) return callback(err); }) }) } + + +
Callback-driven  парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); dbConnect(config.host, function(err, db){ if (err) return callback(err); db.getUser(id, function(err, user){ if (err) return callback(err); callback(null, user); })  }) }) } + + + +
Callback-driven  парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); afterReadConfig(id, config, callback); }) } function afterReadConfig(id, config, callback) { dbConnect(config.host, function(err, db){ if (err) return callback(err); db.getUser(id, function(err, user){ …  }) } + + + + + + +
Callback-driven  парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); afterReadConfig(id, config, callback); }) } function afterReadConfig(id, config, callback) { dbConnect(config.host, function(err, db){ if (err) return callback(err); afterDbConnect(id, db, callback);   }) } function afterDbConnect(id, db, callback) … + +
Callback-driven  парадигма Error: User not found at afterDbConnect (/path/to/script.js:24:14) at /path/to/script.js:20:9 at dbConnect (/path/to/script.js:7:5) at afterReadConfig (/path/to/script.js:18:5) at /path/to/script.js:13:9 at readConfig (/path/to/script.js:3:5) at getUser (/path/to/script.js:11:5) at Object.<anonymous> (/path/to/script.js:28:1) at Module._compile (module.js:404:26) at Object..js (module.js:410:10)
Callback-driven  парадигма Error: User not found at  afterDbConnect  (/path/to/script.js:24:14) at /path/to/script.js:20:9 at  dbConnect  (/path/to/script.js:7:5) at  afterReadConfig  (/path/to/script.js:18:5) at /path/to/script.js:13:9 at  readConfig  (/path/to/script.js:3:5) at  getUser  (/path/to/script.js:11:5) at Object.<anonymous> (/path/to/script.js:28:1) at Module._compile (module.js:404:26) at Object..js (module.js:410:10)
Callback-driven  парадигма function getUser(id, callback) { readConfig(‘config.json’,  function(err, config){ if (err) return callback(err); afterReadConfig(id, config, callback); }) } function afterReadConfig(id, config, callback) { dbConnect(config.host,  function(err, db){ if (err) return callback(err); afterDbConnect(id, db, callback);  }) } function afterDbConnect(id, db, callback) … Синтаксический шум – плата за  Evented I/O
Callback-driven  парадигма function getUser(id, callback) { readConfig(‘config.json’,  function(err, config){ if (err) return callback(err); afterReadConfig(id, config, callback); }) } function afterReadConfig(id, config, callback) { dbConnect(config.host,  function(err, db){ if (err) return callback(err); afterDbConnect(id, db, callback);  }) } function afterDbConnect(id, db, callback) … Синтаксический шум – плата за  Evented I/O PROFIT PROFIT
node-sync Function.prototype.sync = function(context, arguments…) ,[object Object],[object Object],[object Object],https://github.com/ 0 ctave/node-sync https://github.com/ laverdet /node-fibers
var Sync = require(‘sync’); function getUser(id, callback) { Sync(function(){ var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.sync(db, id); return user; }, callback) } Запускаем новое «волокно» ( Fiber) node-sync
var Sync = require(‘sync’); function getUser(id, callback) { Sync(function(){ var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.sync(db, id); return user; }, callback) } «Волокно» вернет значение или ошибку в  callback node-sync
var Sync = require(‘sync’); function getUser(id, callback) { Sync(function(){ var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.sync(db, id); return user; }, callback) } Функция  readConfig  вызывается синхронно и возвращает значение node-sync
var Sync = require(‘sync’); function getUser(id) { var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.sync(db, id); return user; }.async() То же самое, только проще (коллбэка нет) node-sync
var Sync = require(‘sync’); function getUser(id) { var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.sync(db, id); return user; }.async() node-sync getUser(1234, function(err, user) { if (err) return console.error(err); console.log(‘user: ’, user); })
var Sync = require(‘sync’); function getUser(id) { var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); throw new Error(‘something went wrong’); return user; }.async() node-sync getUser(1234, function(err, user) { if (err) return console.error(err); console.log(‘user: ’, user); })
var Sync = require(‘sync’); function getUser(id) { var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.future(db, id); var friends = db.getUserFriends.future(db, id); return { user : user.result, friends : friends.result }; }.async() node-sync getUser  и  getUserFriends выполняются параллельно
var Sync = require(‘sync’); function getUser(id) { var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.future(db, id); db.getUserFriends(id, friends = new Sync.Future()); return { user : user.result, friends : friends.result }; }.async() node-sync другой способ получения «тикета»  future
Callback-driven  парадигма $pages = $db->fetchRows(‘SELECT * FROM pages’); foreach ($pages as $page) { $contents = fetchUrl($page->url); }
Callback-driven  парадигма $pages = $db->fetchRows(‘SELECT * FROM pages’); foreach ($pages as $page) { $contents = fetchUrl($page->url); } OK
Callback-driven  парадигма $pages = $db->fetchRows(‘SELECT * FROM pages’); foreach ($pages as $page) { $contents = fetchUrl($page->url); } db.fetchRows(‘SELECT * FROM pages’, function(err, pages){ pages.forEach(function(page){ fetchUrl(page.url, function(err, contents) { }) }) }); OK
Callback-driven  парадигма $pages = $db->fetchRows(‘SELECT * FROM pages’); foreach ($pages as $page) { $contents = fetchUrl($page->url); } db.fetchRows(‘SELECT * FROM pages’, function(err, pages){ pages.forEach(function(page){ fetchUrl(page.url, function(err, contents) { }) }) }); x 100,000 OK
Callback-driven  парадигма db.fetchRows(‘SELECT * FROM pages’, function(err, pages){ var narrow = new Narrow(10, function(page, callback){ fetchUrl(page.url, function(err, contents) { }) }) narrow.pushAll(pages); }); + + + https://github.com/ 0 ctave/node-narrow
Callback-driven  парадигма db.fetchRows(‘SELECT * FROM pages’, function(err, pages){ var narrow = new Narrow(10, function(page, callback){ fetchUrl(page.url, function(err, contents) { }) }) narrow.pushAll(pages); }); x10 - OK + + + x 100,000 - OK https://github.com/ 0 ctave/node-narrow
Callback - driven  решения? ,[object Object],[object Object],[object Object],[object Object],https://github.com/ 0 ctave/node-sync https://github.com/ Sage/streamlinejs https://github.com/caolan/async https://github.com/joyent/node/wiki/modules#async-flow http://www.scribd.com/doc/40366684/Nodejs-Controlling-Flow
Масштабирование Nodejs – is just node   (c)  Ryan Dahl
Масштабирование Nodejs – is just node   (c)  Ryan Dahl   1 ядро  CPU  = 1  nodejs  процесс
Масштабирование ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],https://github.com/LearnBoost/cluster
HTTP   Cluster ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Подключаем модуль  cluster https://github.com/LearnBoost/cluster
HTTP   Cluster ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Оборачиваем  http  сервер в кластер и «вешаем» на 3080 порт https://github.com/LearnBoost/cluster
HTTP   Cluster ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],Дополнительно выводим  PID https://github.com/LearnBoost/cluster
HTTP   Cluster ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],https://github.com/LearnBoost/cluster $ node my_app.js Server at http://127.0.0.1:3080/  (pid: 9254) Server at http://127.0.0.1:3080/  (pid: 9255) Server at http://127.0.0.1:3080/  (pid: 9256)
HTTP   Cluster ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],https://github.com/LearnBoost/cluster $ node my_app.js Server at http://127.0.0.1:3080/  (pid: 9254) Server at http://127.0.0.1:3080/  (pid: 9255) Server at http://127.0.0.1:3080/  (pid: 9256) $ curl http://127.0.0.1:3080/ Hello from  9255   $
HTTP   Cluster ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],https://github.com/LearnBoost/cluster $ node my_app.js Server at http://127.0.0.1:3080/  (pid: 9254) Server at http://127.0.0.1:3080/  (pid: 9255) Server at http://127.0.0.1:3080/  (pid: 9256) $ curl http://127.0.0.1:3080/ Hello from  9255   $ curl http://127.0.0.1:3080/ Hello from  925 6 $
NodeJS + Много  I/O Много Запросов + Event Loop = PROFIT
Юра Богданов https://github.com/ 0 ctave Github: http://twitter.com/ yuriybogdanov Twitter: http://about.me/ bogdanov About.me: [email_address] Email: http://linkedin.com/ in/yuriybogdanov LinkedIn: Спасибо за внимание .

More Related Content

What's hot

Industrial Programming Java - Lection Pack 01 - Building an application - Lav...
Industrial Programming Java - Lection Pack 01 - Building an application - Lav...Industrial Programming Java - Lection Pack 01 - Building an application - Lav...
Industrial Programming Java - Lection Pack 01 - Building an application - Lav...Fedor Lavrentyev
 
Школа-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиШкола-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиГлеб Тарасов
 
Yii development
Yii developmentYii development
Yii developmentMageCloud
 
Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Яковенко Кирилл
 
Web осень 2013 лекция 1
Web осень 2013 лекция 1Web осень 2013 лекция 1
Web осень 2013 лекция 1Technopark
 
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...zfconfua
 
Web осень 2013 лекция 9
Web осень 2013 лекция 9Web осень 2013 лекция 9
Web осень 2013 лекция 9Technopark
 
Stream API: рекомендации лучших собаководов
Stream API: рекомендации лучших собаководовStream API: рекомендации лучших собаководов
Stream API: рекомендации лучших собаководовtvaleev
 
Игорь Любин - PowerShell - ConfeT&QA 2011
Игорь Любин - PowerShell - ConfeT&QA 2011Игорь Любин - PowerShell - ConfeT&QA 2011
Игорь Любин - PowerShell - ConfeT&QA 2011ilyubin
 
Web осень 2013 лекция 7
Web осень 2013 лекция 7Web осень 2013 лекция 7
Web осень 2013 лекция 7Technopark
 
Java весна 2013 лекция 8
Java весна 2013 лекция 8Java весна 2013 лекция 8
Java весна 2013 лекция 8Technopark
 
Распределенные системы в Одноклассниках
Распределенные системы в ОдноклассникахРаспределенные системы в Одноклассниках
Распределенные системы в Одноклассникахodnoklassniki.ru
 
Web осень 2013 лекция 8
Web осень 2013 лекция 8Web осень 2013 лекция 8
Web осень 2013 лекция 8Technopark
 
Web осень 2013 лекция 4
Web осень 2013 лекция 4Web осень 2013 лекция 4
Web осень 2013 лекция 4Technopark
 
Влад Ковташ — Yap Database
Влад Ковташ — Yap DatabaseВлад Ковташ — Yap Database
Влад Ковташ — Yap DatabaseCocoaHeads
 
Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...
Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...
Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...Fedor Lavrentyev
 
Java осень 2012 лекция 8
Java осень 2012 лекция 8Java осень 2012 лекция 8
Java осень 2012 лекция 8Technopark
 
Java tricks for high-load server programming
Java tricks for high-load server programmingJava tricks for high-load server programming
Java tricks for high-load server programmingAndrei Pangin
 
Расширенное кеширование в Doctrine2
Расширенное кеширование в Doctrine2Расширенное кеширование в Doctrine2
Расширенное кеширование в Doctrine2Ilyas Salikhov
 
Незаурядная Java как инструмент разработки высоконагруженного сервера
Незаурядная Java как инструмент разработки высоконагруженного сервераНезаурядная Java как инструмент разработки высоконагруженного сервера
Незаурядная Java как инструмент разработки высоконагруженного сервераodnoklassniki.ru
 

What's hot (20)

Industrial Programming Java - Lection Pack 01 - Building an application - Lav...
Industrial Programming Java - Lection Pack 01 - Building an application - Lav...Industrial Programming Java - Lection Pack 01 - Building an application - Lav...
Industrial Programming Java - Lection Pack 01 - Building an application - Lav...
 
Школа-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиШкола-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с данными
 
Yii development
Yii developmentYii development
Yii development
 
Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3
 
Web осень 2013 лекция 1
Web осень 2013 лекция 1Web осень 2013 лекция 1
Web осень 2013 лекция 1
 
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
 
Web осень 2013 лекция 9
Web осень 2013 лекция 9Web осень 2013 лекция 9
Web осень 2013 лекция 9
 
Stream API: рекомендации лучших собаководов
Stream API: рекомендации лучших собаководовStream API: рекомендации лучших собаководов
Stream API: рекомендации лучших собаководов
 
Игорь Любин - PowerShell - ConfeT&QA 2011
Игорь Любин - PowerShell - ConfeT&QA 2011Игорь Любин - PowerShell - ConfeT&QA 2011
Игорь Любин - PowerShell - ConfeT&QA 2011
 
Web осень 2013 лекция 7
Web осень 2013 лекция 7Web осень 2013 лекция 7
Web осень 2013 лекция 7
 
Java весна 2013 лекция 8
Java весна 2013 лекция 8Java весна 2013 лекция 8
Java весна 2013 лекция 8
 
Распределенные системы в Одноклассниках
Распределенные системы в ОдноклассникахРаспределенные системы в Одноклассниках
Распределенные системы в Одноклассниках
 
Web осень 2013 лекция 8
Web осень 2013 лекция 8Web осень 2013 лекция 8
Web осень 2013 лекция 8
 
Web осень 2013 лекция 4
Web осень 2013 лекция 4Web осень 2013 лекция 4
Web осень 2013 лекция 4
 
Влад Ковташ — Yap Database
Влад Ковташ — Yap DatabaseВлад Ковташ — Yap Database
Влад Ковташ — Yap Database
 
Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...
Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...
Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...
 
Java осень 2012 лекция 8
Java осень 2012 лекция 8Java осень 2012 лекция 8
Java осень 2012 лекция 8
 
Java tricks for high-load server programming
Java tricks for high-load server programmingJava tricks for high-load server programming
Java tricks for high-load server programming
 
Расширенное кеширование в Doctrine2
Расширенное кеширование в Doctrine2Расширенное кеширование в Doctrine2
Расширенное кеширование в Doctrine2
 
Незаурядная Java как инструмент разработки высоконагруженного сервера
Незаурядная Java как инструмент разработки высоконагруженного сервераНезаурядная Java как инструмент разработки высоконагруженного сервера
Незаурядная Java как инструмент разработки высоконагруженного сервера
 

Similar to Эффективное программирование на NodeJS

Встреча №8. RESTful клиент — это просто. Тонкости использования RestKit, Миха...
Встреча №8. RESTful клиент — это просто. Тонкости использования RestKit, Миха...Встреча №8. RESTful клиент — это просто. Тонкости использования RestKit, Миха...
Встреча №8. RESTful клиент — это просто. Тонкости использования RestKit, Миха...CocoaHeads
 
Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0matroskin1980
 
iOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationiOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationAndrii Dzynia
 
Изоморфные приложения и Python - Виталий Глибин, Huntflow
Изоморфные приложения и Python - Виталий Глибин, HuntflowИзоморфные приложения и Python - Виталий Глибин, Huntflow
Изоморфные приложения и Python - Виталий Глибин, Huntflowit-people
 
Mobile automation uamobile
Mobile automation uamobileMobile automation uamobile
Mobile automation uamobileUA Mobile
 
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...Vadim Kruchkov
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПЧуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПKirill Chebunin
 
Cоздание приложений со знанием Perl
Cоздание приложений со знанием PerlCоздание приложений со знанием Perl
Cоздание приложений со знанием PerlAnatoly Sharifulin
 
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...Ontico
 
PHP 5.4: Что нового?
PHP 5.4: Что нового?PHP 5.4: Что нового?
PHP 5.4: Что нового?phpdevby
 
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...Timur Shemsedinov
 
Building corporate portals with liferay JEEConf 2011
Building corporate portals with liferay   JEEConf 2011Building corporate portals with liferay   JEEConf 2011
Building corporate portals with liferay JEEConf 2011Alexey Kakunin
 
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)Ontico
 
Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2Oleksii Okhrymenko
 

Similar to Эффективное программирование на NodeJS (20)

Встреча №8. RESTful клиент — это просто. Тонкости использования RestKit, Миха...
Встреча №8. RESTful клиент — это просто. Тонкости использования RestKit, Миха...Встреча №8. RESTful клиент — это просто. Тонкости использования RestKit, Миха...
Встреча №8. RESTful клиент — это просто. Тонкости использования RestKit, Миха...
 
Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0
 
Почему Mojolicious?
Почему Mojolicious?Почему Mojolicious?
Почему Mojolicious?
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Devcamp nodejs-2010
Devcamp nodejs-2010Devcamp nodejs-2010
Devcamp nodejs-2010
 
iOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationiOS and Android Mobile Test Automation
iOS and Android Mobile Test Automation
 
Изоморфные приложения и Python - Виталий Глибин, Huntflow
Изоморфные приложения и Python - Виталий Глибин, HuntflowИзоморфные приложения и Python - Виталий Глибин, Huntflow
Изоморфные приложения и Python - Виталий Глибин, Huntflow
 
DDOS mitigation software solutions
DDOS mitigation software solutionsDDOS mitigation software solutions
DDOS mitigation software solutions
 
Mobile automation uamobile
Mobile automation uamobileMobile automation uamobile
Mobile automation uamobile
 
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПЧуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОП
 
Cоздание приложений со знанием Perl
Cоздание приложений со знанием PerlCоздание приложений со знанием Perl
Cоздание приложений со знанием Perl
 
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
 
PHP 5.4: Что нового?
PHP 5.4: Что нового?PHP 5.4: Что нового?
PHP 5.4: Что нового?
 
Crazy owl yii1=> yii2
Crazy owl yii1=> yii2Crazy owl yii1=> yii2
Crazy owl yii1=> yii2
 
бегун
бегунбегун
бегун
 
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...
 
Building corporate portals with liferay JEEConf 2011
Building corporate portals with liferay   JEEConf 2011Building corporate portals with liferay   JEEConf 2011
Building corporate portals with liferay JEEConf 2011
 
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
 
Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2
 

Эффективное программирование на NodeJS

  • 1. NodeJS Эффективное программирование Юра Богданов технический директор и соучредитель Eventr
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10. Blocking I/O callback I/O I/O CPU CPU занято свободно Event Loop монолит А что если во время ожидания I/O заниматься друмиги полезными делами?
  • 11. I/O Event loop Примерно так выглядит более реальный запрос: CPU+I/O
  • 12. I/O CPU callback I/O CPU Event loop Примерно так выглядит более реальный запрос:
  • 13. Event loop Примерно так выглядит более реальный запрос: I/O CPU Свободно для других задач callback I/O CPU
  • 14. Event Loop mysql.query(‘SELECT count(*) FROM users’, function(err, count) { console.log(‘There are %d users in db’, count); }) console.log(‘Hello, ’); Отправка запроса в БД
  • 15. Event Loop mysql.query(‘SELECT count(*) FROM users’, function(err, count) { console.log(‘There are %d users in db’, count); }) console.log(‘Hello, ’); Hello , Ожидание ответа БД...
  • 16. Event Loop mysql.query(‘SELECT count(*) FROM users’, function(err, count) { console.log(‘There are %d users in db’, count); }) console.log(‘Hello, ’); Hello, There are 10231512 users in db Пришел ответ из БД
  • 17.
  • 18.
  • 19. Первый запрос Blocking I/O, 1 процесс
  • 20. Второй запрос, после 10 ms ожидает выполнения первого Blocking I/O, 1 процесс
  • 21. Третий запрос, после 50 ms ожидает выполнения первого и второго Blocking I/O, 1 процесс
  • 22. Blocking I/O, 1 процесс Event loop, 1 процесс
  • 23. Blocking I/O, 1 процесс Event loop, 1 процесс Время: 0 ms Пришел первый запрос, Запрашиваем I/O, освобождаемся , Ждем других запросов
  • 24. Blocking I/O, 1 процесс Event loop, 1 процесс Время: 10 ms Пришел второй запрос, Запрашиваем I/O, освобождаемся , Ждем других запросов
  • 25. Blocking I/O, 1 процесс Event loop, 1 процесс Время: 50 ms Пришел третий запрос, Запрашиваем I/O, освобождаемся , Ждем других запросов
  • 26. Blocking I/O, 1 процесс Event loop, 1 процесс Время: 70 ms Пришел ответ на I/O первого запроса , запускаем callback 1
  • 27. Blocking I/O, 1 процесс Event loop, 1 процесс Время: 80 ms Пришел ответ на I/O второго запроса, callback 2 ожидает своей очереди
  • 28. Blocking I/O, 1 процесс Event loop, 1 процесс Время: 1 0 0 ms с allback 1 завершился, запускаем callback 2
  • 29. Blocking I/O, 1 процесс Event loop, 1 процесс Время: 12 0 ms Пришел ответ на I/O третьего запроса, callback 3 ожидает своей очереди
  • 30. Blocking I/O, 1 процесс Event loop, 1 процесс Время: 130 ms с allback 2 завершился, запускаем callback 3
  • 31. Blocking I/O, 1 процесс Event loop, 1 процесс Время: 160 ms callback 3 завершился Ждем других запросов
  • 32. Время CPU vs I/O RIA трэнд
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57. Callback-driven парадигма function asyncFunction ( arg1, arg2, argN, callback ) { } Неблокирующая функция принимает callback последним аргументом
  • 58. Callback-driven парадигма function asyncFunction ( arg1, arg2, argN, callback ) { } function callback ( err , result1, result2, resultN) { } Неблокирующая функция принимает callback последним аргументом Callback принимает ошибку первым аргументом, остальные – результат
  • 59. Callback-driven парадигма function sum(a, b) { if (a > b) { throw new Error('a cannot be greater than b'); } return a + b; }
  • 60. Callback-driven парадигма function sum(a, b) { if (a > b) { throw new Error('a cannot be greater than b'); } return a + b; } f unction asyncS um(a, b, callback ) { if (a > b) { return callback(new Error('a cannot be greater than b')); } callback(null, a + b); } + + +
  • 61. Callback-driven парадигма function sum(a, b) { if (a > b) { throw new Error('a cannot be greater than b'); } return a + b; } f unction asyncS um(a, b, callback ) { if (a > b) { return callback(new Error('a cannot be greater than b')); } callback(null, a + b); } + + +
  • 62. Callback-driven парадигма try { var result = sum(2, 3); console.log('result = %d', result); } catch (err) { console.error(err); }
  • 63. Callback-driven парадигма try { var result = sum(2, 3); console.log('result = %d', result); } catch (err) { console.error(err); } asyncS um(2, 3, function(err, result){ if (err) return console.error(err); console.log('result = %d', result); }) + + +
  • 64. Callback-driven парадигма function getUser(id, callback) { }
  • 65. Callback-driven парадигма function getUser(id, callback) { } getUser(1234, function(err, user) { if (err) return console.error(err); console.log(‘user: ’, user); })
  • 66. Callback-driven парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); }) } + + +
  • 67. Callback-driven парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); dbConnect(config.host, function(err, db){ if (err) return callback(err); }) }) } + + +
  • 68. Callback-driven парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); dbConnect(config.host, function(err, db){ if (err) return callback(err); db.getUser(id, function(err, user){ if (err) return callback(err); callback(null, user); }) }) }) } + + + +
  • 69. Callback-driven парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); afterReadConfig(id, config, callback); }) } function afterReadConfig(id, config, callback) { dbConnect(config.host, function(err, db){ if (err) return callback(err); db.getUser(id, function(err, user){ … }) } + + + + + + +
  • 70. Callback-driven парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); afterReadConfig(id, config, callback); }) } function afterReadConfig(id, config, callback) { dbConnect(config.host, function(err, db){ if (err) return callback(err); afterDbConnect(id, db, callback); }) } function afterDbConnect(id, db, callback) … + +
  • 71. Callback-driven парадигма Error: User not found at afterDbConnect (/path/to/script.js:24:14) at /path/to/script.js:20:9 at dbConnect (/path/to/script.js:7:5) at afterReadConfig (/path/to/script.js:18:5) at /path/to/script.js:13:9 at readConfig (/path/to/script.js:3:5) at getUser (/path/to/script.js:11:5) at Object.<anonymous> (/path/to/script.js:28:1) at Module._compile (module.js:404:26) at Object..js (module.js:410:10)
  • 72. Callback-driven парадигма Error: User not found at afterDbConnect (/path/to/script.js:24:14) at /path/to/script.js:20:9 at dbConnect (/path/to/script.js:7:5) at afterReadConfig (/path/to/script.js:18:5) at /path/to/script.js:13:9 at readConfig (/path/to/script.js:3:5) at getUser (/path/to/script.js:11:5) at Object.<anonymous> (/path/to/script.js:28:1) at Module._compile (module.js:404:26) at Object..js (module.js:410:10)
  • 73. Callback-driven парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); afterReadConfig(id, config, callback); }) } function afterReadConfig(id, config, callback) { dbConnect(config.host, function(err, db){ if (err) return callback(err); afterDbConnect(id, db, callback); }) } function afterDbConnect(id, db, callback) … Синтаксический шум – плата за Evented I/O
  • 74. Callback-driven парадигма function getUser(id, callback) { readConfig(‘config.json’, function(err, config){ if (err) return callback(err); afterReadConfig(id, config, callback); }) } function afterReadConfig(id, config, callback) { dbConnect(config.host, function(err, db){ if (err) return callback(err); afterDbConnect(id, db, callback); }) } function afterDbConnect(id, db, callback) … Синтаксический шум – плата за Evented I/O PROFIT PROFIT
  • 75.
  • 76. var Sync = require(‘sync’); function getUser(id, callback) { Sync(function(){ var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.sync(db, id); return user; }, callback) } Запускаем новое «волокно» ( Fiber) node-sync
  • 77. var Sync = require(‘sync’); function getUser(id, callback) { Sync(function(){ var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.sync(db, id); return user; }, callback) } «Волокно» вернет значение или ошибку в callback node-sync
  • 78. var Sync = require(‘sync’); function getUser(id, callback) { Sync(function(){ var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.sync(db, id); return user; }, callback) } Функция readConfig вызывается синхронно и возвращает значение node-sync
  • 79. var Sync = require(‘sync’); function getUser(id) { var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.sync(db, id); return user; }.async() То же самое, только проще (коллбэка нет) node-sync
  • 80. var Sync = require(‘sync’); function getUser(id) { var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.sync(db, id); return user; }.async() node-sync getUser(1234, function(err, user) { if (err) return console.error(err); console.log(‘user: ’, user); })
  • 81. var Sync = require(‘sync’); function getUser(id) { var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); throw new Error(‘something went wrong’); return user; }.async() node-sync getUser(1234, function(err, user) { if (err) return console.error(err); console.log(‘user: ’, user); })
  • 82. var Sync = require(‘sync’); function getUser(id) { var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.future(db, id); var friends = db.getUserFriends.future(db, id); return { user : user.result, friends : friends.result }; }.async() node-sync getUser и getUserFriends выполняются параллельно
  • 83. var Sync = require(‘sync’); function getUser(id) { var config = readConfig.sync(null, ‘config.json’); var db = dbConnect.sync(null, config.host); var user = db.getUser.future(db, id); db.getUserFriends(id, friends = new Sync.Future()); return { user : user.result, friends : friends.result }; }.async() node-sync другой способ получения «тикета» future
  • 84. Callback-driven парадигма $pages = $db->fetchRows(‘SELECT * FROM pages’); foreach ($pages as $page) { $contents = fetchUrl($page->url); }
  • 85. Callback-driven парадигма $pages = $db->fetchRows(‘SELECT * FROM pages’); foreach ($pages as $page) { $contents = fetchUrl($page->url); } OK
  • 86. Callback-driven парадигма $pages = $db->fetchRows(‘SELECT * FROM pages’); foreach ($pages as $page) { $contents = fetchUrl($page->url); } db.fetchRows(‘SELECT * FROM pages’, function(err, pages){ pages.forEach(function(page){ fetchUrl(page.url, function(err, contents) { }) }) }); OK
  • 87. Callback-driven парадигма $pages = $db->fetchRows(‘SELECT * FROM pages’); foreach ($pages as $page) { $contents = fetchUrl($page->url); } db.fetchRows(‘SELECT * FROM pages’, function(err, pages){ pages.forEach(function(page){ fetchUrl(page.url, function(err, contents) { }) }) }); x 100,000 OK
  • 88. Callback-driven парадигма db.fetchRows(‘SELECT * FROM pages’, function(err, pages){ var narrow = new Narrow(10, function(page, callback){ fetchUrl(page.url, function(err, contents) { }) }) narrow.pushAll(pages); }); + + + https://github.com/ 0 ctave/node-narrow
  • 89. Callback-driven парадигма db.fetchRows(‘SELECT * FROM pages’, function(err, pages){ var narrow = new Narrow(10, function(page, callback){ fetchUrl(page.url, function(err, contents) { }) }) narrow.pushAll(pages); }); x10 - OK + + + x 100,000 - OK https://github.com/ 0 ctave/node-narrow
  • 90.
  • 91. Масштабирование Nodejs – is just node (c) Ryan Dahl
  • 92. Масштабирование Nodejs – is just node (c) Ryan Dahl 1 ядро CPU = 1 nodejs процесс
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100. NodeJS + Много I/O Много Запросов + Event Loop = PROFIT
  • 101. Юра Богданов https://github.com/ 0 ctave Github: http://twitter.com/ yuriybogdanov Twitter: http://about.me/ bogdanov About.me: [email_address] Email: http://linkedin.com/ in/yuriybogdanov LinkedIn: Спасибо за внимание .