Go Content Distribution

Content Distribution service has been rebuilt in Go from the ground up as a network specific application, increasing performance and massively reducing its footprint.

Lead article image

As you may already know, the first app to be released to the Edge Network was CDN, a web service written in Node.js which predates the network in its current form, and that has been used in production for over five years by a wide range of content providers, from low traffic microsites to international publishers. It’s easy and quick to configure and comes packed a wide range of modifiers that provide comprehensive *just in time* asset manipulation, as well as CSS and JS compression. Its ability to rapidly crop, resize, compress, and reformat images and quickly serve cached resources made it ideal for an increasingly mobile consumer that expects high quality visuals with minimum delay.

Image

When we first rolled it out into the network there was very little to change. It already had multi domain support, meaning a single instance could exist on each Host but be configured to support each domain slightly differently, with different sources, caching, and header configurations. CDN originally required its config to be stored on disk, so we added an endpoint that allowed it to be configured without a restart. If you’ve been running a Host in the last year, you’ve been successfully running a very powerful app that we are hugely proud of.

Those of you that have been paying close attention to the impact on your system may have noticed one rather glaring problem with CDN: it’s huge. Well, that’s not strictly true. It’s ~500mb on disk, which isn’t aggressively large, and certainly doesn’t affect operations when running on a single machine, however in a network where a high level of distribution is required, and where available disk space per device is relatively low, it can become a limiting factor.

When we release a new build of CDN, 390+ devices globally all need to pull a 0.5GB docker image. That’s 190GB from the registry for every release, and that just doesn’t scale. And on a 16GB machine that’s ~3% of the entire volume just for a single application. Those who have followed the more technical posts from the team will know that the network applications are primarily written in Go, and those that have been following the project since the early days may remember that the original prototype for the network was actually written in Node.js. Switching to Go wasn’t a difficult choice. It’s stricter, faster and more efficient than Node, and the resulting binary is far smaller.

Much of the logic from the Node.js build of CDN was so clearly written that the run up to rebuilding it in Go was far less daunting than we originally expected.

🔗Feature migration

The Node.js build of CDN was built for a very different production environment, so migrating to Go was the perfect juncture to take stock of which features to carry over and which to drop. Here’s a short breakdown.

🔗Features to carry over

  • Multiple domain configuration
  • Remote file source for image
  • Remove file source for CSS and JS transformation, as well as all other filetypes

🔗Features to drop

  • SSL support, which is now handled at Gateway level
  • S3 file source which will be replaced by Object Storage in the network
  • Local filesystem source
  • Redis cache which is replaced by Gateway-level caching

🔗Keeping it all production ready

We’ve built Content Distribution using the same logic as the previous version without introducing any breaking changes. Whilst the majority of users to the network are using our technology for the first time, there are a number of existing clients that have opted to migrate from their Cloud hosted CDN to the network, so it was of vital importance that the move was pain-free and invisible to the end-user.

🔗The benefits of writing in Go

🔗A single compiled binary

As mentioned earlier using Go to rebuild Content Distribution wasn’t a difficult choice, especially when we knew how significant the reduction in binary size would be. The newly released docker image is currently ~140MB, a number we intend to half over the next few releases. To put that into perspective, the Node.js build was ~568MB. This reduction in largely down to Go being a compiled language. In addition to the reduction in filesize, we are also seeing a 30-50% reduction in response times. The significance of a 100% increase in performance is a great achievement, and one we’re really proud of.

Image

🔗Reducing potential for errors with Go

Compared to JavaScript, Go is a typed and strict language. At compile-time, the Go compiler detects problems that JavaScript only sees during runtime. This also allows for the earlier detection of errors that in turn speeds up development and protects the deployment process.

🔗Better resources utilization

Node.js uses a single CPU core so to take full advantage of a multi-core system, we rely on process multiplexers such as PM2. In Go the default application behaviour is to use all available CPU cores, and optional limits can be set with the environmental variable GOMAXPROCS .

Node.js has a performant event-loop which helps maximize CPU utilization, but that comes at a cost. Go on the other hand uses goroutines – simple, scaleable subroutines for concurrent and parallel workloads, without the high resource utilization.

🔗Benchmarking in Numbers

🔗Go

Thread Stats Avg Stdev Max +/- Stdev

Latency 564.91ms 406.14ms 1.93s 70.07%

Req/Sec 7.72 5.21 20.00 75.25%

Latency Distribution

50% 475.04ms

75% 781.49ms

90% 1.16s

99% 1.85s

1295 requests in 30.04s, 32.77MB read

Socket errors: connect 0, read 0, write 0, timeout 1

Requests/sec: 43.11

Transfer/sec: 1.09MB

🔗Node.js

Thread Stats Avg Stdev Max +/- Stdev

Latency 636.30ms 415.39ms 1.99s 74.95%

Req/Sec 4.28 3.67 20.00 77.07%

Latency Distribution

50% 555.32ms

75% 735.90ms

90% 1.26s

99% 1.93s

519 requests in 30.04s, 55.79MB read

Socket errors: connect 0, read 0, write 0, timeout 64

Requests/sec: 17.27

Transfer/sec: 1.86MB

🔗What’s next?

We will be moving to use gRPC for communication between the Content Distribution app and Gateway, which will allow us to considerably increase our network performance by reducing latency and concurrent http/2 connections. We’ll also be further optimizing modifier performance and introducing new modifiers for video, audio, and live streams.

Related articles

More updates articles
Mail icon

Like what you are reading? Want to earn tokens by becoming an Edge Node? Save money on your hosting services? Build amazing digital products on top of Edge services? Join our mailing list.

To hear about our news, events, products and services, subscribe now. You can also indicate which services you are interested in, which we use for research and to inform the content that we send.

* You can unsubscribe at any time by emailing us at data@edge.network or by clicking on the unsubscribe link which can be found in our emails to you. Read our Privacy Policy.
Winner Best Edge Computing Platform Technology & Innovation Awards
Presented by Juniper Research