Nginx works differently than Apache, mainly with regard to how it handles threads.
Nginx does not create new processes for each web request, instead the administrator configures how many worker processes to create for the main Nginx process. (One rule of thumb is to have one worker process for each CPU.) Each of these processes is single-threaded. Each worker can handle thousands of concurrent connections. It does this asynchronously with one thread, rather than using multi-threaded programming.
Nginx is said to be event-driven, asynchronous, and non-blocking. “Event” means a user connection. “Asynchronous” means that it handles user interaction for more than one user connection at a time. “Non-blocking” means it does not stop disk I/O because the CPU is busy; in that case, it works on other events until the I/O is freed up.
Apache creates processes and threads to handle additional connections. The administrator can configure the server to control the maximum number of allowable processes. This configuration varies depending on the available memory on the machine. Too many processes exhaust memory and can cause the machine to swap memory to disk, severely degrading performance. Plus, when the limit of processes is reached, Apache refuses additional connections.
Apache can be configured to run in pre-forked or worker multi-process mode (MPM). Either way it creates new processes as additional users connect. The difference between the two is that pre-forked mode creates one thread per process, each of which handles one user request. Worker mode creates new processes too, but each has more than one thread, each of which handles one request per user. So one worker mode process handles more than one connection and one pre-fork mode process handles one connection only.
Worker mode uses less memory than forked-mode, because processes consume more memory than threads, which are nothing more than code running inside a process.
Nginx and Apache
Apache is known for its power and Nginx for speed. This means Nginx can serve up static content quicker, but Apache includes the modules needed to work with back end application servers and run scripting languages.
Both Apache and Nginx can be used as proxy servers, but using Nginx as a proxy server and Apache as the back end is a common approach to take. Nginx includes advanced load balancing and caching abilities. Apache servers can, of course, be deployed in great numbers. A load balancer is needed in order to exploit this. Apache has a load balancer module too, plus there are hardware based load balancers.
Another configuration is to deploy Nginx with the separate php-fpm application. We say that php-fpm is an application, because it is not a .dll or .so loaded at execution time, as is the case with Apache modules. Php-fpm (the FastCGI Process Manager) can be used with Nginx to deliver php scripting ability to Nginx to render non-static content.
Apache Preferred over Nginx
Apache comes with built in support for PHP, Python, Perl, and other languages. For example, the mod_python and mod_php Apache modules process PHP and Perl code inside the Apache process. mod_python is more efficient that using CGI or FastCGI, because it does not have to load the Python interpreter for each request. The same is true for mod_rails and mod_rack, which give Apache the ability to run Ruby on Rails. These processes run faster inside the Apache process.
So if your website is predominately Python or Ruby, Apache might be preferred for your application, as Apache does not have to use CGI. For PHP, it does not matter as Nginx supports PHP internally.
CGI & Fast CGI vs PHP-FPM
PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busier sites.
These features include:
- Adaptive process spawning (NEW!)
- Basic statistics (ala Apache’s mod_status) (NEW!)
- Advanced process management with graceful stop/start
- Ability to start workers with different uid/gid/chroot/environment and different php.ini (replaces safe_mode)
- Stdout & stderr logging
- Emergency restart in case of accidental opcode cache destruction
- Accelerated upload support
- Support for a “slowlog”
- Enhancements to FastCGI, such as fastcgi_finish_request() – a special function to finish request & flush all data while continuing to do something time-consuming (video converting, stats processing, etc.)
The two protocols:
- CGI scripts is a way how to run a server side script when a HTTP request comes; this has nothing to do with PHP
- FastCGI is a “better CGI” – CGI is known to be slow, Fast CGI is a different approach with much faster results; this has also nothing to do with PHP.
Now the PHP related things:
- mod_php is running a PHP as Apache module – that is PHP request is run under Apache process with everything that goes with it – Apache processes are defined by Apache configuration, PHP is run with Apache permission etc.
- PHP-FPM is PHP’s FastCGI implementation; PHP-FPM runs as a standalone FastCGI server and Apache connects to the server using Apache’s module, usually mod_fcgid or mod_fastcgi; I personally think this is much better than running as mod_php, but it depends on your requirements and is also a little more complex; in this configuration, permission, processes related stuff & everything is run under PHP configuration, PHP user etc. & Apache connects to PHP as to a server; in this configuration it is also possible to have pool of PHP servers and to have PHP server on physically different machine than Apache. They say this is almost as fast as using Apache’s module and there are benefits of better control over PHP configuration.
PHP-FPM port vs socket
- When you are using TCP, you are also using the whole network stack. Even if you are on the same machine, this implies that packets are encapsulated and decapsulated to use the network stack and the related protocols.
- If you use unix domain sockets, you will not be forced to go through all the network protocols that are required otherwise. The sockets are identified solely by the inodes on your hard drive.
- Using a socket (e.g. listen = ‘/tmp/php-fpm.sock’) makes sense when both the front-end (e.g. Nginx) and php-fpm are in the same box and
- You have the option to scale horizontally both the front and back-end together (say you are building a container with both and you can create more containers, each with a working pair) or
- Your only option is to scale vertically the one “box” you are using (say, you add more CPU, RAM, etc)
- Using a TCP connection (e.g. listen = 127.0.0.1:9000) makes sense if you want to de-couple the front and the back-end, for example, if you decide to scale up your environment by having a single Nginx receiving connections and passing the work via the network to a cluster of php-fpm boxes