Skip to main content

August 17

Hi everyone, hope you're well! Mostly been doing ArtCentral stuff the last two weeks or so, update below. Split into a few different bits.

ArtCentral: Image resizing optimization

I wasn't entirely satisfied with the solution I had two weeks ago, as it had some inefficiencies that could be improved upon, and for the purpose of something as essential as this to an art website I felt I had to try and optimise it more, so I did.

Lambda memory testing

The first way to optimise it was to find out what memory setting was best for the resizing function. AWS Lambda allows you to set memory for the functions you want to run on it, and it allocates CPU power proportional to the amount of memory you allocated. However, it also charges you proportionally to the memory allocated to your function, so increasing the resources isn't always cost effective - there's a balance to be found.

For example, if doubling the memory and CPU allocated to a function decreases its execution time by 20%, you achieved a 20% performance boost but it's now costing you 100% more to run it, which isn't a great deal. To try and find the "optimal" value, I did some benchmarking: you can see some of the results here (boring stuff, but in case it interests you): https://docs.google.com/spreadsheets/d/11M8-5TVAabYg0NHLzGq0QDJB7GkSupL07cT8iKrQyKg/edit?usp=sharing 

From my testing, 1769MB (which allocates exactly one CPU core, or vCPU to be precise) was the best amount for this function. Values above that didn't decrease runtime by enough to be worth using; due to some region limits on first-time usage, I'm limited to 3008MB, when the usual AWS limit is 10240MB. I've asked them to remove that so I can test it, though I doubt it will be worth using more than 1769MB really.

As you can see in the spreadsheet, resizing very big images (like 40MB PNG files) can take several seconds to finish resizing to three different sizes; it's not especially desirable for the artwork submission page to take that long, so I found a way to reduce it somewhat.

Sharp buffer processing

The original code tutorials for this use case were built for general use - where you want to take one image and resize it to one new size. ArtCentral's use case is more specific; we need to be able to take one image and resize it to up to three different sizes, all conforming to the same aspect ratio limits. As a result, we don't actually need to read the image in three times - we can resize it, save, resize again, save, and resize once more. It took some time to figure out how to do this within the Sharp library, but it cuts around 20-25% off the total processing time (taking an image that takes ~7.7 seconds to resize to around ~5.7 seconds). This is achieved using buffers rather than streaming the data directly from Amazon S3.

This also comes with the bonus of using less HTTP requests, which Lambda charges for, and less time waiting for network requests.

Other considerations

As part of all this, another thing I had to consider is user experience. The ideal scenario is that image resizing, to the user, happens as a magic trick that is done instantly and never has to be waited for, but the reality doesn't make that possible.

If ArtCentral lazily processed images, i.e. only initially resized them when a user requested it, the user in question would be waiting several seconds before the server could send them the image, which would make them think the site was sluggish (and if the site got big, potentially comes with concurrency problems if several users try to view that image at the same time).

On the other hand, trying to eagerly process all images comes with a slight delay for artists when submitting artworks; while it's possible to do this asynchronously instead of waiting, the artist would then be greeted by their new artwork page with an artwork that isn't done resizing yet and can't be displayed, which wouldn't be a very optimal user experience. I think the optimal solution, therefore, is to have the artist wait a few seconds after pressing the Submit button when submitting an artwork, with clear UI feedback.

It's worth pointing out that being able to display images in 4K is likely to be a supporter-only feature (as it's expensive to display assets that large), and if an image doesn't need a resize to 4K that cuts down the resize time significantly, so this isn't as big a problem as it appears; it was just worth getting right the first time around instead of having to try and sort it out later. If an artist starts supporting the site later, it can batch process all their images to 4K and then update the image display URLs accordingly, so they seamlessly transition from 1080p to 4k over a time period of a few minutes without any service interruption for anyone.

Site appearance

With image resizing finally done and dusted, I've been tidying up the site interface a bit. Not being a UI designer, I'm extra aware of the fact that I need to try and make the website as responsive, unobtrusive and intuitive as I can make it, so that it's clear to the user what is going on whenever they do something.

I've made some progress bars for the upload pages, I need to integrate these into the settings pages for uploading profile pictures and possibly other use cases. I've also started defining some CSS rules for the site's standard button appearance and made some elements a bit prettier than they were before, though there's still plenty to do.

After that, it's time to try and finalise the look of the Gallery page. Most of the hard work is done for that page; I just need to decide on the layout of the user's socials area, add things like user location and other such information to the page, and that should mostly be it for that side of things. 

Still remaining to do, so far

Well, a lot. So far the site can register users, log them in, upload artwork and display both single artworks and user profiles, but there's way more that needs to be done:

  • On-site notifications: creating a notifications display page, figuring out how best to implement the notifications serverside in terms of database efficiency

  • Metrics: I specifically want to ensure that artists have a disable metrics option, but users should still be able to "like" posts to add them to a list, even if the "like" itself won't show to the artist. For the most part the site will keep metrics to a minimum.

  • Email notifications: I've looked into using Amazon SES to do this, which theoretically shouldn't be too bad, but I still need to investigate it further. This is another thing I plan to keep to a minimum as there's no real need to send lots of emails to users, and they'll all be opt-in emails outside of e.g. important security updates or such.

  • Multiple artwork display pages: for professionals and others who like to show e.g. progress images, a form of display artwork page that allows the display of multiple images will be needed. I'll need to try and adapt the current page to do this, so that there's a consistent feel when viewing artworks.

  • NSFW ratings and content hiding: this is easy enough conceptually, it'll just be a fair amount of work defining both a number of NSFW categories, backend database options for users to hide specific artworks they don't want to see, and frontend scripts to hide said content for them.

There's much, much more to do as well, but for now that's the main things in front of me to get on with. I'll try to prepare some videos or a temporary test website for the next few updates, just so you can get a basic idea of where all this stuff is leading.