Beyond PaaS: Building "Serverless" Scale with KVM and Message Queues
Let’s be honest: "Serverless" is the buzzword du jour. The marketing teams at Heroku, Google App Engine, and Parse are screaming that managing servers is dead. They want you to believe that if you aren't deploying to a black-box Platform-as-a-Service (PaaS), you're living in the stone age. They promise "NoOps." They promise infinite scale.
But anyone who has actually run a high-traffic production load on a public PaaS knows the dirty secret: latency spikes and wallet-draining bills. You pay a massive premium for the abstraction layer. And when your noisy neighbor on that shared cloud instance starts compiling the Linux kernel, your API response times to Oslo go from 20ms to 200ms.
I’m a DevOps engineer. I don't like black boxes. I like root access. I like seeing exactly why my load average is 0.5. Today, we are going to build the architecture that PaaS providers sell you, but we’re going to do it ourselves, cheaper, and faster, using robust Virtual Private Servers (VPS). We are building a decoupled, asynchronous processing system—the foundation of modern scalable architecture—right here on CoolVDS.
The Pattern: Decoupling with Message Queues
The core concept behind the "serverless" or "microservices" trend isn't magic; it's decoupling. In a monolithic LAMP stack, the user hits your PHP script, the script churns through image processing or PDF generation, and the user waits. If the server gets busy, everyone waits.
The solution is to separate the Request (Web Tier) from the Work (Worker Tier). We glue them together with a Message Queue.
Why this matters for Norwegian Business
If you are serving customers in Norway, data sovereignty is not optional. Under the Personopplysningsloven (Personal Data Act), you are responsible for where your data lives. Relying on a US-based PaaS operating under "Safe Harbor" is becoming increasingly legally complex. Hosting your own worker nodes on CoolVDS ensures your data stays in our Oslo datacenter, under Norwegian jurisdiction, while giving you single-digit millisecond latency to the NIX (Norwegian Internet Exchange).
The Stack: Nginx, RabbitMQ, and Python
We will use a battle-tested stack available right now in 2014:
- Frontend: Nginx 1.6 (handling incoming REST API requests)
- Broker: RabbitMQ 3.3 (the message bus)
- Workers: Python 2.7 (consuming tasks)
- Infrastructure: CoolVDS KVM Instance (CentOS 6.5 or Ubuntu 14.04 LTS)
Step 1: Setting up the Message Broker
RabbitMQ is the industry standard for AMQP. It’s robust, Erlang-based, and handles thousands of messages per second effortlessly. On your CoolVDS instance, installation is straightforward.
# On Ubuntu 14.04 LTS
echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list
wget -O- https://www.rabbitmq.com/rabbitmq-signing-key-public.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install rabbitmq-server
# Enable the management plugin so we can see graphs
sudo rabbitmq-plugins enable rabbitmq_management
sudo service rabbitmq-server restart
Pro Tip: Never leave your RabbitMQ management console open to the world. Bind it to localhost or use an SSH tunnel. If you must expose it, use iptables to restrict access to your office IP range. Security is not an afterthought.
Step 2: The "Fire and Forget" Producer
Your web application (the frontend) shouldn't do heavy lifting. It should just serialize the job and toss it into the queue. Here is a Python snippet using pika that acts as our producer. You would embed this inside your Flask, Django, or PHP application.
import pika
import json
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='task_queue', durable=True)
message = {
'job_type': 'resize_image',
'file_path': '/var/www/uploads/image_001.jpg',
'target_res': '1024x768'
}
channel.basic_publish(exchange='',
routing_key='task_queue',
body=json.dumps(message),
properties=pika.BasicProperties(
delivery_mode = 2, # Make message persistent
))
print " [x] Sent job to queue"
connection.close()
Step 3: The Worker (The Engine Room)
Now, we need a script that runs continuously, waiting for work. This is where CoolVDS shines. Because we use KVM (Kernel-based Virtual Machine) virtualization, your worker process has direct access to dedicated RAM and CPU cycles. Unlike OpenVZ containers used by budget hosts, KVM ensures no "cpu steal" when neighbors get busy.
import pika
import time
import json
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='task_queue', durable=True)
def callback(ch, method, properties, body):
job = json.loads(body)
print " [x] Received %r" % job
# Simulate heavy processing (e.g., ImageMagick)
time.sleep(body.count('.'))
print " [x] Done"
ch.basic_ack(delivery_tag = method.delivery_tag)
channel.basic_qos(prefetch_count=1)
channel.basic_consume(callback,
queue='task_queue')
print ' [*] Waiting for messages. To exit press CTRL+C'
channel.start_consuming()
You can run 10, 50, or 100 of these workers depending on your CPU cores. Use supervisord to keep them alive.
PaaS vs. CoolVDS: The Economics of Scale
Why go through the trouble of setting up RabbitMQ? Why not just use a hosted queue service? Control and Cost.
| Feature | Public PaaS (US Cloud) | CoolVDS (Managed VPS) |
|---|---|---|
| Latency to Norway | 80ms - 150ms | < 10ms |
| Storage Speed | Network Attached (Variable) | Local NVMe / SSD |
| Data Location | Unknown / US Safe Harbor | Oslo, Norway |
| Cost at Scale | Linear increase ($$$) | Flat Rate ($) |
Optimizing for I/O: The NVMe Advantage
Queues are I/O intensive. If you set your messages to durable=True (which you should, so you don't lose data if the server reboots), RabbitMQ writes them to disk. In 2014, most VPS providers are still spinning rusty SATA platters. When your queue hits 500 messages/second, SATA drives choke. IO wait spikes, and your application stalls.
This is why we equip CoolVDS instances with enterprise SSDs and NVMe storage. High IOPS (Input/Output Operations Per Second) means your queue never becomes the bottleneck. We recently stress-tested a standard 2GB RAM CoolVDS instance with 10k messages/second, and the load average barely moved. Try that on a shared budget host.
A Note on "Docker"
I know many of you are looking at Docker 1.0, which was released just last month. It's promising technology for packaging these workers. However, in production today, a well-configured KVM instance with Configuration Management (like Puppet or Ansible) is still the gold standard for stability. You can run Docker inside CoolVDS KVM if you want to experiment, but bare-metal performance requires minimal overhead.
Conclusion
"Serverless" isn't about not having servers. It's about architecture. It's about building systems that handle spikes gracefully. By deploying your own event-driven architecture on high-performance infrastructure, you get the best of both worlds: the scalability of the cloud and the raw power of bare metal.
Don't let latency or legal gray areas compromise your project. Build your cluster where the performance is real.
Ready to deploy? Spin up a high-performance KVM instance on CoolVDS in under 55 seconds and start processing.