asynchronous php and real-time messaging

45
asynchronous

Upload: steve-rhoades

Post on 22-Apr-2015

3.158 views

Category:

Engineering


12 download

DESCRIPTION

With every major browser supporting WebSockets, HTML 5 has changed how we handle client to server communications. The high demand for real time client and server messaging has developers flocking away from PHP to languages such as Node.js. In this session we'll explore the libraries and extensions that make Asynchronous PHP possible and analyze the performance differences with Node.js. In addition we'll identify use cases and walk through examples of how Asynchronous PHP can handle everything from WebSockets and Message Queues to MySQL.

TRANSCRIPT

Page 1: Asynchronous PHP and Real-time Messaging

asynchronous

Page 2: Asynchronous PHP and Real-time Messaging

steve rhoadestwitter+github @steverhoades

Page 3: Asynchronous PHP and Real-time Messaging
Page 4: Asynchronous PHP and Real-time Messaging

Asynchronous PHP

Page 5: Asynchronous PHP and Real-time Messaging

page scraper$urls = ['www.amazon.com', ...]; !foreach($urls as $url) { $content = file_get_contents( "http://$url", false, $context );}

Page 6: Asynchronous PHP and Real-time Messaging

request timewww.amazon.com: 0.80137www.reddit.com: 0.21584www.hackernews.com: 1.80921www.google.com: 0.29365www.yahoo.com: 1.39217!

Total time in seconds: 4.51274

Page 7: Asynchronous PHP and Real-time Messaging

time

call 2

Netw

ork

call 1Ne

twork

call 3

Netw

ork

blocking i/o

Page 8: Asynchronous PHP and Real-time Messaging

* Assuming ~1GB/sec SSD source: https://gist.github.com/jboner/2841832

Send 1K bytes over Gbps network 0.01 ms

Read 4K randomly from SSD* 0.15 ms

Read 1 MB sequentially from memory 0.25 ms

Round trip within same datacenter 0.5 ms

Read 1 MB sequentially from SSD* 1 ms

Disk seek 10 ms

Read 1MB sequentially from disk 20 ms

Send packet CA->Netherlands->CA 150 ms

I/O is slow.

Page 9: Asynchronous PHP and Real-time Messaging

var urls = ['http://www.amazon.com', ...];!for(var i in urls) { http.get(urls[i], function(response) { var str = ''; response.on('data', function (chunk) { str += chunk; });! response.on('end', function () { // do something with data }); });}

page scraper

Page 10: Asynchronous PHP and Real-time Messaging

www.amazon.com: 0.75559www.reddit.com: 0.33153www.hackernews.com: 0.57661www.google.com: 0.48226www.yahoo.com: 0.23333!

Total time: 0.76421

request time

Page 11: Asynchronous PHP and Real-time Messaging

call 2call 1 call 3create

create

non-blocking i/o

create

time

resp

resp

resp

reqreq

req

Page 12: Asynchronous PHP and Real-time Messaging

$urls = ['www.amazon.com',...];!foreach($urls as $ip => $url) { // create a stream that returns immediately // STREAM_CLIENT_CONNECT _MUST_ be passed // STREAM_CLIENT_ASYNC_CONNECT says create connection // asynchronously $socket = stream_socket_client( "tcp://$ip:80", $errno, $errstr, 0, STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT ); // set stream as non-blocking with 0, default is 1 stream_set_blocking($socket, 0);! // sockets = read streams, requests = write streams $sockets[(int) $socket] = $socket; $requests[(int) $socket] = $socket; }

non-blocking i/o

Page 13: Asynchronous PHP and Real-time Messaging

while(!empty($sockets)) { //run loop $read = $sockets; $write = $requests; $except = NULL; ! // check the multiplexer for stream events $ready = stream_select($read, $write, $except, 0); foreach($read as $readFd) { // .. read } foreach($write as $writeFd) { // .. write } }

$urls = ['www.amazon.com',...];

foreach($urls as $ip => $url) { // create a stream that returns immediately // STREAM_CLIENT_CONNECT _MUST_ be passed // STREAM_CLIENT_ASYNC_CONNECT says create connection // asynchronously $socket = stream_socket_client( "tcp://$ip:80", $errno, $errstr, 0, STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT

// set stream as non-blocking with 0, default is 1 stream_set_blocking($socket, 0);

// sockets = read streams, requests = write streams $sockets[(int) $socket] = $socket; $requests[(int) $socket] = $socket;

non-blocking i/o

Page 14: Asynchronous PHP and Real-time Messaging

non-blocking i/owww.reddit.com: 0.18858www.hackernews.com: 0.37317www.google.com: 0.10562www.yahoo.com: 0.10172www.amazon.com: 0.68584!

Total time: 0.69041(PHP Blocking Example: 4.51274)

Page 15: Asynchronous PHP and Real-time Messaging

event-drivennon-blocking i/o

Igor Wiedler

Christopher Boden#reactphp

Page 16: Asynchronous PHP and Real-time Messaging

igorw/evenementEventEmitter

on($event, callable $listener)$this->on('pipe', array($this, 'handleEvent'));

emit($event, array $arguments = [])$this->emit('data', array($data, $this));

once($event, callable $listener)$this->once('init', array($this, 'configure'));

Page 17: Asynchronous PHP and Real-time Messaging

event loop

service request

dispatcher

ticknextTickfutureTick

demultiplexertimers & streams

event handlercallback

Page 18: Asynchronous PHP and Real-time Messaging

even

t loop

periodic timers$loop->addPeriodicTimer(1, function($timer) { echo "Yes, I am annoying =)" . PHP_EOL;});!

one off timers$loop->addTimer(1, function($timer) { echo "I'm a one off timer.” . PHP_EOL;});

interval in seconds

callback Timer object

// cancel that annoying timer $timer->cancel(); });

timers

Page 19: Asynchronous PHP and Real-time Messaging

STREAMSStream($stream, $loop) events:

data, close, error, drain

$readStream = new Stream(fopen($file,"r"),$loop);$readStream->on('data',function($data, $stream) { //do something with $data});

Page 20: Asynchronous PHP and Real-time Messaging

readableStream

writeableStreamemit->(‘pipe’)

STREAMS & PIPING

on->(‘drain’)resume()on->(‘data’)

write($data)end()

end()pause()

if $data > $limit

$readStream->pipe($writeStream);

Page 21: Asynchronous PHP and Real-time Messaging

Promises/A

states

“A promise represents the eventual value returned from the single completion of an operation.”

“once fulfilled or rejected the promise’s value shall not be changed”

pending, fulfilled, rejected

http://wiki.commonjs.org/wiki/Promises/A

Page 22: Asynchronous PHP and Real-time Messaging

working with a Promise $loop = React\EventLoop\Factory::create(); $factory = new React\Dns\Resolver\Factory(); $dns = $factory->create('8.8.8.8', $loop);! $dns ->resolve('github.com') ->then(function ($ip) { echo "Host: $ip\n"; } ); $loop->run();

Deferred

Page 23: Asynchronous PHP and Real-time Messaging

working with Promise\all()

$promises = array( $file1->read(), $file2->read());!Promise\all($promises)->then(function($v){});Promise\race($promises)->then(function($v){});Promise\some($promises, 4)->then(function($v){});

$file1 = new file('test_file.txt', "r", $loop);$file2 = new file('test_file2.txt', "r", $loop);

Page 24: Asynchronous PHP and Real-time Messaging

Server events:connection, error

SOCKETS

Connectionextends Stream

events: data, close, error, drain

$loop = React\EventLoop\Factory::create(); $socket = new React\Socket\Server($loop); !$socket->on('connection', function($conn) { echo $conn->getRemoteAddress() . " connected" . PHP_EOL; $conn->on('data', function($data) { echo "Data received for connection" . PHP_EOL; }); }); !$socket->listen(4000); $loop->run();

Page 25: Asynchronous PHP and Real-time Messaging

page scraper$factory = new React\Dns\Resolver\Factory();$dns = $factory->create('8.8.8.8', $loop);$urls = ['www.amazon.com',...];$msg = "GET / HTTP/1.0\r\nAccept: */*\r\n\r\n";!foreach($urls as $url) { $connector = new React\SocketClient\Connector($loop, $dns); $connector->create($url, 80)->then( function (React\Stream\Stream $stream) use ($msg){ $stream->write($msg); $stream->on('data', function($data, $stream) { // buffer data } ); $stream->on('end', function($stream) { // do something with the data $stream->close(); }); } );}$loop->run();

Page 26: Asynchronous PHP and Real-time Messaging

request timewww.reddit.com: 0.47400www.hackernews.com: 0.41715www.google.com: 0.16216www.yahoo.com: 0.15773www.amazon.com: 0.65287!

Total time: 0.69455(PHP Blocking Example: 4.51274)

Page 27: Asynchronous PHP and Real-time Messaging

Messaging

Page 28: Asynchronous PHP and Real-time Messaging

Messaging Techniques

polling long polling (hanging GET)

pre-

Page 29: Asynchronous PHP and Real-time Messaging

Messaging Techniques

long polling (hanging GET)

streaming

pre-

Page 30: Asynchronous PHP and Real-time Messaging

Server Sent Eventssupported by all major browsers

• automatically re-connects • uni-directional • send arbitrary events

var source = new EventSource('stream.php');

source.addEventListener('message', function(e) { console.log(e.data);}, false);

Page 31: Asynchronous PHP and Real-time Messaging

demoserver sent events

Page 32: Asynchronous PHP and Real-time Messaging

WebSocketssupported by all major browsers

• new URI schemes ws and wss • bi-directional, full-duplex • send messages independently

Page 33: Asynchronous PHP and Real-time Messaging

WebSocketssupported by all major browsers

• multiplayer games • chat applications • social streams • auctions

Page 34: Asynchronous PHP and Real-time Messaging

WebSockets APIsupported by all major browsers

var ws = new WebSocket("ws://www.websockets.org"); ws.onopen = function(e) { console.log("Connection open ..."); }; ws.onmessage = function(e) { console.log( "Received Message: " + e.data); }; ws.onclose = function(e) { console.log("Connection closed."); }; ws.send("Hello WebSockets!"); ws.close();

Page 35: Asynchronous PHP and Real-time Messaging

RatchetWebSocket Support for • HTTP Server • handles WebSockets • supports the WAMP 1.0 protocol

Page 36: Asynchronous PHP and Real-time Messaging

$socketServer = new React\Socket\Server($loop);$socketServer->listen('8080', '0.0.0.0');$websocketServer = new IoServer( new HttpServer( new WsServer( $myWsApp ) ), $socketServer, $loop);

RatchetWebSocket Server

onOpen($conn)

onClose($conn)

onError($from, $error)

onMessage($from, $msg)

Page 37: Asynchronous PHP and Real-time Messaging

demoweb sockets

Page 38: Asynchronous PHP and Real-time Messaging

WAMPWeb Application Messaging Protocol

autobahn.js

Remote Procedure Calls Publish & Subscribe

Page 39: Asynchronous PHP and Real-time Messaging

$socketServer = new React\Socket\Server($loop);$socketServer->listen(8080, '0.0.0.0');$wampServer = new IoServer( new HttpServer( new WsServer( new WampServer( $myWampApp ) ) ), $socketServer, $loop);

Ratchet

onCall($conn, $id, $topic, $params)

onPublish($conn, $topic, $event)

onSubscribe($conn, $topic)

onUnsubscribe($conn, $topic)

Page 40: Asynchronous PHP and Real-time Messaging

Ratchet$conn->callResult($id,$this->playerData);wamp connection

$topic->broadcast($event, array($conn->WAMP->sessionId));topic$conn->callError($id, $topic, 'You are not allowed to make calls');

Page 41: Asynchronous PHP and Real-time Messaging

demoWAMP

Page 42: Asynchronous PHP and Real-time Messaging

results based on: http://philsturgeon.uk/blog/2013/11/benchmarking-codswallop-nodejs-v-php

Page 43: Asynchronous PHP and Real-time Messaging

OTHER INTERESTING LIBRARIES:

AMP: dispatch blocking calls to worker threads.https://github.com/rdlowrey/Amp

INTERESTING READS:COOPERATIVE MULTI-TASKING USING COROUTINES IN PHPhttp://bit.ly/1nTAV4e - nikic

Page 44: Asynchronous PHP and Real-time Messaging

Q & A

http://socketo.me http://reactphp.org

Code Examples:https://github.com/steverhoades/drupalcampla

Page 45: Asynchronous PHP and Real-time Messaging

steve rhoadestwitter+github @steverhoades