why latency varies in web socket when it's a static connection? - node.js

as HTTP creates the connection again and again for each data to be transferred over a network, WEB SOCKETS are static and the connection will be made once initially and will stay until the transmission is done...but if the web sockets are static then why the latency differs for each data packet..???
the latency test app i have created shows me different time lag.. so what is the advantage of web socket being a static connection or if this is a common issue in web sockets ??
Do i need to create a buffer to control the flow of data because the data transmission in the is continous..?
does the latecy increases when data transmission is continous?

There is no overhead to establish a new connection with a statically open web socket (as the connection is already open and established), but when you're making a request half way around the world, networking takes some time so there's latency when you're talking to a server half way around the world.
That's just how networking works.
You get a near immediate response from a server on your own LAN and the further away the server gets (in terms of network topology) the more routers each packet much transit through, the more total delay there is. As you witnessed in your earlier question related to this topic, when you do a tracert from your location to your server location, you saw a LOT of different hops that each packet has to traverse. The time for each one of these hops all adds up and busy routers may also each add a small delay if they aren't instantly processing your packet.
The latency between when you send a packet and get a response is just 2x the packet transit time plus whatever your server takes to respond plus perhaps a tiny little overhead for TCP (since it's a reliable protocol, it needs acknowledgements). You cannot speed up the transit time unless you pick a server that is closer or somehow influence the route the packet takes to a faster route (this is mostly not under your control once you've selected a local ISP to use).
No amount of buffering on your end will decrease the roundtrip time to your server.
In addition, the more hops in the network there are between your client and server, the more variation you may get from one moment to the next in the transit time. Each one of the routers the packet traverses and each one of the links it travels on has their own load, congestion, etc... that varies with time. There will likely be a minimum transit time that you will ever observe (it will never be faster than x), but many things can influence it over time to make it slower than that in some moments. There could even be a case of an ISP taking a router offline for maintenance which puts more load on the other routers handling the traffic or a route between hops going down so a temporary, but slower and longer route is substituted in its place. There are literally hundreds of things that can cause the transit time to vary from moment to moment. In general, it won't vary a lot from one minute to the next, but can easily vary through the day or over longer periods of time.
You haven't said whether this is relevant or not, but when you have poor latency on a given roundtrip or when performance is very important, what you want to do is to minimize the number of roundtrips that you wait for. You can do that a couple of ways:
1. Don't sequence small pieces of data. The slowest way to send lots of data is to send a little bit of data, wait for a response, send a little more data, wait for a response, etc... If you had 100 bytes to send and you sent the data 1 byte at a time waiting for a response each time and your roundtrip time was X, you'd have 100X as your total time to send all the data. Instead, collect up a larger piece of the data and send it all at once. If you send the 100 bytes all at once, you'd probably only have a total delay of X rather than 100X.
2. If you can, send data parallel. As explained above the pattern of send data, wait for response, send more data, wait for response is slow when the roundtrip time is poor. If your data can be tagged such that it stands on its own, then sometimes you can send data in parallel without waiting for prior responses. In the above example, it was very slow to send 1 byte, wait for response, send next byte, wait for response. But, if you send 1 byte, then send next byte, then send next byte and then some times later you process all the response, you get much, much better throughput. Obviously, if you already have 100 bytes of data, you may as well just send that all at once, but if the data is arriving real time, you may want to just send it out as it arrives and not wait for prior responses. Obviously whether you can do this depends entirely upon the data protocol between your client and server.
3. Send bigger pieces of data at a time. If you can, send bigger chunks of data at once. Depending upon your app, it may or may not make sense to actually wait for data to accumulate before sending it, but if you already have 100 bytes of data, then try to send it all at once rather than sending it in smaller pieces.

Related

Node's epoll behaviour on socket

I wrote a simple node.js program that sends out 1000 http requests and it records when these requests comes back and just increases counter by 1 upon response. Endpoint is very light weight and it just has simple http resonse without any heavy html. I recorded that it returns me around 200-300 requests per second for 3 seconds. On other hand, when i start this same process 3 times (4 total processes = amount of my available cores) i notice that it performs x4 faster. So i receive aproximately 300 * 4 requests per second back. I want to understand what happens when epoll gets triggered upon Kernel notifying the poll about new file descriptor being ready to compute (new tcp payload arrived). Does v8 take out this filedescriptor and read the data / manipulate with it and where is the actuall bottleneck? Is it in computing and unpacking the payload? It seems that only 1 core is working on sending/receiving these requests for this 1 process and when i start multiple (on amount of my cores), it performs faster.
where is the actuall bottleneck?
Sounds like you're interested in profiling your application. See https://nodejs.org/en/docs/guides/simple-profiling/ for the official documentation on that.
What I can say up front is that V8 does not deal with file descriptors or epoll, that's all Node territory. I don't know Node's internals myself (only V8), but I do know that the code is on https://github.com/nodejs/node, so you can look up how any given feature is implemented.

Bash - cURL Get requests are slow (Relatively)

I'm constantly querying a server for a list of items. Usually the data returned is "offers:" with a blank list, 99.999% of the time this is the data I get back from my request. So, pretty small payload.
I have a ping of 35ms pretty rock solid, jitter is about 0.2ms
But when running a single loop of requests, I get updates about every 300ms.
My goal is to make this as fast as I possibly can, so I parallelized it, running 8 of the loops. But now, I see that frequently 4 or more of the threads will seem to run simultaneously. Giving me 4 requests within 10 or 20ms of each other, and leaving periods of up to 200ms with no requests being processed.
The server I'm interfacing is of unknown specs, but it's a large company I'm interfacing with and I'd assume that the server I am communicating with is more than capable of handling anything I could possibly throw at it.

Socket.IO: most efficient way to update clients with massively fluctuating data

Imagine Agar.io. Unlike a chat app, the list of users (or players) and other environment objects will be constantly changing, for each player, as players move around the map. That is because each client can't receive updates about every object, because the map is too large and the lag would be too much. So which of the following methods of updating clients, with Socket.IO, would be more efficient:
Send an environment array containing data, which replaces the local arrays on each client.
Send individual messages when objects appear/disappear in a players field of view, and tinker with the local arrays object by object.
If there is a better way than the above two, please outline it.
This is a multi-vector tradeoff decision so without some measuring and probably experimentation, we can't really tell you what situation is optimal. But, we can direct your thinking which you can hopefully use to finish the analysis.
First off, to scale and reduce lag, you want to:
Send fewer messages to each client.
Send smaller payloads with each message as long as it doesn't make item #1 worse (e.g. as long as it doesn't cause you to send more messages).
Have fewer times on the server where you are doing calculations and then sending messages.
To send fewer messages to each client you want to:
Reduce the scope of the map that the client gets sent updates about to only things that are closely in view (it sounds like you're already doing some of that).
Combine as much information as you can in each message that you are going to send to a client - make sure that you're never sending more than one message to a given client for a particular update.
To send smaller messages to each client you want to:
Reduce the size of the data you send to each client. This means that if some data has not changed since that last time you communicated with this client, then don't resend that data. This would suggest that your second option (client updates its own local array) is a better way to do it because you only have to send deltas to the client and it remembers previous state.
Carefully analyze the format of the data you're sending to the client and reduce its size wherever possible. Straight JSON is often not the most efficient way to send data if you're trying to optimize transmission size.

socket io node js to get server time every one second performance

I want to display realtime server time on my webpage and would like to know if I can use socket.emit periodically (every 1 second) for that? And if I do use it, what is the performance impact?
Alternatively, I can simply get the timezone once from the server and just use browser's date object to get current time and convert the timezone to display realtime. But, in this case, I am assuming that my server's date-time setting is correctly configured.
Basically, I just want to know whats the performance impact on the server/client when i run a socket.emit every 1 second using setInterval
There's no point in sending server time constantly. Just time a round trip packet, send the server time once, add the transit time and then compare the server time to the local time to create an offset. Then, just use the local time + the offset from then on. It will be at least as accurate as constantly sending the server time and will be more efficient.
The idea is that the client clock and the server clock run at the same speed so you just need to know what the offset is between the two and then you can use the client clock plus the offset.
The performance impact of sending a small message every second to one client is probably no big deal, but if you have lots of clients connected, it could start to be significant and further could cause delays between the time each client is sent the packet thus rendering the sent time not that accurate.

TCP Message framing + recv() [linux]: Good conventions?

I am trying to create a p2p applications on Linux, which I want to run as efficiently as possible.
The issue I have is with managing packets. As we know, there may be more than one packet in the recv() buffer at any time, so there is a need to have some kind of message framing system to make sure that multiple packets are not treated as one big packet.
So at the moment my packet structure is:
(u16int Packet Length):(Packet Data)
Which requires two calls to recv(); one to get the packet size, and one to get the packet.
There are two main problems with this:
1. A malicious peer could send a packet with a size header of
something large, but not send any more data. The application will
hang on the second recv(), waiting for data that will never come.
2. Assuming that calling Recv() has a noticeable performance penalty
(I actually have no idea, correct me if I am wrong) calling Recv() twice
will slow the program down.
What is the best way to structure packets/Recieving system for both the best efficiency and stability? How do other applications do it? What do you recommend?
Thankyou in advance.
I think your "framing" of messages within a TCP stream is right on.
You could consider putting a "magic cookie" in front of each frame (e.g. write the 32-bit int "0xdeadbeef" at the top of each frame header in addition to the packet length) such that it becomes obvious that your are reading a frame header on the first of each recv() pairs. It the magic integer isn't present at the start of the message, you have gotten out of sync and need to tear the connection down.
Multiple recv() calls will not likely be a performance hit. As a matter of fact, because TCP messages can get segmented, coalesced, and stalled in unpredictable ways, you'll likely need to call recv() in a loop until you get all the data you expected. This includes your two byte header as well as for the larger read of the payload bytes. It's entirely possible you call "recv" with a 2 byte buffer to read the "size" of the message, but only get 1 byte back. (Call recv again, and you'll get the subsequent bytes). What I tell the developers on my team - code your network parsers as if it was possible that recv only delivered 1 byte at a time.
You can use non-blocking sockets and the "select" call to avoid hanging. If the data doesn't arrive within a reasonable amount of time (or more data arrives than expected - such that syncing on the next message becomes impossible), you just tear the connection down.
I'm working on a P2P project of my own. Would love to trade notes. Follow up with me offline if you like.
I disagree with the others, TCP is a reliable protocol, so a packet magic header is useless unless you fear that your client code isn't stable or that unsolicited clients connect to your port number.
Create a buffer for each client and use non-blocking sockets and select/poll/epoll/kqueue. If there is data available from a client, read as much as you can, it doesn't matter if you read more "packets". Then check whether you've read enough so the size field is available, if so, check that you've read the whole packet (or more). If so, process the packet. Then if there's more data, you can repeat this procedure. If there is partial packet left, you can move that to the start of your buffer, or use a circular buffer so you don't have to do those memmove-s.
Client timeout can be handled in your select/... loop.
That's what I would use if you're doing something complex with the received packet data. If all you do is to write the results to a file (in bigger chunks) then sendfile/splice yields better peformance. Just read packet length (could be multiple reads) then use multiple calls to sendfile until you've read the whole packet (keep track of how much left to read).
You can use non-blocking calls to recv() (by setting SOCK_NONBLOCK on the socket), and wait for them to become ready for reading data using select() (with a timeout) in a loop.
Then if a file descriptor is in the "waiting for data" state for too long, you can just close the socket.
TCP is a stream-oriented protocol - it doesn't actually have any concept of packets. So, in addition to recieving multiple application-layer packets in one recv() call, you might also recieve only part of an application-layer packet, with the remainder coming in a future recv() call.
This implies that robust reciever behaviour is obtained by receiving as much data as possible at each recv() call, then buffering that data in an application-layer buffer until you have at least one full application-layer packet. This also avoids your two-calls-to-recv() problem.
To always recieve as much data as possible at each recv(), without blocking, you should use non-blocking sockets and call recv() until it returns -1 with errno set to EWOULDBLOCK.
As others said, a leading magic number (OT: man file) is a good (99.999999%) solution to identify datagram boundaries, and timeout (using non-blocking recv()) is good for detecting missing/late packet.
If you count on attackers, you should put a CRC in your packet. If a professional attacker really wants, he/she will figure out - sooner or later - how your CRC works, but it's even harder than create a packet without CRC. (Also, if safety is critical, you will find SSL libs/examples/code on the Net.)

Resources