NodeJS and Nginx Image Server
Recently at work I took a project that had the potential to dramatically streamline a process that is a major portion of our business. Construct a new on-demand image watermarking and caching server. First some backstory on what I do and our current process for watermarking images.
I work for a startup in Silicon Valley as a Sr. Software Engineer. Startups being startups I wear multiple hats (Everything from infrastructure management to running ethernet cables and setting up access points in our warehouses). We have a large home grown ERP system that allows for selling of inventory on multiple ecommerce platforms for multiple seller accounts. We handle everything from order fulfillment, automatically revising and listing items on multiple selling platforms, to inventory management and warehousing.
Images are naturally a very important portion of our business. Our old process was cumbersome and made it incredibly difficult and time consuming to add a new seller account and watermark existing product images. Here is a brief description of the old process:
1) User uploads SKU images to a FTP server
2) User selects which watermarks to apply to these images and processes them
3) Watermarked SKU images are uploaded to a CDN container for their appropriate seller.
This process worked fine for a while… until we started to grow. Adding a new seller account meant running a script for days to apply a new watermark to pre-existing images and upload them to a new CDN container.
Nginx does a lot of the heavy lifting here. I will attempt to explain this as clear as possible, but for security and IP reasons I cannot get into the specifics of domains or anything like that. Basically when Nginx receives a request it extracts a few things the seller, the last three digits of the SKU, and the requested image. It then uses the ‘try files’ directive to attempt to locate a cached copy of the file within the seller’s virtual host from a folder/bucket based on the last three digits of the SKU. If this image is not found Nginx then takes the extracted information and passes it to the Node service that then watermarks the image, saves it to the appropriate bucket within the seller’s virtual host and serves it back to the user. The below diagram can help illustrate the whole process.
This is basically it, very few components to the system. The only other piece to the system is a simple bash script which runs every two minutes to detect new images and clear the cache. For the Node piece I utilized Express JS. The actual watermarking is being done by a Node GD port called Easy GD. The NPM page for Easy-GD contains sample code that shows exactly how to overlay a watermark on an image. The cache buckets are created by Node on the fly if they do not exist, and the system also handles thumbnails. Monit and Upstart are being used to keep the node service running and provide alerts in case of failure. This tutorial, helped in setting that up, although it was relatively simple.
How has it been running?
The system has been live for about 5 days now. It runs on dedicated hardware. Here are the specs:
4 Gb Ram
On a normal day it appears to have a RAM footprint of around 1.5Gb. Under peak load I have seen things top out at around 3.5Gb but usually for no longer than a few minutes. CPU usage is incredibly low. When watermarking images, usage will spike to about 30% and then quickly drop back down.
Overall our users seem happy with the new simpler process (They just have to upload photos now), and the system has been running incredibly well. Nginx and Node are a great combination for something like this.