This article is a primer on using monit to monitor unix processes. Specifically it shows how monit can be used to improve the stability and availability of a Ruby on Rails web application. All of the techniques discussed would be equally applicable to monitoring almost any other type of Unix process.
Why could monit be useful for me?
You run a web application on Slicehost, Linode or a similar VPS. Perhaps you run your own dedicated server. You want to ensure that your application is available at all times. This means that both front and backend servers must be running constantly, and support processes (such as memcached, Sphinx, mysql, etc) must always be available.
These processes are system-critical. If any of them fail, your web application will partly or wholly stop functioning. In an e-commerce site that may mean significant loss of sales. In any website it's most definitely bad news. Monit can help to avoid it happening, and this article shows how.
The following is the desired outcome: In the event that any of the above processes crash or otherwise stop functioning, they should be automatically restarted by monit. In the worst case scenario, where monit can't restart one or more automatically, an email should be sent warning that manual intervention is required.
Furthermore, if for some reason the server is rebooted without your knowledge, monit should automatically re-launch each of the components required for full functionality. So if Slicehost ever reboots your slice in the middle of the night, it won't be 8 hours before anybody can use your website again.
Why not God?
God is an open-source system-monitoring tool written in Ruby.
I have never used God, but I am familiar with the nature of the Ruby programming language. Ruby is an expressive and powerful language which is perfectly suited to the task of building certain classes of system utilities and web applications. It is also an integral component of the web application
I am currently developing .
Ruby does have certain drawbacks however. Specifically, the standard (MRI) installation tends to create memory leaks and bloat, especially in long-running Ruby processes. Of course this includes such important processes as web servers -- and even system monitoring tools themselves. This includes God.
Here is an angry, but interesting, write-up of the problem which contains more than a grain of truth.
My recent experience suggests that deploying using the free
Ruby Enterprise Edition, significantly reduces the problem of memory leaks in long-running processes. However, apart from being the topic for a different blog post, this does not alter my conclusion that given a feasible non-Ruby alternative, avoiding the use of Ruby in a system-monitoring tool is a definite advantage.
This is precisely the train of thought which led me to evaluate monit.
What is monit?
Monit is an open-source utility for managing and monitoring processes, files, directories and more. It is written in C, and so neatly sidesteps the problem of Ruby's stability. Monit is capable of a lot more than I will cover here. You should note that I used the software for the first time only a few hours ago. While this means I am far from an expert, it also illustrates the simplicity of getting started.
I have sometimes heard about the supposed complexity of Monit configuration files. This put me off trying the software in the past. It is a myth. Monit configuration files are simple, and easy to create. There is nothing to fear.
How do I get started?
Download, compile and install monit. You may wish to carry this out on your server.
Here, I will illustrate how to monitor a full Ruby on Rails web application, including the frontend server (nginx), backend server (unicorn), Redis, a Node.js component, and a Resque message queue worker.
Create a monit configuration file in a suitable location. Inside it, add something like this:
The first line tells monit to check all processes every 30 seconds. The second line tells it to use the local mail server (I used the one-line postfix installation illustrated which worked perfectly).
Line four sets the location of the log file (tail it). Finally, lines 7-8 set up a web interface which allow you to remotely monitor and restart your server processes, without requiring an SSH connection:
Useful, huh?
Important note: The following is not a one-size fits-all recipe for every web server. Copy-and-pasting without examining and adapting for your own circumstances, is unlikely to work well, if at all. The examples may, however, be useful as pointers. I adapted them from
this old, but useful article.
Nginx
First of all let's monitor our front-end web server. In this case it's Nginx, which is usually reasonably stable, but it could just as well be Apache which can be slightly less so. Add the following to your monit.conf:
You will need to gsub the location of your nginx pidfile, and the commands to start and stop nginx on your server. As well as checking the process is running, I have monit attempt to download an empty text file ping.txt in the root html directory. If this file is unavailable then nginx will be instantly restarted.
Unicorn
Unicorn is a
pre-forking unix http server which can be easily configured to serve Ruby on Rails applications. The following configuration could be readily adapted to monitor a cluster of Mongrel or thin servers. Here is the monit.conf snippet:
Nginx needs to be run as root, but I don't want to run my Rails apps with superuser priveleges. The as uid deploy and gid deploy commands ensure that they are launched as user:group deploy:deploy.
I have Unicorn configured to serve through a unix socket, but it also listens on port 7070. That means that hitting mydomain.com:7070 bypasses Nginx, and serves the Rails app directly from Unicorn. This is useful for testing: I configured a simple metal action to serve an empty 200 response to the route /ping_rails. If this action fails for any reason, Unicorn will be restarted immediately, and I will be emailed.
Redis
Redis is a persistent key-value store which while very stable is also integral to the functionality of my application. The setup to monitor Redis is simpler:
Node.js
Node.js handles uploading and processing uploaded files, an integral part of my web application. This was the trickiest configuration to get working. I found the easiest way to get a pidfile was to write it from within the node.js script itself:
Then add the following to your monit.conf:
I was unable to get monit to launch node directly, but wrapping it in a simple bash script which set the current working directly correctly worked fine.
Resque
Resque is a Rails background queue worker which uses Redis to run Rails actions in the background, detached from the HTTP request cycle. It is important to the functioning of my website (for example, it is responsible for sending all outbound emails). Again, setting up monit was a little tricky. Resque is launched via a rake task, but I needed to somehow write a pidfile for monit to use. When I wrapped it in a simple Ruby script which wrote a pidfile and launched the rake task, I found that rake was launched in a different process to the Ruby script, meaning that monit couldn't see that Resque had launched successfully, and kept needlessly trying to restart it.
This seemed to be solved by using the backtick form of shelling out a command from a Ruby script. Here is my start-resque script:
And then the monit.conf snippet:
Ready? Go
You can launch monit at any time with monit -c /your/monit.conf. Tail the log that you set up in the first step and try killing nginx. If monit is working, you will watch it automatically restart. Don't forget to check your inbox, and check out the web interface on yourdomain.com:6789.
Launching monit on start-up
An integral part of this strategy is for monit to start automatically if my server is rebooted. Once it starts, it will automatically nudge all of the above processes into action and effectively boot your entire application.
To achieve this I added the following line to /etc/crontab:
Conclusions
I have not yet deployed monit into a production environment but I am confident of its prospects.
Contrary to my previous misconception, monit is easy to install and configure. And being written in C it stands a good chance of standing up to the strain of a heavyweight server environment.
Running a monitoring tool such as this is essential for any kind of mission-critical web application, and I am only surprised that I have not delved into monit until now. If you need to ensure the availability of any kind of unix system process, then I recommend you consider using monit.