Successfully reported this slideshow.
Your SlideShare is downloading. ×

Realtime Communication Techniques with PHP

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
Socket programming with php
Socket programming with php
Loading in …3
×

Check these out next

1 of 62 Ad

More Related Content

Slideshows for you (20)

Advertisement

Similar to Realtime Communication Techniques with PHP (20)

Recently uploaded (20)

Advertisement

Realtime Communication Techniques with PHP

  1. 1. Realtime Communication Techniques with PHP Scott Mattocks & Chris Lewis, OnForce, Inc.
  2. 2. Agenda <ul><li>Introductions </li></ul><ul><li>Overview </li></ul><ul><ul><li>User expectations </li></ul></ul><ul><ul><li>Problems with delivery </li></ul></ul><ul><li>Techniques </li></ul><ul><ul><li>Refresh </li></ul></ul><ul><ul><li>Short Polling </li></ul></ul><ul><ul><li>Long Polling </li></ul></ul><ul><ul><li>WebSockets </li></ul></ul><ul><li>Q&A </li></ul>
  3. 3. Introductions <ul><li>Scott Mattocks </li></ul><ul><ul><li>Senior PHP developer at OnForce, Inc. </li></ul></ul><ul><ul><li>Contributor to PEAR </li></ul></ul><ul><ul><li>Author of Pro PHP-GTK </li></ul></ul><ul><li>Chris Lewis </li></ul><ul><ul><li>Senior PHP developer at OnForce, Inc. </li></ul></ul><ul><ul><li>6 years of enterprise PHP experience </li></ul></ul><ul><ul><li>12 years of front-end web development experience </li></ul></ul><ul><li>Both are contributors to the WaterSpout Real-time Communication Server </li></ul>
  4. 4. Overview <ul><li>Example: http://www.spoutserver.com </li></ul><ul><ul><li>Click “John Locke” in the Demos section </li></ul></ul>
  5. 5. Overview <ul><li>Users expect data to be delivered more quickly and seemlessly </li></ul><ul><ul><li>Gmail changed the way user expect to interact with websites </li></ul></ul><ul><li>Loading an entire page to show a small change is slow and wasteful </li></ul>
  6. 6. Problems with delivery <ul><li>The web runs (for the most part) on HTTP </li></ul><ul><ul><li>HTTP is one way </li></ul></ul><ul><ul><li>User asks for data </li></ul></ul><ul><ul><li>Server sends data back </li></ul></ul><ul><ul><li>The server can't do anything without the user asking first </li></ul></ul>
  7. 7. Problems with delivery <ul><li>Timeliness </li></ul><ul><ul><li>There is a gap between arrival of the data on the server and notification of the user. </li></ul></ul><ul><ul><li>We want to reduce the gap without killing the servers. </li></ul></ul>Client Server New Data New Data Black out
  8. 8. Problems with delivery <ul><li>Efficiency </li></ul><ul><ul><li>How much of the transfered data is important to the user? </li></ul></ul><ul><ul><li>Data transfer: </li></ul></ul><ul><ul><ul><li>X bytes sent for request (GET headers) </li></ul></ul></ul><ul><ul><ul><li>Y bytes sent for response (body and headers) </li></ul></ul></ul><ul><ul><ul><li>Z bytes of new data </li></ul></ul></ul><ul><ul><ul><li>Z / (X + Y) = efficiency </li></ul></ul></ul><ul><ul><li>We want try to send only the data that has changed and that is important to the user </li></ul></ul>
  9. 9. Problems with delivery <ul><li>Scalability </li></ul><ul><ul><li>What kind of load are we causing on the server? </li></ul></ul><ul><ul><li>Are we holding resources (i.e. database connections) that could be used to server other users? </li></ul></ul><ul><ul><li>We want to do more with less </li></ul></ul>
  10. 10. Solutions <ul><li>Refresh the page </li></ul><ul><li>Short Polling </li></ul><ul><li>Long Polling </li></ul><ul><ul><li>1 server </li></ul></ul><ul><ul><li>2 servers </li></ul></ul><ul><li>WebSockets </li></ul>
  11. 11. Solutions @gnomeboy want to come over for some cookies? @gnomegirl hellz yeah! <ul><li>Example: Simple twitter feed style page </li></ul>
  12. 12. Solutions <ul><li>Page consists of a wrapper around message content </li></ul><ul><ul><li>Avg message size = 100 bytes </li></ul></ul><ul><ul><li>Avg page size (without images) = 4 KB </li></ul></ul><ul><ul><li>Avg request headers = 410 bytes </li></ul></ul><ul><ul><li>Avg response headers = 210 bytes </li></ul></ul><ul><li>(JavaScript code examples use Prototype) </li></ul>
  13. 13. Refresh <ul><li>The same as if the user hit F5 </li></ul><ul><ul><li>Reloads the entire page </li></ul></ul><ul><ul><li>New page load adds the new message </li></ul></ul><ul><li>No constant connection to the server </li></ul><ul><ul><li>Black out periods between requests </li></ul></ul>
  14. 14. Refresh database web server web server
  15. 15. Refresh <ul><li>Difficulty </li></ul><ul><ul><li>1 out of 10 </li></ul></ul><ul><ul><li>Use HTML or JavaScript </li></ul></ul><ul><li><meta http-equiv=&quot;refresh&quot; content=&quot;5&quot; /> </li></ul><ul><li>setTimeout('window.location.reload(true)', 5000); </li></ul>
  16. 16. Refresh <ul><li>Timeliness </li></ul><ul><ul><li>Timeliness of data depends on the refresh rate </li></ul></ul><ul><ul><li>There is an additional delay for the round trip to the server </li></ul></ul><ul><ul><ul><li>Includes time to send request, process request, and send response </li></ul></ul></ul>
  17. 17. Refresh <ul><li>Efficiency (assume 10 total requests, 1 new message) </li></ul><ul><ul><li>Data transfer: </li></ul></ul><ul><ul><ul><li>410 bytes sent for each request </li></ul></ul></ul><ul><ul><ul><li>4210 bytes sent for each response, 4310 for new message response </li></ul></ul></ul><ul><ul><ul><li>100 bytes of new data </li></ul></ul></ul><ul><ul><ul><li>100 / ((410 + 4210) * 10 + 100) = .0021 per message </li></ul></ul></ul><ul><ul><li>Server resources used </li></ul></ul><ul><ul><ul><li>1 HTTP process per request (10 total) </li></ul></ul></ul><ul><ul><ul><li>1 Database connection per request (10 total) </li></ul></ul></ul>
  18. 18. Short Polling <ul><li>Ask the server for updates since the last time you asked </li></ul><ul><ul><li>Like a road trip with a 3 year old </li></ul></ul><ul><ul><li>Are we there yet? Are we there yet? </li></ul></ul><ul><li>No constant connection to the server </li></ul><ul><ul><li>Black out periods between requests </li></ul></ul><ul><ul><li>Cursor required to prevent data loss </li></ul></ul>
  19. 19. Short Polling database web server web server
  20. 20. Short Polling <ul><li>Difficulty </li></ul><ul><ul><li>5 out of 10 </li></ul></ul><ul><ul><li>AJAX </li></ul></ul><ul><ul><ul><li>Background request to the server checks for new messages at a timed interval </li></ul></ul></ul><ul><ul><ul><li>New messages are added to DOM by JavaScript </li></ul></ul></ul>
  21. 21. Short Polling function poll_server () { new Ajax. Request ( this .urlPolling, { method: 'post' , parameters: data, onSuccess: this .successHandler, onFailure: this .handleFailure, onException: this .handleException }); } setInterval ( 'poll_server()' , 5000 );
  22. 22. Short Polling function successHandler (trans, messages_div) { if (trans.responseText) { var json = trans.responseText. evalJSON (); if (json.message) { var msg = json.message + '<br />' ; $(messages_div). insert (msg); } } }
  23. 23. Short Polling function successHandler (trans, messages_div) { if (trans.responseText) { var json = trans.responseText. evalJSON (); if (json.message) { var msg = json.message + '<br />' ; $(messages_div). insert (msg); } } }
  24. 24. Short Polling <ul><li>Timeliness </li></ul><ul><ul><li>Timeliness of data depends on the refresh rate </li></ul></ul><ul><ul><li>There is an additional delay for the round trip to the server </li></ul></ul><ul><ul><ul><li>Includes time to send request, process request, and send response </li></ul></ul></ul>
  25. 25. Short Polling <ul><li>Efficiency (assume 10 total requests, 1 new message) </li></ul><ul><ul><li>Data transfer: </li></ul></ul><ul><ul><ul><li>410 bytes sent for each request </li></ul></ul></ul><ul><ul><ul><li>210 bytes sent for each empty response, 310 for new message response </li></ul></ul></ul><ul><ul><ul><li>100 bytes of new data </li></ul></ul></ul><ul><ul><ul><li>100 / ((410 + 210) * 10 + 100) = .0158 per message </li></ul></ul></ul><ul><ul><li>Server resources used </li></ul></ul><ul><ul><ul><li>1 HTTP process per request (10 total) </li></ul></ul></ul><ul><ul><ul><li>1 Database connection per request (10 total) </li></ul></ul></ul>
  26. 26. Long Polling - 1 server <ul><li>Ask the server for updates since the last time you asked </li></ul><ul><ul><li>Server does not respond until a new message has arrived </li></ul></ul><ul><li>No constant connection to the server </li></ul><ul><ul><li>Black out periods between sending response and next request </li></ul></ul><ul><ul><li>Cursor required to prevent data loss </li></ul></ul>
  27. 27. Long Polling – 1 server database web server web server
  28. 28. Long Polling – 1 server <ul><li>Difficulty – Client side </li></ul><ul><ul><li>5 out of 10 </li></ul></ul><ul><ul><li>AJAX </li></ul></ul><ul><ul><ul><li>Background request to the server checks for new messages and waits for responses </li></ul></ul></ul><ul><ul><ul><li>New messages are added to DOM by JavaScript </li></ul></ul></ul>
  29. 29. Long Polling – 1 server <ul><li>Difficulty – Server side </li></ul><ul><ul><li>5 out of 10 </li></ul></ul><ul><ul><li>Continuously loop checking for new messages </li></ul></ul><ul><ul><li>Break out of loop when new message arrives </li></ul></ul>
  30. 30. Long Polling – 1 server function poll_server () { new Ajax. Request ( this .urlPolling, { method: 'post' , parameters: data, onSuccess: this .successHandler, onFailure: this .handleFailure, onException: this .handleException }); } document. observe ( 'dom:loaded' , poll_server);
  31. 31. Long Polling – 1 server function successHandler (trans, messages_div) { if (trans.responseText) { var json = trans.responseText. evalJSON (); if (json.message) { var msg = json.message + '<br />' ; $(messages_div). insert (msg); } } poll_server (); }
  32. 32. Long Polling – 1 server <?php $query = 'SELECT message FROM messages WHERE dateadded > ?' ; $stmt = $pdo -> prepare ( $query ); while (true) { $message = $stmt -> execute ( $cursor_date ); if (! empty ( $message )) { echo json_encode ( $message ); break ; } } ?>
  33. 33. Long Polling – 1 server <ul><li>Timeliness </li></ul><ul><ul><li>Near real-time </li></ul></ul><ul><ul><li>As soon as a message shows up on the server, it is sent to the waiting client </li></ul></ul><ul><ul><li>Black out period between sending response and making new request can add some delay </li></ul></ul>
  34. 34. Long Polling – 1 server <ul><li>Efficiency (1 request, 1 new message) </li></ul><ul><ul><li>Data transfer: </li></ul></ul><ul><ul><ul><li>410 bytes sent for request </li></ul></ul></ul><ul><ul><ul><li>310 bytes for new message response </li></ul></ul></ul><ul><ul><ul><li>100 bytes of new data </li></ul></ul></ul><ul><ul><ul><li>100 / (410 + 310) = .138 per message </li></ul></ul></ul><ul><ul><li>Server resources used </li></ul></ul><ul><ul><ul><li>1 HTTP process </li></ul></ul></ul><ul><ul><ul><li>1 Database connection </li></ul></ul></ul>
  35. 35. Long Polling – 2 servers <ul><li>2 servers work together to use fewer resources </li></ul><ul><ul><li>Main web server handles initial page request </li></ul></ul><ul><ul><li>Main server informs polling server when new message arrives </li></ul></ul><ul><ul><li>Polling server informs client </li></ul></ul><ul><li>No constant connection to server </li></ul><ul><ul><li>Black out periods between sending response and next request </li></ul></ul><ul><ul><li>Cursor required to prevent data loss </li></ul></ul>
  36. 36. Long Polling – 2 servers web server polling server HTTP XHR over HTTP
  37. 37. Long Polling – 2 servers <ul><li>Difficulty – Client side </li></ul><ul><ul><li>5 out of 10 </li></ul></ul><ul><ul><li>AJAX </li></ul></ul><ul><ul><ul><li>Background request to the server checks for new messages and waits for responses </li></ul></ul></ul><ul><ul><ul><li>New messages are added to DOM by JavaScript </li></ul></ul></ul>
  38. 38. Long Polling – 2 servers <ul><li>Difficulty – Server side </li></ul><ul><ul><li>8 out of 10 </li></ul></ul><ul><ul><li>Web server makes cURL call to polling server when a new message is added </li></ul></ul><ul><ul><li>Polling server determines who message is for and sends the response to the waiting connection </li></ul></ul>
  39. 39. Long Polling – 2 servers function poll_server () { new Ajax. Request ( this .urlPolling, { method: 'post' , parameters: data, onSuccess: this .successHandler, onFailure: this .handleFailure, onException: this .handleException }); } document. observe ( 'dom:loaded' , poll_server);
  40. 40. Long Polling – 2 servers function successHandler (trans, messages_div) { if (trans.responseText) { var json = trans.responseText. evalJSON (); if (json.message) { var msg = json.message + '<br />' ; $(messages_div). insert (msg); } } poll_server (); }
  41. 41. Long Polling – 2 servers Main Web Server Polling Server <?php $query = 'INSERT INTO messages VALUES (?, ?)' ; $stmt = $pdo -> prepare ( $query ); $stmt -> prepare ( $message , $date ); $polling_server -> send ( $message ); ?> <?php foreach ( $this ->waiting as $connection ){ $connection -> respond ( $message ); } ?>
  42. 42. Long Polling – 2 servers <ul><li>Timeliness </li></ul><ul><ul><li>Near real-time </li></ul></ul><ul><ul><li>As soon as a message shows up on the server, it is sent to the waiting client </li></ul></ul><ul><ul><li>Black out period between sending response and making new request can add some delay </li></ul></ul>
  43. 43. Long Polling – 2 servers <ul><li>Efficiency (1 request, 1 new message) </li></ul><ul><ul><li>Data transfer: </li></ul></ul><ul><ul><ul><li>410 bytes sent for request </li></ul></ul></ul><ul><ul><ul><li>310 bytes for new message response </li></ul></ul></ul><ul><ul><ul><li>100 bytes of new data </li></ul></ul></ul><ul><ul><ul><li>100 / (410 + 310) = .138 per message </li></ul></ul></ul><ul><ul><li>Server resources used </li></ul></ul><ul><ul><ul><li>1 HTTP process on polling server per message </li></ul></ul></ul><ul><ul><ul><li>0 Database connections </li></ul></ul></ul>
  44. 44. WebSockets <ul><li>According to http://en.wikipedia.org/wiki/WebSocket: </li></ul><ul><li>„ WebSockets is a technology providing for bi-directional, full-duplex communications channels, over a single Transmission Control Protocol (TCP) socket, designed to be implemented in web browsers and web servers” </li></ul>
  45. 45. WebSockets <ul><li>WebSockets allow server to push data to client </li></ul><ul><li>Connection established via client-initiated handshake </li></ul><ul><li>After handshake, both the client and the server can send and recieve data </li></ul><ul><ul><li>Server can send data without the client asking for it first </li></ul></ul>
  46. 46. WebSockets <ul><li>Builds off of 2 server long polling </li></ul><ul><ul><li>Main web server communicates with event server </li></ul></ul><ul><li>Constant connection between client and server </li></ul><ul><ul><li>No black out periods </li></ul></ul><ul><ul><li>No need for cursor </li></ul></ul>
  47. 47. WebSockets web server WebSocket server JSON via WebSockets
  48. 48. WebSockets <ul><li>Difficulty – Client side </li></ul><ul><ul><li>5 out of 10 </li></ul></ul><ul><ul><li>WebSocket API </li></ul></ul><ul><ul><ul><li>Connection established </li></ul></ul></ul><ul><ul><ul><li>onMessage events fired when new data comes in from the server </li></ul></ul></ul><ul><ul><ul><li>New messages are added to DOM by JavaScript </li></ul></ul></ul>
  49. 49. WebSockets <ul><li>Difficulty – Server side </li></ul><ul><ul><li>8 out of 10 </li></ul></ul><ul><ul><li>Web server makes cURL call to WebSocket server when a new message is added </li></ul></ul><ul><ul><li>WebSocket server determines who message is for and sends the response to the waiting connection </li></ul></ul>
  50. 50. WebSockets function poll_server () { var socket = new WebSocket ( 'ws://example.com/' ); socket.onmessage = function (response) { successHandler (response, 'message_errors' ); } } document. observe ( 'dom:loaded' , poll_server);
  51. 51. WebSockets function successHandler (trans, messages_div) { if (trans.data) { var json = trans.data. evalJSON (); if (json.message) { var msg = json.message + '<br />' ; $(messages_div). insert (msg); } } }
  52. 52. WebSockets Main Web Server WebSocket Server <?php $query = 'INSERT INTO messages VALUES (?, ?)' ; $stmt = $pdo -> prepare ( $query ); $stmt -> prepare ( $message , $date ); $polling_server -> send ( $message ); ?> <?php foreach ( $this ->waiting as $connection ){ $connection -> respond ( $message ); } ?>
  53. 53. WebSockets <ul><li>Timeliness </li></ul><ul><ul><li>Real-time </li></ul></ul><ul><ul><li>As soon as a message shows up on the server, it is sent to the waiting client </li></ul></ul><ul><ul><li>No black out period </li></ul></ul>
  54. 54. WebSockets <ul><li>Post Handshake Efficiency </li></ul><ul><ul><li>Data transfer: </li></ul></ul><ul><ul><ul><li>0 bytes sent for request </li></ul></ul></ul><ul><ul><ul><li>100 bytes for new message response </li></ul></ul></ul><ul><ul><ul><li>100 bytes of new data </li></ul></ul></ul><ul><ul><ul><li>100 / 100 = 1.000 per message </li></ul></ul></ul><ul><ul><li>Server resources used </li></ul></ul><ul><ul><ul><li>1 process on WebSocket server </li></ul></ul></ul><ul><ul><ul><li>0 Database connections </li></ul></ul></ul>
  55. 55. WebSockets <ul><li>Efficiency Demo </li></ul><ul><ul><li>http://spoutserver.com/demos/compare </li></ul></ul><ul><li>Comparison </li></ul><ul><ul><li>Refresh: .0021 </li></ul></ul><ul><ul><li>Short Polling: .0158 </li></ul></ul><ul><ul><li>Long Polling: .138 </li></ul></ul><ul><ul><li>WebSockets: 1.00 </li></ul></ul>
  56. 56. WaterSpout <ul><li>Lightweight HTTP server </li></ul><ul><ul><li>Static files </li></ul></ul><ul><ul><li>Dynamic content (PHP) </li></ul></ul><ul><li>Best used as part of event-driven server pair </li></ul><ul><ul><li>Can function as both ends </li></ul></ul><ul><li>Handles WebSockets and long polling </li></ul><ul><li>Written in PHP </li></ul>
  57. 57. WaterSpout <ul><li>Two types of connections </li></ul><ul><ul><li>Listeners </li></ul></ul><ul><ul><li>Updates </li></ul></ul><ul><li>When an update comes in the appropriate listeners are notified </li></ul><ul><ul><li>Custom controllers define which listeners should be notified </li></ul></ul>
  58. 58. WaterSpout - Listeners <?php public function listen () { // Handle cursor for long polling fall back. // ... $this ->dispatcher-> add_listener ( $this ); } ?>
  59. 59. WaterSpout - Dispatcher <?php /* Called every .25 seconds on all waiting listeners */ public function process_event (Controller $mover = null) { $key = array_search (( int ) $this ->_cursor, array_keys (self:: $_commands )); if ( $key === false && ! is_null ( $this ->_cursor)) { return ; } $commands = array_slice (self:: $_commands , $key ); if ( empty ( $commands )) { return ; } $response = new HTTPResponse ( 200 ); $body = array ( '__URI__' => $this ->uri, 'commands' => $commands, 'cursor' => end ( array_keys (self:: $_commands )) + 1 ); $response -> set_body ( $body , true); $this -> write ( $response ); $this ->_cursor = ( int ) end ( array_keys (self:: $_commands )) + 1 ; } ?>
  60. 60. WaterSpout vs Apache/Nginx <ul><li>Neither Apache nor Nginx has a way for one process to notify the listeners </li></ul><ul><ul><li>You need to put the incoming update into some shared location (mysql, memcache, etc) </li></ul></ul><ul><ul><li>Listeners have to poll the shared location </li></ul></ul><ul><ul><ul><li>Heavy </li></ul></ul></ul><ul><ul><ul><li>Slows down timeliness </li></ul></ul></ul><ul><li>WaterSpout solves this by letting updates notify listeners </li></ul>
  61. 61. WebSockets <ul><li>Resources </li></ul><ul><ul><li>http://dev.w3.org/html5/websockets/ </li></ul></ul><ul><ul><li>http://en.wikipedia.org/wiki/Web_Sockets </li></ul></ul><ul><ul><li>http://www.spoutserver.com/ </li></ul></ul>
  62. 62. Questions? <ul><li>Contact </li></ul><ul><ul><li>[email_address] </li></ul></ul><ul><li>Twitter </li></ul><ul><ul><li>@spoutserver </li></ul></ul><ul><li>Feedback </li></ul><ul><ul><li>http://joind.in/talk/view/1748 </li></ul></ul><ul><li>Slides </li></ul><ul><ul><li>http://www.slideshare.net/spoutserver </li></ul></ul>

Editor's Notes

  • - Once upon a time, the internet was flat. Users asked for content and web servers gave it to them. - XMLHttpRequest came along and change all of that. - Google said “well, we know they are going to ask for their new messages soon anyway, so why not give them the new messages before they ask?”
  • - Unless you are Facebook, the database is your bottle neck. - Solutions that consume database resources are not very scalable - Timeliness is often sacrificed for scalability
  • Basically the same as refresh but with less data transfered

×