Nginx Tuning: A Performance Optimization Guide

         Most Nginx installation guides tell you the basics—install via apt-get, tweak a few lines of config here and there, and voilà, you have a web server! And, in most cases, a default Nginx installation will serve your website just fine. However, if you truly want to squeeze every ounce of performance out of Nginx, you have to dig a little deeper. In this guide, I’ll explain which Nginx settings can be fine-tuned to optimize performance when handling a large number of clients. Keep in mind, this is not a comprehensive tuning guide. It’s a quick overview—a summary of the settings that can be tweaked to improve performance. Your mileage may vary.

Basic (Optimized) Configuration

The only file we will modify is nginx.conf, which contains all the settings for Nginx’s various modules. You should be able to find nginx.conf in your server’s /etc/nginx directory. First, we’ll discuss some global settings, and then go module by module through the file to talk about which settings can give you great performance with a high volume of clients and why they improve performance. A complete configuration file is provided at the end of this article.

Top-level Configuration

In the nginx.conf file, there are a few high-level configurations placed above the module sections.

  1. user www-data; 
  2. pid /var/run/nginx.pid; 
  3. worker_processes auto; 
  4. worker_rlimit_nofile 100000; 

user and pid should be left at their defaults – we won’t change these because changing them makes little difference.

worker_processes defines the number of worker processes Nginx will use to serve web requests. The optimal value depends on many factors, including (but not limited to) the number of CPU cores, the number of hard drives storing data, and the load pattern. When in doubt, setting it to the number of available CPU cores is a good start (setting it to “auto” will try to detect it automatically).

worker_rlimit_nofile changes the maximum number of open files for worker processes. If this isn’t set, the value defaults to the operating system limit. Setting this allows your OS and Nginx to handle more files than “ulimit -a” would normally allow, preventing Nginx from encountering “too many open files” errors.

Events Module

The events module contains all the settings for handling connections in Nginx.

  1. events { 
  2. worker_connections 2048; 
  3. multi_accept on; 
  4. use epoll; 

worker_connections sets the maximum number of simultaneous connections that can be opened by a single worker process. If we have set the worker_rlimit_nofile mentioned above, we can set this value quite high.

Keep in mind that the maximum number of clients is also limited by the available socket connections on the system (~ 64K), so setting an unrealistically high value offers no benefit.

multi_accept tells Nginx to accept as many connections as possible after getting a new connection notification.

use sets the polling method used for multiplexing client threads. If you use Linux 2.6+, you should use epoll. If you use *BSD, you should use kqueue. Want to know more about event polling? Check out Wikipedia (note, understanding everything might require a neckbeard and some operating system course fundamentals).

(It’s worth noting that if you don’t know which polling method Nginx should use, it will automatically choose the one best suited for your OS.)

HTTP Module

The HTTP module controls all the core features of Nginx’s HTTP processing. Since there are quite a few configurations here, we’ll only excerpt a small portion. All of these settings should be placed inside the http block, although you might not specifically notice this section of settings.

  1. http { 
  2. server_tokens off; 
  3. sendfile on; 
  4. tcp_nopush on; 
  5. tcp_nodelay on; 
  6. … 

server_tokens  doesn’t make Nginx run faster, but it turns off the Nginx version number on error pages, which is beneficial for security.

sendfile enables the use of sendfile(). sendfile() copies data between one file descriptor and another, such as between a disk and a TCP socket. Pre-sendfile, data would be read into a user-space buffer before being transmitted, using read() to copy from the file into the buffer, and then write() to send the buffer data to the network. sendfile() immediately reads data from the disk into the OS cache. Because this copying happens within the kernel, sendfile() is more efficient than combining read() and write() along with opening, closing, and discarding buffers (more on sendfile).

tcp_nopush tells Nginx to send all header files in one data packet, rather than sending them one by one.

tcp_nodelay tells Nginx not to buffer data but to send it in small segments—this should be set for applications where timely delivery of data is critical, preventing small chunks of information from not getting an immediate return value.

  1. access_log off; 
  2. error_log /var/log/nginx/error.log crit; 

access_log sets whether Nginx will store access logs. Turning this off can make read/write disk I/O operations faster (aka, YOLO).

error_log tells Nginx to record only critical errors:

  1. keepalive_timeout 10; 
  2. client_header_timeout 10; 
  3. client_body_timeout 10; 
  4. reset_timedout_connection on; 
  5. send_timeout 10; 

keepalive_timeout  assigns the timeout for keep-alive connections with a client. The server will close the connection after this timeout expires. Setting this low allows Nginx to keep working persistently for longer.

client_header_timeout and client_body_timeout set the timeout for the request header and request body (respectively). We can set these low as well.

reset_timeout_connection tells Nginx to close connections with unresponsive clients. This frees up the memory space occupied by that client.

send_timeout specifies the response timeout to the client. This setting doesn’t apply to the entire transfer but only between two successive read operations from the client. If the client does not read any data during this period, Nginx closes the connection.

  1. limit_conn_zone $binary_remote_addr zone=addr:5m; 
  2. limit_conn addr 100; 

limit_conn_zone sets the parameters for a shared memory zone that stores the state for various keys (like the current number of connections). 5m is 5 megabytes, and this value should be set large enough to store (32K*5) 32-byte states or (16K*5) 64-byte states.

limit_conn sets the maximum number of connections for a given key. Here the key is addr, and we set the value to 100, meaning we allow a maximum of 100 simultaneous connections per IP address.

  1. include /etc/nginx/mime.types; 
  2. default_type text/html; 
  3. charset UTF-8; 

include is just an instruction to include the contents of another file in the current one. Here we use it to load a list of MIME types for later use.

default_type sets the default MIME-type for files.

charset sets the default character set in our header files.

The following two points for performance enhancement are explained over at the great WebMasters StackExchange.

  1. gzip on; 
  2. gzip_disable "msie6"; 
  3. # gzip_static on; 
  4. gzip_proxied any; 
  5. gzip_min_length 1000; 
  6. gzip_comp_level 4; 
  7. gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 

gzip tells Nginx to send data using gzip compression. This will reduce the amount of data we send.

gzip_disable disables gzip for specified clients. We set it to IE6 or lower to make our solution broadly compatible.

gzip_static tells Nginx to look for pre-gzipped resources before compressing assets on the fly.This requires you to pre-compress your files (commented out in this example), allowing you to use the highest compression ratio so that Nginx no longer needs to compress these files on the fly (for more detailed information about gzip_static, click here).

gzip_proxied Allows or disallows compression of response streams based on the request and response. We set it to any, meaning all requests will be compressed.

gzip_min_length Sets the minimum number of bytes before data compression is enabled. If a request is smaller than 1000 bytes, it’s better not to compress it, as compressing such small data can slow down all processes handling this request.

gzip_comp_level Sets the data compression level. This level can be any value from 1 to 9, with 9 being the slowest but offering the highest compression ratio. We set it to 4, a balanced setting.

gzip_type Sets the data formats to be compressed. Some are already listed in the example above, and you can add more formats as needed.

  1. # cache informations about file descriptors, frequently accessed files 
  2. # can boost performance, but you need to test those values 
  3. open_file_cache max=100000 inactive=20s
  4. open_file_cache_valid 30s; 
  5. open_file_cache_min_uses 2; 
  6. open_file_cache_errors on; 
  7. ## 
  8. # Virtual Host Configs 
  9. # aka our settings for specific servers 
  10. ## 
  11. include /etc/nginx/conf.d/*.conf; 
  12. include /etc/nginx/sites-enabled/*; 

open_file_cache Opens the cache while also specifying the maximum number of cached items and the cache duration. We can set a relatively high maximum time so that inactive entries are cleared after 20 seconds.

open_file_cache_valid Specifies the interval for checking the validity of information within open_file_cache.

open_file_cache_min_uses Defines the minimum number of file accesses during the inactivity period defined in the open_file_cache directive parameters.

open_file_cache_errors Specifies whether to cache error information when searching for a file, including adding files to the configuration again. We also include server modules defined in separate files. If your server modules are not in these locations, you must modify this line to specify the correct path.

A Complete Configuration

  1. user www-data; 
  2. pid /var/run/nginx.pid; 
  3. worker_processes auto; 
  4. worker_rlimit_nofile 100000; 
  5. events { 
  6. worker_connections 2048; 
  7. multi_accept on; 
  8. use epoll; 
  9. http { 
  10. server_tokens off; 
  11. sendfile on; 
  12. tcp_nopush on; 
  13. tcp_nodelay on; 
  14. access_log off; 
  15. error_log /var/log/nginx/error.log crit; 
  16. keepalive_timeout 10; 
  17. client_header_timeout 10; 
  18. client_body_timeout 10; 
  19. reset_timedout_connection on; 
  20. send_timeout 10; 
  21. limit_conn_zone $binary_remote_addr zone=addr:5m; 
  22. limit_conn addr 100; 
  23. include /etc/nginx/mime.types; 
  24. default_type text/html; 
  25. charset UTF-8; 
  26. gzip on; 
  27. gzip_disable "msie6"; 
  28. gzip_proxied any; 
  29. gzip_min_length 1000; 
  30. gzip_comp_level 6; 
  31. gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 
  32. open_file_cache max=100000 inactive=20s
  33. open_file_cache_valid 30s; 
  34. open_file_cache_min_uses 2; 
  35. open_file_cache_errors on; 
  36. include /etc/nginx/conf.d/*.conf; 
  37. include /etc/nginx/sites-enabled/*; 

After editing the configuration, make sure to restart Nginx for the settings to take effect.

  1. sudo service nginx restart 

Afterword

That’s it! Your web server is now ready for the flood of visitors that were previously troubling you. This is not the only way to speed up a website, and soon I will write more articles introducing other methods to accelerate your website.

Original link: http://blog.zachorr.com/nginx-setup/

Leave a Comment

Your email address will not be published.