[[This is Chapter 13(f) from "beta" Volume IV of the upcoming book "Development&Deployment of Multiplayer Online Games", which is currently being beta-tested. Beta-testing is intended to improve the quality of the book, and provides free e-copy of the "release" book to those who help with improving; for further details see "Book Beta Testing". All the content published during Beta Testing, is subject to change before the book is published.
To navigate through the book, you may want to use Development&Deployment of MOG: Table of Contents.]]
[[TODO: move to the beginning of Chapter 13]]
When speaking about the programming network-related app – usually very little attention is paid to the question “whether the app is going to run over the Internet, or locally in LAN”. And in theory – indeed, there is no difference whatsoever: there is a long-standing perception that we should just use our TCP (HTTP, whatever-else), and “smart TCP/IP stack will do everything-we-need for us”.
In practice, however – it is not that simple; and whenever we’re starting to speak about low-latency scenarios such as those involved in games (or stock exchanges) – the statement above tends to fall apart really really quickly.
Fundamental Properties of the Internet
The effects I’ll describe below, are all related to the nature of the Internet, and apply regardless of the transport-level and app-level protocols being used. As a result – for the time being we will NOT speak in terms of TCP or UDP; rather – we’ll concentrate on a good old IP packet (which belongs to the Level 3 a.k.a. L3 of OSI/ISO networking model).
The IP packet, the whole IP packet and nothing but the IP packet, so save me Stevens
First of all, we need to mention two absolutely fundamental properties of the Internet
Everything on the Internet is transferred via IP packets.
Whatever we’re doing on the Internet – is implemented on top of exchanging IP packets. TCP streams are nothing but sequences of IP packets, UDP datagrams are just IP packets (with an 8-byte UDP header starting their payload), IPSEC VPN is a yet another type of IP packet, and so on. Those few network-related protocols we’re using, and which do not fit into this patterns (such as ARP which effectively binds L3 to L2, or L2-and-lower Ethernet/Framerelay/ATM/SONET/…) – are inherently confined to our local networks (or “local” networks of respective ISPs1). Or looking at it from a bit different angle – if we want to send something between two boxes which are sitting at the arbitrary points on the Internet – we MUST use IP packets to achieve it.
1 They’re “local” even when they’re covering half of the globe – in a sense that none of them covers “the whole Internet”.
Each and Every IP Packet is Inherently Unreliable
The second fundamental property of the Internet says that
Each and every IP packet is in danger of being lost
All the routers, switches (actually – pretty much each and every device which forms Internet infrastructure) – are allowed to drop each and every packet.
All the routers, switches (actually – pretty much each and every device which forms Internet infrastructure) – are allowed to drop each and every packet. There is absolutely no way to tell them “hey, this packet is sooooo important, so you MUST deliver it – just this single packet, pretty please…”). This property simplifies implementation of the Internet greatly (and moreover – arguably, without it, Internet wouldn’t be able to work as it works now) – but has very significant implications.
In particular, if we need reliable delivery of anything – it is a responsibility of the communication end-points to (a) detect that the packet is lost, and (b) to re-send the packet.
This is exactly what TCP or Reliable UDP is doing. However, it has further implications. More specifically, detecting of a lost packet takes time, and re-sending it takes time too. This (combined with the fact that TCP is a stream, so out-of-order delivery is not really an option) is the primary reason why TCP tends to cause higher latencies (that is, in presence of lost packets) even after Nagle’s algorithm is disabled; more on it in [[TODO]] section.
Channel-Level Retransmits
In some cases (especially if physical channel is expected to be very poor and/or unstable), channel-level protocol (usually at L2) can have its own L2-level acknowledgements and initiate a retransmit if the packet is not acknowledged (one example of such protocol is Bluetooth, which in turn is often used for tethering).
However, this trickery doesn’t affect the fundamental property of all packets being losable. Just because even if one single channel provides this kind of guarantee, others normally don’t (and routers normally don’t provide guarantees about their processing abilities either). So, while indeed some of the channels over which your IP packets travel, can be sorta-reliable – when speaking about Internet as a whole, each and every IP packet still MUST be considered at risk of being lost.
Real-World Issues
Now, with these two fundamental properties in mind, we can start discussing more subtle issues of the real-world Internet. Let’s start with discussing things which happen “on the Internet itself” - or from another perspective, between ISP's routers (i.e. not including connections such as connection from home modem to ISP, etc.).
Router Failures. BGP Convergence Time and Manually Handled Failures
Everything out there can fail, and with about 20-30 routers on a typical over-the-Internet path, chances of any one of them to fail are rather high.
Everything out there can fail, and with about 20-30 routers on a typical over-the-Internet path, chances of any one of them to fail are rather high. What happens if a router somewhere on the Internet fails – is that adjacent routers will eventually understand that one of their peers has failed, and will switch to an alternative path to route the packets. For all the even half-decent ISPs, having that alternative path (known as “multi-homing”) is a de-facto standard at least for 20 years. It means that most of the time, the effects of a failed router are limited to the (usually 100%) packet loss during that “detect-and-switch-to-alternative-path” window.
This time is known as “BGP convergence time”, with typical values being between 1 and 2 minutes. From our app-level developer perspective, it means that one of common scenarios to happen, will be 100% packet loss for a time between 1 and 2 minutes. And as you can imagine - it is going to be a very serious disruption for affected players.
While such disruptions are not going to be frequent for each of the customers/players, it is still important to account for them for two reasons:
- If you have 100K simultaneous connections – you’ll see some of it happening on a very regular basis. Not that it is a problem per se – but at least you’ll need to make sure that your Client behaves reasonably under such circumstances.
- Oh, and be prepared to answer claims coming from your players/customers such as “hey, the whole Internet works for me except for your site, so it is not my problem, so it MUST be yours”. Quite often such complaints come when the major router somewhere on the way goes down.
Worse than that – if such a failed router happens to be close to your Server (or it is a border router of a large ISP – which I’ve seen to fail much more frequently than backbone routers) – you can experience such a 2-minute packet loss for many thousands of your connections at the same time. And (especially if you’re using your own protocols) - you’d better think about such scenarios and test your system against them. Once upon a time, one of my own systems had exhibited a problem, related to O(N) lookup in a place where N was deemed to be very small; however, under one-way 100% packet loss over 10K Clients – it wasn’t really small, which has unnecessarily increased recovery time from the problem by 20 minutes or so. I got lucky at that time – as effects could have been much One of my own systems had exhibited a problem, related to O(N) lookup in a place where N was deemed to be very small; however, under one-way 100% packet loss over 10K Clients – it wasn’t really small