Blueprint by Tiny
Return to Tiny.cloud
Return to Tiny.cloudTry TinyMCE for Free
Search by

Introducing a new CDN infrastructure for Tiny Cloud

Tim Dettrick

November 18th, 2019

Written by

Tim Dettrick
Tim Dettrick

Category

Trends & Inspiration

Here at Tiny, we're always excited to talk about our products and their shiny new features. But, as with all enterprise-level software, it's not only what you can see that contributes to a product's success. There's a lot more that goes on behind the scenes to make it all work smoothly.

With the rapid speed at which technology advances and evolves, we need to review our infrastructure frequently, thinking of new, innovative ways to increase performance so there's one less thing for you and your users to worry about. We want you to know that we've got your back now and well into the future.

In this article, Tim Dettrick, one of our Senior Software Engineers, describes three problems that influenced the development of our new infrastructure (codename: Dispenser) for delivering TinyMCE on the cloud to our customers, as well as an overview of the solution.

For more information on what you can do to take full advantage of the performance benefits, check out our related article on 3 tips to improve TinyMCE performance in the cloud.

Ben Long, Developer Advocate at Tiny

The bundling problem

Our previous CDN infrastructure for Tiny Cloud (codename: Vostok) didn't start out serving TinyMCE. It originally served up one of our previous editor offerings, textbox.io, and started life in early 2015.

Vostok was a product of its day, and while 2015 might not seem so long ago, on the web it certainly is. HTTP/2 was released that year, and so was Windows 10. The latter of those is more important than it might sound, because Internet Explorer only acquired HTTP/2 support for Windows 10. So long as support for Internet Explorer remained important to Tiny, the choice to use HTTP/2 would depend on the Windows 10 adoption rate.

As a result, Vostok was architected for the world of HTTP/1.1. Remember when concatenating all your JavaScript resources together was the only way to avoid blocking on requests? Such were the arcane practices prior to HTTP/2, and Vostok was built for them.

TinyMCE turned up on Vostok in 2016, back in the days of TinyMCE 4.4. There were fewer premium plugins on Tiny Cloud, and all of them could be bundled together easily. Everything we controlled access to was JavaScript, so Vostok simplified the problem by putting it all together into two files: tinymce.min.js and plugins.min.js. The rest of the assets were open source, or not particularly useful on their own, so they were served via a traditional CDN out of an S3 bucket.

Since then, Tiny has been hard at work, releasing multiple TinyMCE 4.x versions, and TinyMCE 5 earlier this year. With TinyMCE 5 came much more sophisticated theming and icon packs…and a problem. Vostok catered for JavaScript, but the premium skins and icon packs we wanted to offer were not code. As we pondered how to solve this, another thing became apparent: tinymce.min.js wasn't so small anymore.

TinyMCE 5.0.14, in its fullest form with all the premium plugins, includes a lot of things. With PowerPaste and everything else bundled in, Vostok served tinymce.min.js as 986 kb uncompressed, or 303 kb gzipped as it traveled over the wire. Once it reached the other end, all of that had to be parsed and loaded, no matter where or how the editor was being used. It was apparent that a better solution going forward would be to deliver the core editor on its own, and deliver additional plugins separately as needed.

On top of this, there were some long-running operational issues with the way Vostok was designed to serve the editor. In order to avoid external dependencies and process requests quickly, Vostok loaded all the required JavaScript into memory on the server when (and only when) it started. Vostok was quick, but its memory usage was proportional to the (steadily increasing) number of editor versions we offered on Tiny Cloud. It also required a server restart to load new versions, because it had never been architected with hot-reload in mind. To guard against the on-start load failing, we did a blue-green deploy, creating new servers and decommissioning the old. But this meant that every time a plugin or editor version was released, we redeployed the production cluster. It was automated, but it was also a pain because it significantly increased deployment times.

There was also the matter of caching, which we'll come back to later.

All said, Vostok was a reliable workhorse, just like the R7-series rockets that launched its namesake. It had got the job done, but something new was required.

The redirect problem

To solve the bundling problem, we would have to check the referring domain and API key for many resources, not just a couple of JavaScript bundles. There were a few problems with this, but the biggest challenge was where the API key was:

https://cloud.tinymce.com/5/tinymce.min.js?apiKey=<your API key>

Putting the API key in the query parameters sounds great, until you realize that to have it available for every resource, the editor would need to know about it and add it for every asset it loads. Oh, and we'd have to add that functionality to every editor version we released. To use a phrase familiar to our Australian-based engineering team: "Yeah, nah mate!"

So, how else could we provide the API key without modifying enormous amounts of editor code?

https://cdn.tiny.cloud/1/<your API key>/tinymce/5/tinymce.min.js

By putting it in the base of the URL, we'd ensure that as the editor loaded resources via relative links, every resource path requested from our servers would include the same API key.

Great…but then we'd have to change the URL for everybody currently using the cloud. Here at Tiny, we don't like breaking things for our customers, or forcing them to change their code based on our timelines. So we'd need to implement a redirect.

Redirects are not the sorts of things you do lightly for assets that might be required for a page to function. The additional latency might be fine if you're close to a server with the content, but our Australian engineering team grew up knowing what "ping time" means. The speed of light doesn't play favorites, whether you're an admiral who wants their intel or a knowledge worker who wants their editor.

So, if we had to implement a redirect in this new system we were building (codename: Dispenser), we were determined to get some extra value from it.

The caching problem

Vostok always had a problem with caching. We reduced latency and load times by using global edge-caching in front of our servers - when the editor is in the cache, you get it faster. However, we could never cache it for very long, because Vostok's response depended on what products you purchased.

If you think of Vostok's response as a function, here's what it looked like:

ApiKey -> Domain -> EditorVersion -> Set Product -> JavaScript

For those not used to Haskell-style type signatures, that means Vostok needed to know your API key, the domain you'd requested the editor from, the editor and plugin versions you wanted, and the set of products you had bought, and from those parameters it would give you back the entire editor bundle as JavaScript.

If you varied any of those inputs, the output would change. As you continue to add more Tiny features (changing "Set Product" in the process), we don't want you waiting long to get them. So, we were only able to cache for as long as we thought you'd tolerate waiting for "Set Product" to be updated with your new purchase.

There are only two hard things in Computer Science: cache invalidation and naming things.

Phil Karlton

At one point, possibly unaware of Phil Karlton's wisdom, the engineering team tried to handle this by selectively invalidating the global cache when "Set Product" changed. This makes some sense for intermediate caches, but not when it comes to browser caching, so it wasn't ideal. When we reviewed this in 2018, we realized our expenditure on the cache invalidation infrastructure was greater than all the rest of the serving infrastructure, while caching still remained limited to an hour. Continuing cache invalidation wasn't justifiable, so we adjusted the cache TTLs down to 15 minutes and turned off all the invalidation infrastructure.

We needed a better model.

Dispenser: Short-lived references, long-lived content

Our new CDN infrastructure, Dispenser, uses redirects to its advantage. There's always an initial 307 Temporary Redirect response when using Dispenser, with a short-lived (~10 minutes) cache TTL. That redirect has only one function: to send you to the latest version of the editor as you've specified it.

/1/<your-api-key>/tinymce/5/tinymce.min.js
→ /1/<your-api-key>/tinymce/5.0.14-54/tinymce.min.js

If you're using an old-style URL with a query parameter, we fix that at the same time too. Most of the time, this redirect will come from a cache not too far from you.

Following that redirect, we know that the editor version you're asking for will not be changing, so it can be cached for much longer. We do a few instrumentation tweaks for the cloud version of the core editor, so a request for tinymce.min.js is not long-lived by most standards, but it's cached for at least an hour. Most of the time, that's good enough that the users in your region are probably getting a cache hit from an edge cache <30ms away. If they've visited your site recently, it's probably a 304.

If it is a user's first time loading that version of TinyMCE, Dispenser serves it in just 467kb uncompressed, or 177kb gzipped. That's because, instead of bundling all the plugins, you're just getting the editor. If you want PowerPaste, just include it in your plugin list, and it will be fetched on editor init just like a community plugin. There won't be a redirect, because the path already includes the resolved editor version. Dispenser does almost no bundling of files because, with HTTP/2 and its connection multiplexing, requests are cheap.

So how does this help when you purchase additional plugins, skins, or icons? Well, for any individual file you're downloading, we don't need to know everything you're entitled to.

ApiKey -> Set Product

Instead, for any given file, we just need to know if you have purchased the product you're after:

ApiKey -> Product -> Boolean

If you have some tolerance for false positives or negatives, caching whether an item is a member of a set is much more efficient than caching the entire set. When you request something you've purchased, we're happy for it to live out in the edge cache for at least a day. We don't mind providing an extra day of access to a product you have canceled. However, if you request something you haven't purchased, we assume a slower response (reminding you it hasn't been purchased) is acceptable, so we cache this for a very small time. As a result, when you purchase a plugin or theme from Tiny, your users will have it available within a few seconds.

Because of this focus on cacheable responses, you'll notice something a little unusual with Dispenser: the more users you have, the faster your editor loads. Why? Because there's a higher likelihood that the content is already in the cache, and a higher likelihood that the edge cache has a connection already open to one of our servers if it's not.

Making the most of Dispenser

It's important to note that, although Dispenser loves caching, if you make it difficult for Dispenser to cache when using TinyMCE on the cloud, then you'll get worse performance.

So, before you leave, check out our 3 tips on how to make the most of our new infrastructure.

--

If you're not currently familiar with our editor, try it out and get your free API Key (including a trial of our premium plugins).

We're always looking for more ways to improve our products and how they are delivered to you. Feel free to reach out to us at any time to discuss.

Tiny CloudTinyMCE
Tim Dettrick
byTim Dettrick

Tim is a senior engineer developing and improving Tiny’s cloud offerings. His days involve using Haskell, containerization, and cloud infrastructure to tackle the challenge of building resilient systems that cope with how inconveniently large the Earth actually is.

Related Articles

  • Abstract depiction of man thinking about content types, beside a plant. by indianpix
    Trends & Inspiration

    How a great WYSIWYG editor can take your LMS to the next level

    by Ben Long in Trends & Inspiration

Build beautiful content for the web with Tiny.

The rich text editing platform that helped launch Atlassian, Medium, Evernote and more.

Begin my FREE 30 day trial
Tiny Editor