High-performance Dancer apps
Using or considering using Dancer in a high-traffic environment? There are some techniques you can use to help ensure good performance, which will be documented here.
Some of these tips are based on a Dancer application in production at work - in a couple of months it's answered over 40 million requests for several hundred thousand individual domain names, so it's battle-proven.
Handle static files via the webserver
For performance, you want your application's static files (images, Javascript, CSS etc) to be served up by your webserver, e.g. Nginx, rather than being passed to your Dancer app to serve.
A short example Nginx configuration:
server { listen 80; server_name foo.example.com; location / { # Serve static files directly: if (-f $request_filename) { expires 30d; break; } # Pass on other requests to Dancer app proxy_pass_header Server; proxy_pass http://localhost:3000/; } }
Similiar configuration methods should work with other deployment methods.
Run under a suitable backend
For high-load situations, you'll want to be running under a suitable Plack back-end. Starman is a very high performance backend, and is recommended.
A simple "hello world" benchmark test in the Starman documentation shows it capable of handling over 6800 requests per second. Naturally, with a real-world more complex app, you're not going to achieve quite that level of performance.
Pre-load your application
When running with Starman, you can pre-load your application before forking worker processes, to increase performance and provide memory savings with copy-on-write memory management.
Use Starman's --preload-app
option to enable this (but be aware that this can
cause Bad Things to happen if resources like database connections or other
sockets are opened by your app at compile time, as they will be unintentionally
shared amongst child processes. Dancer::Plugin::Database contains code to
ensure fork/thread safety, so you should be safe if using that plugin to manage
your database connections.
You can also pre-load individual modules using plackup
's -M
for similar
effect:
starman -MDancer -MMoose -MFoo myapp.psgi
Caching
Using Dancer::Plugin::Cache::CHI to cache data and responses as much as possible (using a backend like Memcached) can save a lot of execution time, and help your application to handle more requests, faster.
A simple example to cache a whole page response:
# Arrange for the cache to be consulted for a matching response before route # handlers are invoked: check_page_cache(); get '/foo' => sub { my $data = some_expensive_slow_function(); my $content = template 'foo', $data; cache_page $content; return $content; };
Profile your app to find bottlenecks
As covered previously, Dancer::Plugin::NYTProf can be useful to profile your Dancer applications and see where time is spent to identify bottlenecks where a little optimisation can pay off.
AUTHOR
David Precious, <davidp@preshweb.co.uk>