110

I am currently working on a Ruby on Rails project which shows a list of images.

A must-have for this project is that it shows new posts in realtime without the need of refreshing the web page. After searching for a while, I've stumbled upon some JavaScript solutions and services such as PubNub; however, none of the provided solutions made sense at all.

In the JavaScript solution (polling) the following happens:

  • User 1 views the list of photos.
  • In the background the JavaScript code is polling an endpoint every second to see if there is a new post.
  • User 2 adds a new photo.
  • There is a delay of 50 ms before the new cycle is triggered and fetches the new data.
  • The new content is loaded in the DOM.

This seems odd when translated to a real world example:

  • User 1 holds a pile of pictures on his/her desk.
  • He/she walks to the photographer every second and asks if he has a new one.
  • The photographer makes a new photo.
  • This second when he/she walks in, she can take the picture and put it on the pile.

In my opinion the solution should be as following:

  • User 1 holds a pile of pictures on his/her desk.
  • The photographer takes a new picture.
  • The photographer walks to the pile and puts it with the rest.

The PubNub solution is basically the same, however this time there is an intern walking between the parties to share the data.

Needless to say, both solutions are very energy consuming as they are triggered even when there is no data to load.

As far as my knowledge goes there is no (logic) explanation why this way of implementation is used in almost every realtime application.

19
  • 197
    Ignoring for a moment that web browsers are not servers that can receive incoming connections... wait, no, lets not ignore that. Commented Jul 22, 2014 at 18:45
  • 17
    @dennis: a stateful, persistent connection between the server and client would probably get rid of the need for polling, but that is not how the Web was designed. Commented Jul 22, 2014 at 18:49
  • 59
    How about Websockets?
    – I.devries
    Commented Jul 22, 2014 at 20:28
  • 25
    Or take a look at long polling. Basically you poll, but the server doesn't respond before it has any new data to show you.
    – Matsemann
    Commented Jul 22, 2014 at 20:51
  • 53
    There are many perfectly sensible solutions and algorithms in computer-space that would be completely absurd to do in meatspace. Commented Jul 23, 2014 at 2:48

8 Answers 8

182

Pushing works well for 1, or a limited number of users.

Now change the scenario with one photographer and 1000 users that all want a copy of the picture. The photographer will have to walk to 1000 piles. Some of them might be in locked office, or spread all over the floor. Or their user on vacation, and not interested in new pictures at the moment.

The photographer would be busy walking all the time and not take new pictures.

Fundamentally: a pull/poll model scales better to lots of unreliable readers with loose realtime requirements (if a picture takes 10 seconds later to arrive on a pile, what's the big deal).

That said, a push model is still better in a lot of situations. If you need low latency (you need that new photo 5s after it's taken), or updates are rare and requests frequent and predictable (keep asking the photographer every 10 seconds when he generates a new picture a day), then pulling is inappropriate. It depends on what you're trying to do. NASDAQ: push. Weather service: pull. Wedding photographer: probably pull. News photo agency: probably push.

28
  • 33
    I really like your analogy with 1000 users, some on vacation, some not interested. +1.
    – riwalk
    Commented Jul 22, 2014 at 18:59
  • 4
    @EsbenSkovPedersen: Socket limit is not due to IP address. It's due to maximum open file descriptor. So the maximum number of open socket is independent of how many IP addresses you use.
    – slebetman
    Commented Jul 23, 2014 at 14:11
  • 10
    This is a horrible analogy to put it mildly. In order for the push to work, any user's client must maintain an open connection of some sort. In fact, polling is an emulation of a connection. It's not like because some clients are polling, that all clients are notified. Similarly, when some clients open a connection for push notifications, not all clients are notified. This is very poor advise that invites throwing resources out the window. Being bombarded with 10000 requests per second is virtually never cheaper or otherwise better than maintaining 10000 open sockets.
    – back2dos
    Commented Jul 23, 2014 at 15:00
  • 8
    @ptyx: The 1s interval is the one being discussed here. 10k requests per second means 10k TCP handshakes and 10k HTTP requests (each easily reaching 2KB), which gives you multiple orders of magnitude more background noise pounding your server. There is a variety of battle tested libraries that make push subscriptions as easy as putting polling in place. There are even frameworks like meteor.js that completely abstract the whole issue away. Appealing to scalability without any further explanation is also hardly an argument. Anyway, I have voiced my doubts and don't wish to start a discussion ;)
    – back2dos
    Commented Jul 23, 2014 at 16:48
  • 5
    I agree with back2dos's comment above. If pull scaled better than push, google, stack exchange, facebook, online stock services, etc. would use pull technology. But they don't. Fundamentally, hammering the server instead of setting up a listening station scales terribly. Major services avoid polling.
    – Travis J
    Commented Jul 23, 2014 at 23:02
107

I'm really surprised that only one person has mentioned WebSockets. Support is implemented in basically every major browser.

In fact PubNub uses them. For your application the browser would probably subscribe to a socket that would broadcast whenever a new photo is available. The socket wouldn't send the photo, mind you, but just a link so the browser could download it asynchronously.

In your example imagine something like:

  1. User(s) lets photographer know that he wants to know about all future photos
  2. Photographer says over loudspeaker that a new photo is available
  3. User asks photographer for photo

This is somewhat like your original example solution. It's more efficient than polling because the client doesn't have to send any data to the server (except maybe heartbeats.)

Also, as others have mentioned, there are other methods that are better than simple polling that work in older browsers (longpolling, et al.)

15
  • 43
    @RobertHarvey how come WebSockets are not related to the question? The question asks whether polling is an acceptable strategy, and nowadays it clearly isn't acceptable (or not optimal at least). WebSockets, Server-sent events and long polling perform much better on virtually every single use case. Commented Jul 22, 2014 at 22:58
  • 7
    @RobertHarvey that was just my interpretation, no reframing as far as I can see. Sure, the question asked why is it still accepted and not what is the optimal strategy, but these are still tightly related imho. Commented Jul 22, 2014 at 23:01
  • 25
    WebSockets (and the like) are the closest you can get to implementing the OP's "solution", so I think it's very relevant despite him not mentioning it specifically. Commented Jul 23, 2014 at 2:48
  • 6
    Not to mention, StackExchange sites like the one you're on right now (unless you're looking at this webpage cached/saved) use WebSockets. This was why I was also wondering why no one until @korylprince mentioned WebSockets.
    – trysis
    Commented Jul 23, 2014 at 5:10
  • 6
    @FabrícioMatté: actually, not every single use cases. Long polling requires keeping a socket open for every users which takes up system resources. Fr services that isn't very time critical but have lots of users, keeping a socket open is usually more expensive than servicing a short 304 every now and then. For most services, a slight delay is not an issue. A single machine can usually serve more clients with polling than with push.
    – Lie Ryan
    Commented Jul 23, 2014 at 13:22
42

Sometimes good enough is good enough.

Of all the possible ways to implement a "real-time" communications process, polling is perhaps the simplest way. Polling can be used effectively when the polling interval is relatively long (i.e. seconds, minutes or hours rather than instantaneous), and the clock cycles consumed by checking the connection or resource don't really matter.

2
  • 3
    This, a thousand times this. It's accepted because it's usually good enough.
    – corsiKa
    Commented Jul 24, 2014 at 18:19
  • 1
    That's a good enough answer
    – Zain R
    Commented Nov 25, 2014 at 1:39
31

The HTTP protocol is limited in that the client MUST be the one to initiate the request. The server cannot communicate with the client unless responding to a client's request.

So to adjust your real world example, add the following restraint:

  • User 2 can ONLY respond to User 1's questions with a single sentence reply, after which User 1 must leave. User 2 has no other way of communicating.

With this new restraint, how would you do it other than polling?

16
  • 6
    HTTP 2.0 will support server pushes. "Pushing allows servers to send representations to clients without an explicit request being made." en.wikipedia.org/wiki/HTTP_2.0
    – kaptan
    Commented Jul 22, 2014 at 19:28
  • 5
    @kaptan, that's great, but its not available. Make do with what you've got.
    – riwalk
    Commented Jul 22, 2014 at 20:36
  • 7
    There is also long-polling which is available right now and simulates a push model using a pull.
    – Tim B
    Commented Jul 22, 2014 at 21:02
  • 24
    @dennis: Having written industrial automation software I'd just like to comment on your polling of sensors example. Polling sensors serves two purposes - the most obvious is to fetch new data. The less obvious is to detect that the sensor is still alive, not crashed due to a bug or burning due to factory fire or melted due to industrial accident. Silence, the fact that you receive no reply, is also valuable data.
    – slebetman
    Commented Jul 23, 2014 at 4:16
  • 3
    @dennis Sensors often sense much faster than you're interested in the data. Polling allows you to get the sensor value exactly when you want it, without being flooded with updates you don't care about. (Imagine if the OS notified your application every time a file changed anywhere on the disk, instead of your application needing to open and read the file)
    – user20574
    Commented Jul 23, 2014 at 11:04
13

Why is polling accepted? Because in reality every solution is actually low-level polling!

If the server should update you as soon as new pictures are available, it usually has to have a connection to you - because IP addresses change often and you never know if someone isn't interested anymore, so the client has to send some form of keep-alive signal, for example, "I'm still here, I'm not offline"

All stateful connections (for example, TCP/IP) work the same, since you can only send singular data-packets over the Internet; you never know if the other party is still there.

So every protocol has a timeout. If an entity doesn't answer within X seconds, it is presumed to be dead. So even if you have only an open connection between server and client, without sending any data, the server and client have to send regular keep-alive packets (this is handled low-level if you open a connection between them) - and how is this in the end any different from polling?

So the best approach would probably be longpolling:

The client sends a request immediately after loading the site (for example, telling the photographer "Tell me if there are any new pictures"), but the server doesn't answer if there aren't any new pictures. As soon as the request times out, the client asks again.

If the server now has any new pictures, it can immediately answer all the clients which stand in line for new pictures. So your reaction time after a new picture is even shorter than with push, since the client is still waiting in an open connection for a reply and you don't have to build up a connection to the client. And the polling requests from the client are not much more traffic than a constant connection between client and server for an answer!

4
  • I disagree that every solution ends up being low-level polling. You're confusing polling required to send data with polling required to know when a client is lost. Yes, the latter will always end up polling somewhere down the protocol stack, but that can be at a very low frequency (such as once every five minutes) whereas polling for actual data every second is a waste that CAN be avoided with true push notifications that is NOT polling at any level of the stack. Commented Jul 25, 2014 at 6:29
  • First most keepalive packets run at a fairly high frequency, because you want to avoid common timeout intervals so few sec isn't uncommon for TCP/IP and almost anything not using tcp may be blocked by firewalls. So when I need to send a data packet every X seconds, why not fill it with some data at virtually no cost?
    – Falco
    Commented Jul 25, 2014 at 7:26
  • 1
    @Guralnek even if you had a connection with a keep alive interval of 5 mins the timeout would be higher, since you have to add actual delay and lost packets. And the server would keep many connections for 5min after the clients have disconnected, so overall this would likely cost more server resources while saving only minimal bandwidth
    – Falco
    Commented Jul 25, 2014 at 7:30
  • 1
    +1 for long polling. Look up Comet en.wikipedia.org/wiki/Comet_%28programming%29
    – Zan Lynx
    Commented Nov 24, 2014 at 13:57
9

One advantage of polling is that it limits the harm that can be caused if a message goes missing or the state of something gets glitched. If X asks Y for its state once every five seconds, then the loss of a request or a reply will merely result in X's information being ten seconds out of date rather than 5. If Y gets rebooted, X can find out about it the next time Y is able to respond to one of X's messages. If X gets rebooted, it might never bother asking Y for anything afterward, but whoever is observing the status of X should recognize that it has been rebooted.

If instead of X polling Y, X relied upon Y to inform it whenever its state changed, then if Y's state changed and it sent a message to X, but for whatever reason that message was not received, X might never become aware of the change. Likewise if Y gets rebooted and never has any reason to send X a message about anything.

In some cases it may be helpful to for X to request that Y autonomously send messages with its status, either periodically or when it changes, and only have X poll if it goes too long without hearing anything from Y. Such a design may eliminate the need for X to send most of its messages (typically, X should at least occasionally inform Y that it's still interested in receiving messages, and Y should stop sending messages if it goes too long without any indication of interest). Such a design would, however, require Y to persistently maintain information about X, rather than being able to simply send a reply to whoever polled it and then immediately forget about who that was. If Y is an embedded system, such a simplification may help reduce memory requirements sufficiently to allow the use of a smaller and cheaper controller.

Polling can have an additional advantage when using a potentially-unreliable communications medium (e.g. UDP or radio): it can largely eliminates the need for link-layer acknowledgments. If X sends Y a status request Q, Y responds with a status report R, and X hears R, X won't need to hear any sort of link-layer acknowledgment for Q to know that it was received. Conversely, once Y sends R, it doesn't need to know or care if X received it. If X sends a status request and gets no response, it can send another. If Y sends a report and X doesn't hear it, X will send another request. If each request goes out once and either yields a response or doesn't, neither party needs to know or care whether any particular message was received. Since sending an acknowledgment may consume almost as much bandwidth as a status request or report, using a round-trip of request-report doesn't cost much more than would an unsolicited report and acknowledgment. If X sends a few requests without getting replies, it may on some dynamically-routed networks need to enable link-level acknowledgments (and ask in its request that Y do likewise) so that the underlying protocol stack can recognize the delivery problem and search for a new route, but when things are working a request-report model will be more efficient than using link-level acknowledgments.

5
  • The problem you talk about with Y pushing messages to X (second paragraph) can be fixed by having a serial number attached to each message. If a message is lost, X will know because it did not receive that serial. At that point it can take other measures to sync up with Y. DNS master -> slave replication works this way. Commented Jul 23, 2014 at 2:51
  • @korylprince: Either side can find out about the missing message if the other side has occasion to send something (and does so successfully), or if it has reason to expect something from the other side and never receives it. If one side sends a status update and either doesn't require acknowledgments or gives up after retrying a few times, and the other side isn't expecting scheduled transmissions, the other side won't know that the connection has disappeared.
    – supercat
    Commented Jul 23, 2014 at 3:42
  • 2
    @korylprince - The problem is, without periodic messages, X may detect the missing message a day late or a year late or 10 years late. To detect missing packet in reasonable time you need to somehow poll. You can "pull" poll or you can "push" poll. The first is called "polling" the second is called "heartbeat"
    – slebetman
    Commented Jul 23, 2014 at 4:19
  • Both very true. It all depends on the situation. Commented Jul 23, 2014 at 11:30
  • @slebetman: Without periodic messages, if Y gets rebooted, there may be no mechanism by which X would ever discover it.
    – supercat
    Commented Jul 23, 2014 at 14:34
1

The question is to balance the amount of unnecessary polls vs the amount of unnecessary pushes.

If you poll:

  • You get an answer at this very moment. Good if you ask only occasionally or need a data set this very moment.
  • You might get a "no content" answer, causing pointless load on the line.
  • You put load on the line only when you poll, but always when you poll.

If you push:

  • You deliver the answer right when it is available, which allows an immediate processing on the client side.
  • You might deliver data to clients which are not interested in this data, causing pointless load on the line.
  • You put load on the line every time there is new data, but only when there is new data.

There are several solutions on how to deal with the various scenarios and their disadvantages, like for example a minimum time between polls, poll-only proxies to take the load off the main system, or - for the pushes - a regulation to register and specify the wanted data followed by unregistering on log-off. Which one fits best is nothing you can say in general, it depends on the system.

In your example polling is not the most efficient solution, but the most practical one. It is very easy to write a polling system in JavaScript, and it is very easy to implement it on the delivery side as well. A server made to deliver image data should be able to handle the extra requests, and if not, it can be scaled linearly, as the data is mostly static and can therefore be easily cached.

A push method implementing a log-in, description of wanted data and finally a log-off would be most efficient, but is probably too complex for the average "script-kiddy", and needs to deal with the question: what if the user just shuts down the browser and log-off cannot be performed?

Maybe it is better to have more users (as accessing is easy) than to save some bucks on another cache-server?

1

For some reason, these days, all the younger web developers seem to have forgotten the lessons of the past, and why some things have evolved the way they did.

  1. Bandwidth was an issue
  2. Connection might be intermittent.
  3. Browsers did not have as much computing power
  4. There were other methods of accessing content. The web is is not w3.

In the face of these constraints, you might not have a constant 2 way communication. And if you looked at the OSI model, you'd find most considerations are meant to decouple persistency with the underlying connection.

With that in mind, a polling method of pulling information is a great way to reduce bandwidth and computation on the client side. The rise of push is really for the most part just the client doing constant polling, or web sockets. Personally if i was everyone else out there, i'd appreciate the regularity of polling as a means of traffic analysis, where an out of time GET/POST request would signal a man in the middle situation of some sort.

Not the answer you're looking for? Browse other questions tagged or ask your own question.