• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content

Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Like this presentation? Why not share!

Building for Real Time - working with Asynchronous I/O by Grant Goodale

on

  • 1,644 views

Includes information on how Goodale and team built WordSquared (formerly scrabb.ly)

Includes information on how Goodale and team built WordSquared (formerly scrabb.ly)

Statistics

Views

Total Views
1,644
Views on SlideShare
1,644
Embed Views
0

Actions

Likes
0
Downloads
16
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />

Building for Real Time - working with Asynchronous I/O by Grant Goodale Building for Real Time - working with Asynchronous I/O by Grant Goodale Presentation Transcript

  • Building For Real Time Working with Asynchronous I/O November 8, 2010 grant@moreblinktag.com
  • Scrabb.ly http://scrabb.ly
  • Word2 Scrabb.ly http://scrabb.ly http://wordsquared.com
  • Real time, MMO-style word game. Hundreds of people playing at once. Every tile played is broadcast to everyone.
  • Peaked at 1,000 simultaneous players. 1,000 players × ~15 message a second = ~900,000 messages/minute. Over 50MM/hour.
  • Architecture: 1 node.js server, 0.5GB RAM. (Room to spare.) 1 MongoDB server, 2GB RAM. (Now more.) How?
  • Asynchronous I/O. The Reactor Pattern. Required reading: http://kegel.com/c10k.html Node.js (JavaScript), EventMachine (ruby), Twisted (Python), libevent (C++).
  • Before: Need multiple processes or threads for concurrency.
  • Async: The Hollywood Principle “Don’t call us, we’ll call you.”
  • Why not multithread / multiprocess? Memory usage and cost of context switching. At higher levels of concurrency ( higher than Word 2 ) can swamp ability to do useful work. MUCH contention on this topic.
  • Code
  • Questions? grant@moreblinktag.com twitter: @ggoodale
  • https://gist.github.com/667263 var net = require('net'), _ = require('./underscore-min')._; // Our active connections var connections = {}; var server = net.createServer(function(sock) { sock.setTimeout(0); sock.setEncoding("utf8"); connections[sock.remotePort] = sock; // Store a reference to the new client sock.on('data', function(data) { _.each(connections, function(receiver) { if (sock !== receiver) { receiver.write(data); } // Send new data to all other sockets }); }); sock.on('close', function() { delete connections[this.remotePort]; }); }); server.listen(8124, "0.0.0.0"); console.log("Server started");
  • https://gist.github.com/667257 var net = require('net'), fs = require('fs'), _ = require('./underscore-min')._; // Our active connections var connections = {}; var doc = fs.readFileSync('lyrics.txt', 'utf8').split(" "); var word = 0; var intervalId = null; var sing = function() { if ((word >= doc.length || _.size(connections) == 0) && intervalId != null) { clearInterval(intervalId); word = 0; intervalId = null; } else { _(connections).each(function(receiver) { receiver.write(doc[word] + " "); }); word++; } } var server = net.createServer(function(sock) { sock.setTimeout(0) sock.setEncoding("utf8"); connections[sock.remotePort] = sock; // Store a reference to the new client sock.on('data', function(data) { if (data.match(/^singn$/i) && !intervalId) { intervalId = setInterval(sing, 350); // Sing! } else { _.each(connections, function(receiver) { if (sock !== receiver) { receiver.write(data); } // Send new data to all other sockets }); } }); sock.on('close', function() { delete connections[this.remotePort]; }); }); server.listen(8124, "0.0.0.0"); console.log("Server started");
  • var net = require('net'), _ = require('./underscore-min')._; var connections = {}; var selectReceiver = function(sender) { var eligibleReceivers = _.select(connections, function(conn) { return (conn !== sender && !conn.gameData); }); return eligibleReceivers[Math.floor(Math.random() * eligibleReceivers.length)]; }; var judgeGame = function(player, word) { if (player.gameData == word.trim()) { player.write("BINGO! Your score is now " + ++player.score + "!n> "); } else { player.score = 0; player.write("nBUZZ! Your score is now zero.n> "); } delete player.gameData; clearTimeout(player.timerId); }; var server = net.createServer(function(sock) { https://gist.github.com/667264 sock.setTimeout(0); sock.setEncoding("utf8"); sock.score = 0; connections[sock.remotePort] = sock; sock.on('data', function(data) { if (this.gameData) { judgeGame(this, data); } else if (_.size(connections) > 1 && data.length > 1) { var receiver = selectReceiver(sock); receiver.gameData = data.slice(0,15).trim(); receiver.timerId = setTimeout(judgeGame, 5000, receiver, ''); receiver.write("nType "" + receiver.gameData + "" - you have 5 seconds!n> "); this.write("Word sent!n> "); } else { this.write("> "); } }); sock.on('close', function() { delete connections[this.remotePort]; if (this.timerId) { clearTimeout(this.timerId); } }); sock.write("Welcome to telephone! Send a player a word to type:n> "); }); server.listen(8124, "0.0.0.0"); console.log("Server started");