Server side JavaScript: going all the way
-
Upload
oleg-podsechin -
Category
Technology
-
view
7.727 -
download
0
description
Transcript of Server side JavaScript: going all the way
Server side JavaScript:going all the way
#rejectjs 29.09.11
/me
#startups#akshell#ringojs
#moscowjs#dailyjs
Node.js
Ideal use cases
– Real time apps, infrastructure duct tape
Badly suited for
– CRUD, command line tools, CPU heavy loads
Easy to get started with
– Difficult to get into production
Akshell NarwhalJS
RingoJS Wakanda
GPSEE
v8cgi
ServerJS Fragmentation
Node.js CommonJS Wakanda RingoJS v8cgi Narwhal Common Node Flussperfd Akshell GPSEE0
2000
4000
6000
8000
10000
12000
Project Followers
Group Members
Fo
llow
ers
Sync vs. Async
“async style is kicking sync style's ass”
sync is “on top of” async – a higher level of abstraction
Sync vs. Async
function add(callback) { http.get(url1, function(response1) { var part1 = response1.data; http.get(url2, function(response2) { var part2 = response2.data; callback(part1 + part2); } }}
Sync vs. Async
http.get(url1).data + http.get(url2).data
Interoperability
Pure JavaScript modules run anywhere Templating, parsing, formatting, encoding
Anything doing I/O exposes sync or async API Defines the interface exposed by higher level
packages
CommonJS /1
Assert Console System/1.0
CommonJS /2
Binary/B
IO/A Filesystem/A JSGI 0.3 HTTP Client /A Sockets/A Subprocess
common-node
Implements synchronous CommonJS proposals using node-fibers
Traceur to support latest language features Bridges the gap between platforms, sync and
async
What it's good for?
everything!
What's it actually good for?
Business logic
– Lots of state, fine grained error handling CRUD
– Java, Rails, PHP, Python Command line tools Cross platform portability
On Threads & Fibers
“Threads suck”
- Brendan Eich, creator of JavaScript
“Fibers introduce interleaving hazards — Any function call can cause a yield and then your closure invariants *may be* broken.”
- Kris Kowal, creator of CommonJS/Modules
Concurrency in JavaScript
“You shouldn’t think that event-based concurrency eliminates synchronization, or shared memory, or anything other than preemption”
- Sam Tobin-Hochstadt, member of the Ecma TC39 committee on JavaScript
fibers /1
Co routine implementation using libcoro
Co-operative multitasking
Implicit synchronization
fibers /2
Not a fork or a hack of Node
No wrapper script required
V8 Context and 64KB stack per fiber
Will run on Windows
Node.js
process[ closure
closure
t →
RingoJS (0.8)
process thread stack
processthread stack
t →
Common Node (fibers)
processfiber stack
fiber stack[
t →
Comparison
Node.js Common Node RingoJS
Process Count Single Single Multiple
State Closure Fiber Stack Thread Stack
Multitasking User (co-op) Library (co-op) OS (pre-empt)
Memory Usage Low Low High
“Jitter” High High Low
Internals - sleep
exports.sleep = function(milliseconds) {
var fiber = Fiber.current;
setTimeout(function() {
fiber.run();
}, milliseconds);
yield();
};
Internals – HttpClient /1
var req = http.request(options, function(r) {
fiber.run(r);
});
req.on('error', function(error) {
fiber.run(error);
});
this.guts.body.forEach(function(block) {
req.write(block.buffer || block);
});
req.end();
Internals – HttpClient /2
var result = yield();
if(result instanceof Error)
throw new Error(result.message);
return {
status: result.statusCode,
headers: result.headers,
body: new Stream(result)
};
Internals - IO
// on 'data', 'end', 'error'
// pause when draining
var listeners = attach(this.stream);
var data = yield();
detach(this.stream, listeners);
Examples
JSGI
exports.app = function(request) {
return {
status: 200,
headers: {},
body: ['Hello World!']
// openRaw(module.filename)
};
};
Spawn & Sleep
exports.app = function(request) {
spawn(function() {
sleep(10000);
console.log('Hello Server!');
});
return {
status: 200,
headers: {},
body: ['Hello Client!']
};
};
HTTP Proxy
var HttpClient = require('httpclient').HttpClient;
exports.app = function(req) {
req.url = 'http://nodejs.org';
return new HttpClient(req).finish();
};
Twitter Streaming /1
var stream = new TextStream( new HttpClient({
method: 'POST',
url: '...',
headers: {}
body: ['track='+system.args[4]],
timeout: 10000
}).finish().body);
Twitter Streaming /2
var line;
while(true) {
line = stream.readLine();
if(!line.length) break;
if(line.length > 1) {
var message = JSON.parse(line);
console.log(message.text);
}
}
Telnet Chat /1
var socket = require('socket');
var server = new socket.Socket();
var clients = [], client;
server.bind('localhost', 23);
Telnet Chat /2
while(true) {
clients.push(client = server.accept().getStream());
spawn(function() { var stream = client, line;
while((line = stream.read(null)).length) {
clients.forEach(function(c) {
if(stream != c)
c.write(line);
});
}
clients.splice(clients.indexOf(stream), 1);
});
}
Demo
telnet 10.0.0.97
Benchmarksab -n 50000 -c 50
hello-world
exports.app = function() {
return {
status: 200,headers: {
'Content-Type': 'text/plain'},body: ['Hello World!\n']
};
};
string-alloc
exports.app = function(request) {
for( var i = 1; i <= 50; i++)
b.decodeToString("ascii");return {
status: 200,headers: {},body: [b]
};
};
parse-json
exports.app = function(request) {
JSON.parse(json);
return {
status: 200,headers: {},body: [json]
};
};
static-file
exports.app = function() {
return {
status: 200,
headers: {},
body: openRaw('../README.md')
};
};
set-timeout
exports.app = function() {
sleep(100);
return {
status: 200,
headers: {},
body: []
};
};
Throughput
hello-world string-alloc parse-json static-file set-timeout0
1000
2000
3000
4000
5000
6000
Node.js
Common Node
RingoJS
SyncJS Fragmentation
Wakanda RingoJS v8cgi Narwhal Common Node Flussperfd Akshell GPSEE0
50
100
150
200
250
300
350
400
Project Followers
Group Members
Fo
llow
ers
Road map
common-utils tests in separate project narhwal-mongodb fork hns/stick fork higher level packages (see project wiki)
Contributing
Google “common node”
github.com/olegp/common-node/
npm -g install common-node