FIFA 2014 World Cup live stream architecture

live_stream_nginx We were given the task to stream the FIFA 14 World Cup and I think this was an experience worth sharing. This is a quick overview about: the architecture, the components, the pain, the learning, the open source and etc.

The numbers

  • GER 7×1 BRA (yeah, we’re not proud of it)
  • 0.5M simultaneous users @ a single game – ARG x SUI
  • 580Gbps @ a single game – ARG x SUI
  • =~ 1600 watched years @ the whole event

The core overview

The project was to receive an input stream, generate HLS output stream for hundreds of thousands and to provide a great experience for final users:

  1. Fetch the RTMP input stream
  2. Generate HLS and send it to Cassandra
  3. Fetch binary and meta data from Cassandra and rebuild the HLS playlists with Nginx+lua
  4. Serve and cache the live content in a scalable way
  5. Design and implement the player

If you want to understand why we chose HLS check this presentation only in pt-BR. tip: sometimes we need to rebuild some things from scratch.

The input

The live stream comes to our servers as RTMP and we were using EvoStream (now we’re moving to nginx-rtmp) to receive this input and to generate HLS output to a known folder. Then we have some python daemons, running at the same machine, watching this known folder and parsing the m3u8 and posting the data to Cassandra.

To watch files modification and to be notified by these events, we first tried watchdog but for some reason we weren’t able to make it work as fast as we expected and we changed to pyinotify.

Another challenge we had to overcome was to make the python program scale to x cpu cores, we ended up by creating multiple Python processes and using async execution.

tip: maybe the best language / tool is in another castle.

The storage

We previously were using Redis to store the live stream data but we thought Cassandra was needed to offer DVR functionality easily (although we still uses Redis a lot). Cassandra response time was increasing with load to a certain point where clients started to timeout and the video playback completely stopped.

We were using it as Queue-like which turns out to be a anti-pattern. We then denormalized our data and also changed to LeveledCompactionStrategy as well as we set durable_writes to false, since we could treat our live stream as ephemeral data.

Finally, but most importantly, since we knew the maximum size a playlist could have, we could specify the start column (filtering with id > minTimeuuid(now – playlist_duration)). This really mitigated the effect of tombstones for reads. After these changes, we were able to achieve a latency in the order of 10ms for our 99% percentile.

tip: limit your queries + denormalize your data + send instrumentation data to graphite + use SSD.

The output

With all the data and meta-data we could build the HLS manifest and serve the video chunks. The only thing we were struggling was that we didn’t want to add an extra server to fetch and build the manifests.

Since we already had invested a lot of effort into Nginx+Lua, we thought it could be possible to use lua to fetch and build the manifest. It was a matter of building a lua driver for Cassandra and use it. One good thing about this approach (rebuilding the manifest) was that in the end we realized that we were almost ready to serve DASH.

tip: test your lua scripts + check the lua global vars + double check your caching config

The player

In order to provide a better experience, we chose to build Clappr, an extensible open-source HTML5 video player. With Clappr – and a few custom extensions like PiP (Picture In Picture) and Multi-angle replays – we were able to deliver a great experience to our users.

tip: open source it from day 0 + follow to flow issue -> commit FIX#123

The sauron

To keep an eye over all these system, we built a monitoring dashboard using mostly open source projects like: logstash, elastic search, graphite, graphana, kibana, seyren, angular, mongo, redis, rails and many others.

tip: use SSD for graphite and elasticsearch

The bonus round

Although we didn’t open sourced the entire solution, you can check most of them:

Discussion / QA @ HN

32 thoughts on “FIFA 2014 World Cup live stream architecture

  1. Interesting 🙂 We gave a talk about the same issue last year in Velocity 🙂 We had the same issues for our Platform though we are using Mediaroom and Microsoft technologies.

    You can check the slides in the following link:

    Sadly the video taken in velocity is not free 😦 But it is hosted with last years Barcelona Velocity Talks.

    What we feared the most was a final Brazil – Spain 😉

    • We didn’t measure this latency ( does that in such a great way), what I think we could do is: (not rock science):
      + ingest point (rtmp input) buffer
      + network latency between the stream generator and our server
      + delay introduced by hls generator
      + delay response of cassandra
      + latency between final users and our edge servers
      This latency from RAW input until final users. (roughly speaking we had like 7-11s delay from realtime)

      Slow connections: we leave this problem to hls adaptive algorithm (the best case scenario you will only consume the lower bitrate).

      “Did you playback from the latest frames or did you catch up?”
      I might not understood you but, we also rely on the way hls playback works (when you switch video quality it tries to find a keyframe, when you start a video it see what kind of video is and might start playing with latest chunks, or considering the media sequence…)

  2. Indeed it’s a nice post.
    I just have one single question, which I’ll never understand: why you decided to rely so much on adaptive stream (DASH)?!?! I’m asking this because you guys did not even provide the option to manually set the video quality on the player…. Sometimes, users do not have only a bandwidth bottleneck problem (which is partially tackled by DASH), but also they can have CPU or RAM problems, that can bring a lot of stalling during the playback…….

    I would suggest that you bring it back the manual selection for video quality on the Globo player, since, e.g., Premiere FC is sometimes very very hard to watch — I don’t want to always watch it in HD quality having multiple stalling during the transmission. I prefer to watch it in a lower quality but without any problems. 🙂

    That’s my two cents.


    • We maybe do a post about this dashboard :D!

      But the thing is: *it is just an aggregation and presentation* over the available data source (mostly graphite)

  3. I experiencing the creation of a video server and I would like to know what was the ts segment size you used in 2014 world cup live videos. I also would like to know the value of the initial buffer size and general buffer size. They are dynamically controled by clappr player or are the fixed?

    Thank you.

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s