NodeJS to Client : large data sending performance - javascript

How can I send large data from NodeJS to Client?
I tried this two:
1. Socket.io request
2. Ajax GET request
But both way are slow.
I am using mongoDB. Data size would be 1,000,000+ objects(1-2GB) but even 10,000 data sending, It is so slow.
How can I make it more faster? (Data reading time from MongoDB to NodeJS is no problem. )
This is Socket.io code
=> NodeJS
io.sockets.on('connection', function(socket) {
socket.on('getData', function() {
var items = TestModel.find();
items.find({},function(err,obj){
for(var i=0;i<obj.length;i++){
socket.emit('responseData', obj[i]);
}
socket.emit('complete',"Item length : ");
});
});
});});
If I use socket.emit('responseData', obj), I ll get a overflow err
=> index.HTML
<html>
<head>
<meta charset="utf-8"/>
<script src="/socket.io/socket.io.js"></script>
<title></title>
</head>
<body>
Socket.io Test
</body>
<script>
window.onload = function() {
var socket = io.connect();
socket.emit('getData');
var i=0;
//socket.emit('getName');
socket.on('responseData', function(data) {
i++;
});
socket.on('complete',function(data){
alert(data+i);
});
};
</script>
</html>
This is Ajax GET code
=> NodeJS
app.get('/load',function(req,res){
var items = TestModel.find();
console.log("Model loaded");
items.find({},function(err, obj){
res.send(JSON.stringify(obj));
console.log("Sent Models");
});
});
=> Ajax
$(function(){
$(document).ready(function(){
$.get('/load', {}, function(data){
...
});
});});

compression
Check and/or enable compression, you could get up to 10x gain, depending on data and format. There's a tradeoff between compression quality and server cpu usage, in general, start with best compression algorithm browser (or client) supports.
If the client is under your control, you could even try xz or something more exotic :)
caching
Tag your responses (https://en.wikipedia.org/wiki/HTTP_ETag) and add hooks for If-None-Match: ... request header field.
streaming
Depends on what the client is using the data for, is it saved? processed? displayed? In many cases client can start performing actions on part of data. If that part is at the start of response, streaming it makes a lot of sense
parallelize
Clients could use Range: ... request header field to download segments of data. In which case single client could issue multiple requests against segments of given dataset simultaneously. This typically helps if client's network is crappy (e.g. another continent).
preview
Perhaps client can process or "show" a simplified representation of data first. If there's a human user behind the client, they may wish to quickly check your data before making a decision to download it. Pretty common for images and design documents where a thumbnail or preview is generated server-side.

Related

Sending string from Javascript to Python code using Sockets

I am new to this area so forgive me if I've not explained myself well enough.
I am trying to set up a basic test where the html page that I've made (served using node.js) connects to my javascript template and that sends a string "hello world" to my python program.
I am connecting to port 3000 and using local host. My python module is capable of binding to the port but doesn't print any data that should be sent to the local host.
I am assuming the issue is oriented around the javascript side. Essentially all I am trying to do is have the webserver send the string as soon as the user clicks the button, although I am not sure how to establish this connection between my js template and html template. Even without a button the js fails to send the data.
I did use src = and used "alert("hello")" to check that the two templates were linked, which worked; as soon as the user opened the webpage they got a popup statement. But upon trying to send data using sockets, I'm not sure why no data is being sent from the webpage to my python program.
HTML:
<!DOCTYPE html>
<html>
<body>
<script type = "text/javascript" src = "backendrequest.js"></script>
<input id="clickMe" type="button" value="clickme" onclick="socketPress();" />
</body>
</html>
Javascript:
var net = require('net');
var client = new net.Socket();
client.connect(3000, 'localhost', function() {
console.log('Connected');
client.write('Hello World!');
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.destroy(); // kill client after server's response
});`
Python:
import socket
def Main():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# get local machine name
host = socket.gethostname()
port = 3000
# connection to hostname on the port.
s.connect((host, port))
# Receive no more than 1024 bytes
msg = s.recv()
s.close()
print (msg.decode('ascii'))
My main objective is to have the user print on python the data, in this case "hello world," coming from my local host, using sockets.
Any advice would be highly appreciated as I just want to know where I am going wrong.

What is the best technology for a chat/shoutbox system? Plain JS, JQuery, Websockets, or other?

I have an old site running, which also has a chat system, which always used to work fine. But recently I picked up the project again and started improving and the user base has been increasing a lot. (running on a VPS)
Now this shoutbox I have (running at http://businessgame.be/shoutbox) has been getting issues lately, when there are over 30 people online at the same time, it starts to really slow down the entire site.
This shoutbox system was written years ago by the old me (which ironically was the young me) who was way too much into old school Plain Old JavaScript (POJS?) and refused to use frameworks like JQuery.
What I do is I poll every 3 seconds with AJAX if there are new messages, and if YES, load all those messages (which are handed as an XML file which is then parsed by the JS code into HTML blocks which are added to the shoutbox content.
Simplified the script is like this:
The AJAX functions
function createRequestObject() {
var xmlhttp;
if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else { // code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
// Create the object
return xmlhttp;
}
function getXMLObject(XMLUrl, onComplete, onFail) {
var XMLhttp = createRequestObject();
// Check to see if the latest shout time has been initialized
if(typeof getXMLObject.counter == "undefined") {
getXMLObject.counter = 0;
}
getXMLObject.counter++;
XMLhttp.onreadystatechange = function() {
if(XMLhttp.readyState == 4) {
if(XMLhttp.status == 200) {
if(onComplete) {
onComplete(XMLhttp.responseXML);
}
} else {
if(onFail) {
onFail();
}
}
}
};
XMLhttp.open("GET", XMLUrl, true);
XMLhttp.send();
setTimeout(function() {
if(typeof XMLhttp != "undefined" && XMLhttp.readyState != 4) {
XMLhttp.abort();
if(onFail) {
onFail();
}
}
}, 5000);
}
Chat functions
function initShoutBox() {
// Check for new shouts every 2 seconds
shoutBoxInterval = setInterval("shoutBoxUpdate()", 3000);
}
function shoutBoxUpdate() {
// Get the XML document
getXMLObject("/ajax/shoutbox/shoutbox.xml?time=" + shoutBoxAppend.lastShoutTime, shoutBoxAppend);
}
function shoutBoxAppend(xmlData) {
process all the XML and add it to the content, also remember the timestamp of the newest shout
}
The real script is far more convoluted, with slower loading times when the page is blurred and keeping track of AJAX calls to avoid double calls at the same time, ability to post a shout, load settings etc. All not very relevant here.
For those interested, full codes here:
http://businessgame.be/javascripts/xml.js
http://businessgame.be/javascripts/shout.js
Example of the XML file containing the shout data
http://businessgame.be/ajax/shoutbox/shoutbox.xml?time=0
I do the same for getting a list of the online users every 30 seconds and checking for new private messages every 2 minutes.
My main question is, since this old school JS is slowing down my site, will changing the code to JQuery increase the performance and fix this issue? Or should I choose to go for an other technology alltogether like nodeJS, websockets or something else? Or maybe I am overlooking a fundamental bug in this old code?
Rewriting an entire chat and private messages system (which use the same backend) requires a lot of effort so I'd like to do this right from the start, not rewriting the whole thing in JQuery, just to figure out it doesn't solve the issue at hand.
Having 30 people online in the chatbox at the same time is not really an exception anymore so it should be a rigid system.
Could perhaps changing from XML data files to JSON increase performance as well?
PS: Backend is PHP MySQL
I'm biased, as I love Ruby and I prefer using Plain JS over JQuery and other frameworks.
I believe you're wasting a lot of resources by using AJAX and should move to websockets for your use-case.
30 users is not much... When using websockets, I would assume a single server process should be able to serve thousands of simultaneous updates per second.
The main reason for this is that websockets are persistent (no authentication happening with every request) and broadcasting to a multitude of connections will use the same amount of database queries as a single AJAX update.
In your case, instead of everyone reading the whole XML every time, a POST event will only broadcast the latest (posted) shout (not the whole XML), and store it in the XML for persistent storage (used for new visitors).
Also, you don't need all the authentication and requests that end up being answered with a "No, there aren't any pending updates".
Minimizing the database requests (XML reads) should prove to be a huge benefit when moving from AJAX to websockets.
Another benifit relates to the fact that enough simultaneous users will make AJAX polling behave the same as a DoS attack.
Right now, 30 users == 10 requests per second. This isn't much, but it can be heavy if each request would take more than 100ms - meaning, that the server answers less requests than it receives.
The home page for the Plezi Ruby Websocket Framework has this short example for a shout box (I'm Plezi's author, I'm biased):
# finish with `exit` if running within `irb`
require 'plezi'
class ChatServer
def index
render :client
end
def on_open
return close unless params[:id] # authentication demo
broadcast :print,
"#{params[:id]} joind the chat."
print "Welcome, #{params[:id]}!"
end
def on_close
broadcast :print,
"#{params[:id]} left the chat."
end
def on_message data
self.class.broadcast :print,
"#{params[:id]}: #{data}"
end
protected
def print data
write ::ERB::Util.html_escape(data)
end
end
path_to_client = File.expand_path( File.dirname(__FILE__) )
host templates: path_to_client
route '/', ChatServer
The POJS client looks like so (the DOM update and from data access ($('#text')[0].value) use JQuery):
ws = NaN
handle = ''
function onsubmit(e) {
e.preventDefault();
if($('#text')[0].value == '') {return false}
if(ws && ws.readyState == 1) {
ws.send($('#text')[0].value);
$('#text')[0].value = '';
} else {
handle = $('#text')[0].value
var url = (window.location.protocol.match(/https/) ? 'wss' : 'ws') +
'://' + window.document.location.host +
'/' + $('#text')[0].value
ws = new WebSocket(url)
ws.onopen = function(e) {
output("<b>Connected :-)</b>");
$('#text')[0].value = '';
$('#text')[0].placeholder = 'your message';
}
ws.onclose = function(e) {
output("<b>Disonnected :-/</b>")
$('#text')[0].value = '';
$('#text')[0].placeholder = 'nickname';
$('#text')[0].value = handle
}
ws.onmessage = function(e) {
output(e.data);
}
}
return false;
}
function output(data) {
$('#output').append("<li>" + data + "</li>")
$('#output').animate({ scrollTop:
$('#output')[0].scrollHeight }, "slow");
}
If you want to add more events or data, you can consider using Plezi's auto-dispatch feature, that also provides you with an easy to use lightweight Javascript client with an AJAJ (AJAX + JSON) fallback.
...
But, depending on your server's architecture and whether you mind using heavier frameworks or not, you can use the more common socket.io (although it starts with AJAX and only moves to websockets after a warmup period).
EDIT
Changing from XML to JSON will still require parsing. The question is actually whether XML vs. JSON parsing speeds.
JSON will be faster on the client javascript, according to the following SO question and answer: Is parsing JSON faster than parsing XML
JSON seems to be also favored on the server-side for PHP (might be opinion based rather than tested): PHP: is JSON or XML parser faster?
BUT... I really think your bottleneck isn't the JSON or the XML. I believe the bottleneck relates to the multitude of times that the data is accessed, (parsed?) and reviewed by the server when using AJAX.
EDIT2 (due to comment about PHP vs. node.js)
You can add a PHP websocket layer using Ratchet... Although PHP wasn't designed for long running processes, so I would consider adding a websocket dedicated stack (using a local proxy to route websocket connections to a different application).
I love Ruby since it allows you to quickly and easily code a solution. Node.js is also commonly used as a dedicated websocket stack.
I would personally avoid socket.io, because it abstracts the connection method (AJAX vs Websockets) and always starts as AJAX before "warming up" to an "upgrade" (websockets)... Also, socket.io uses long-polling when not using websockets, which I this is terrible. I'd rather show a message telling the client to upgrade their browser.
Jonny Whatshisface pointed out that using a node.js solution he reached a limit of ~50K concurrent users (which could be related to the local proxy's connection limit). Using a C solution, he states to have no issues with more than 200K concurrent users.
This obviously depends also on the number of updates per second and on whether you're broadcasting the data or sending it to specific clients... If you're sending 2 updates per user per second for 200K users, that's 400K updates. However, updating all the users only once every 2 seconds, that's 100K updates per second. So trying to figure out the maximum load can be a headache.
Personally, I didn't get to reach these numbers on my apps, so I never got to discover Plezi's limits first hand... although, during testing, I had no issues with sending hundred of thousands of updates per second (but I did had a connection limit due to available ports and open file handle limits on my local machine).
This definitely shows how vast of an improvement you can reach by utilizing websockets (especially since you stated to notice slowdowns with 30 concurrent users).

node.js express response.write() not async in Safari

I have a very simple node.js server that I use to ping some servers I need to keep online.
Using Express I have a very simple endpoint I can access that will perform a loop of requests and report the results.
Using res.write() on each loop, the webpage I load can show me the progress as it's happening.
The problem is, this progress doesn't happen in Safari on either OS X or iOS. It waits until the process is complete and then dumps the whole output in 1 go.
Here's an example of my code:
router.route('/test').get(function(req, res)
{
res.write('<html><head></head><body>');
res.write('Starting tests...<br />');
performServerTests(req, res, function(results)
{ // Each loop within performServerTests also uses res.write()
res.write('<br />Complete');
res.end('</body></html>');
});
});
Is there a known reason why Safari would wait for the res.end() call before displaying what it already has, while Chrome shows each res.write() message as it receives it?
Thanks
When using chunked transfers (what you're trying to do), browsers are generally waiting for a minimum amount of data to be received before starting rendering. The exact size is browser-specific - see Using "transfer-encoding: chunked", how much data must be sent before browsers start rendering it? for some quite recent data points on this.
You example could for example be written like this (adding some headers to be explicit too):
router.route('/test').get(function(req, res)
{
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
res.setHeader('Transfer-Encoding', 'chunked');
res.write('<html><head></head><body>');
res.write('Starting tests...<br />');
var buf = ""
for (var i = 0; i < 500; i++) {
buf += " "
}
res.write(buf);
performServerTests(req, res, function(results)
{ // Each loop within performServerTests also uses res.write()
res.write('<br />Complete');
res.end('</body></html>');
});
});

The request is too large for IE to process properly

I am using Websync3, Javascript API, and subscribing to approximately 9 different channels on one page. Firefox and Chrome have no problems, but IE9 is throwing an alert error stating The request is too large for IE to process properly.
Unfortunately the internet has little to no information on this. So does anyone have any clues as to how to remedy this?
var client = fm.websync.client;
client.initialize({
key: '********-****-****-****-************'
});
client.connect({
autoDisconnect: true,
onStreamFailure: function(args){
alert("Stream failure");
},
stayConnected: true
});
client.subscribe({
channel: '/channel',
onSuccess: function(args) {
alert("Successfully connected to stream");
},
onFailure: function(args){
alert("Failed to connect to stream");
},
onSubscribersChange: function(args) {
var change = args.change;
for (var i = 0; i < change.clients.length; i++) {
var changeClient = change.clients[i];
// If someone subscribes to the channel
if(change.type == 'subscribe') {
// If something unsubscribes to the channel
}else{
}
}
},
onReceive: function(args){
text = args.data.text;
text = text.split("=");
text = text[1];
if(text != "status" && text != "dummytext"){
//receiveUpdates(id, serial_number, args.data.text);
var update = eval('(' + args.data.text + ')');
}
}
});
This error occurs when WebSync is using the JSON-P protocol for transfers. This is mostly just for IE, cross domain environments. Meaning websync is on a different domain than your webpage is being served from. So IE doesn't want do make regular XHR requests for security reasons.
JSON-P basically encodes the up-stream data (your 9 channel subscriptions) as a URL encoded string that is tacked onto a regular request to the server. The server is supposed to interpret that URL-encoded string and send back the response as a JavaScript block that gets executed by the page.
This works fine, except that IE also has a limit on the overall request URL for an HTTP request of roughly 2kb. So if you pack too much into a single request to WebSync you might exceed this 2kb upstream limit.
The easiest solution is to either split up your WebSync requests into small pieces (ie: subscribe to only a few channels at a time in JavaScript), or to subscribe to one "master channel" and then program a WebSync BeforeSubscribe event that watches for that channel and re-writes the subscription channel list.
I suspect because you have a key in you example source above, you are using WebSync On-Demand? If that's the case, the only way to make a BeforeSubscribe event handler is to create a WebSync proxy.
So for the moment, since everyone else is stumped by this question as well, I put a trap in my PHP to not even load this Javascript script if the browser is Internet Destroyer (uhh, I mean Internet Explorer). Maybe a solution will come in the future though.

Does the ExternalInterface, in Flex 3, have a data size limitation?

I am using the ExternalInterface on Flex 3. We are actually using flex to compress a large amount of DOM data, so this is specifically being used with LARGE data.
To further investigate, if there is a limitation, is this universal? (IE. Silverlight)
First, let me state that this is being done with an application that was made by inexperienced software engineers. This is an app that we need to buy time by compressing the data so that we can build a long-term solution. We have no other options, unfortunately.
Background: This is an application that is actually a web-spreadsheet. Our long term solution is to make a Office Business Application.
No, Flash do not impose any size limits on ExternalInterface communication.
I think it does, or there is some other configuration which governs this. I was testing a file upload using FileReference object and wanted to pass the data sent from server back to hosting page via external interface call. Below is a snippet of my UPLOAD_COMPLETE_DATA event handler
private function onFileUploadCompleteData (e:DataEvent):void
{
var file:FileReference = FileReference(e.target);
Alert.show("onFileUploadCompleteData : " + e.data );
if(ExternalInterface.available && callBackOnUploadCompleteData.length > 0)
{
var data:Object = new Object();
data.FileName = file.name;
data.ServerData = e.data;
//data.ServerData = e.data.substr(0, 50);
ExternalInterface.call(callBackOnUploadCompleteData, data);
}
}
This event gets fired but the call to my javascript is never made. If I uncomment the line which trims the returned data to first 50 characters, it start working and calls the javascript correctly.
Either there is a size restriction imposed by flash (10.2) or IE9 (which is what I was using), or there is something else I am missing.

Categories