Of late, many mainstream distributions have been switching to Systemd as their init system. This includes Debian (since Debian 8) and Ubuntu (since Ubuntu 15.04). In the traditional SysV init system we used to have stuff like spawn-fcgi or custom scripts for starting a Fastcgi process and having the web server connect to it over Unix or TCP sockets. Such kind of usage decreased when PHP FPM was introduced since it’s safe enough to assume that 90% (probably more) of the FastCGI deployments are just launching PHP interpreters using whatever mechanism is there (spawn-fcgi or custom scripts). PHP FPM does this for you now and it’s pretty good at it.
Related Articles
FastCGI is just a protocol, it can be used by any application. For custom applications which do not support starting their own FastCGI processes and listening on a socket we have to use external mechanisms. SystemD has a couple of good features which can help reduce the amount of custom work needed in terms of process monitoring, socket paths, file ownership, etc.
My use case:
So I installed the support ticketing system called Request Tracker from Best Practical on a server, and initially using spawn-fcgi to start the FastCGI process and nginx to serve the site. I found problems quite fast: spawn-fcgi would create N number of processes which are listening on the given socket, but there’s no re-launching mechanism if the processes die. Applications can crash any time, so we need something to relaunch. The traditional options would have been to use something like a cron job to monitor the PID file or use monit, there are many options. Then I came across this article by the spawn-fcgi people about how to use SystemD to start a FastCGI process.
Once again, a custom script is involved. Digging through SystemD documentation and some more Googling, I was able to get the FastCGI process spawning working using SystemD without any external dependencies (no extra scripts, etc). Here’s how:
[Unit] Description = Request Tracker FastCGI backend After = postgresql.service Wants = postgresql.service [Service] User = rt Group = rt ExecStart = /usr/local/rt/sbin/rt-server.fcgi StandardOutput = null StandardInput = socket StandardError = null Restart = always [Install] WantedBy = multi-user.target
[Unit] Description = RT FastCGI Socket [Socket] SocketUser = www-data SocketGroup = www-data SocketMode = 0660 ListenStream = /run/rt.sock [Install] WantedBy = sockets.target
If you do systemctl enable rt-fastcgi.socket && systemctl start rt-fastcgi.socket then you should have the RT process started up by SystemD when the first request arrives from the web server at /run/rt.sock , and the process keeps running listening for further requests. It gets restarted automatically in case if it crashes or is issued a SIGTERM manually (which is needed if you make changes to the configuration file).
The problem with this setup:
If you see the difference between this method and the spawn-fcgi method, you will observe that while it is possible to spawn multiple request handlers (i.e. multiple RT processes which can serve the web server) using a single command but the same is not possible with this SystemD method. The daemon being spawned by SystemD must do this extra handling. A single process cannot serve many concurrent requests which is definitely a problem. So let’s use SystemD’s automatic unit files based on per instance feature to make it multiple processes:
[Unit] Description = Request Tracker FastCGI backend (instance %i) After = postgresql.service Wants = postgresql.service [Service] User = rt Group = rt ExecStart = /usr/local/rt/sbin/rt-server.fcgi StandardOutput = null StandardInput = socket StandardError = null Restart = always [Install] WantedBy = multi-user.target
[Unit] Description = RT FastCGI Socket (instance %i) [Socket] SocketUser = www-data SocketGroup = www-data SocketMode = 0660 ListenStream = /run/rt%i.sock [Install] WantedBy = sockets.target
What the above setup would do is, listen for requests on multiple sockets at /run/rt%i.sock and spawn the appropriate number of instances. How to use this feature from nginx? Here’s how:
upstream rt_backend { server unix:/run/rt1.sock; server unix:/run/rt2.sock; server unix:/run/rt3.sock; server unix:/run/rt4.sock; server unix:/run/rt5.sock; } server { # other stuff whatever needed location / { include fastcgi_params; fastcgi_param SCRIPT_NAME ""; fastcgi_param PATH_INFO $uri; #fastcgi_pass unix:/run/rt.sock; fastcgi_pass rt_backend; } }
Then just do systemctl enable rt-fastcgi@{1..N}.socket && systemctl start rt-fastcgi@{1..N}.socket , start firing requests from nginx and you should see the number of processes growing because nginx sends requests to the upstream in a Round Robin fashion (which can be changed, of course. Refer to nginx documentation for that).
The post SystemD Fastcgi Multiple Processes appeared first on Nilesh.