Voxer is always trying to lower the latency between our users. Our data shows that
as we reduce latency, people send more messages. We've done a lot of optimizations on
the backend to improve the performance of our technology stack: node.js, riak, redis,
and SmartOS. The next set of improvements we have been working on are at the network
protocol level by tuning stud and moving to the SPDY protocol, which forms the
basis of HTTP 2.0.
Our mobile clients have always used HTTPS to talk to the backend, but this has caused a
number of performance problems. The latency of mobile networks is unpredictable, and it
fluctuates wildly. Even using persistent connections and HTTP pipelining,
we used a pool of HTTPS connections to reduce client latency and to address issues like head-of-line blocking.
Negotiating and maintaining a pool of TLS connections is complex and slow,
and we haven't found a library that does this well on iOS.
The benefits of SPDY from a networking perspective are well documented. We have
found that using SPDY for our application has made the application easier to understand, debug,
and maintain. SPDY uses a single TCP socket for all requests, so error handling logic,
queuing, retry, and background modes have all gotten simpler.
Twitter has released their CocoaSPDY library which solves a
similar problem to iSPDY. Had this library been available when we started using SPDY, we may have chosen
to use it instead and extend it to our needs. At this point, iSPDY has been tailored for our
specific use case at Voxer, and we will continue to maintain it going forward.
The most important feature in iSPDY that we are relying on heavily is Server Push streams.
Older Voxer clients used WebSockets or traditional HTTP long-polling to get live updates, but
both of these have various tradeoffs at the client, server, and networking levels. In our
application, SPDY with server push is the ideal solution for live updates. A single long-lived
TCP connection can be used to send multiple live media streams to a waiting client without
waiting for a round trip or causing head-of-line blocking from a slow sender.
Here are our design goals for iSPDY:
- low latency tuning options
- low memory footprint
- server push stream support
- priority scheduling for outgoing data
- trailing headers
- ping support
- transparent decompression of response using Content-Encoding header
- background socket reclaim detection and support on iOS
- VoIP mode support on iOS
- optionally use IP instead of DNS name to connect to server and save DNS resolution time
Adding support for SPDY on our backend was relatively straightforward because we are
using node.js and node-spdy. Fedor Indutny is the primary author of both iSPDY
and node-spdy, so these two libraries work well together. We use stud for TLS
termination, so node.js sees an unencrypted SPDY stream, which is supported by node-spdy.
Older clients and those on other platforms will continue to send HTTPS, but node-spdy has
HTTP fallback support. The server code handling these endpoints is almost entirely unchanged,
which has made testing and integrating SPDY much easier.
You can download and play with iSPDY on github.