======================== Performance Improvements ======================== ------------ Module: core ------------ :Author: Jan Kneschke :Date: $Date: 2004/11/03 22:26:05 $ :Revision: $Revision: 1.3 $ :abstract: handling performance issues in lighttpd .. meta:: :keywords: lighttpd, performance .. contents:: Table of Contents Description =========== Performance Issues ------------------ lighttpd is optimized into various directions. The most important is performance. The operation system has two major facalities to help lighttpd a deliver it best performance. HTTP Keep-Alive --------------- Disabling keep-alive might help your server if you suffer from a large number of open file-descriptors. The defaults fo the server is: :: server.max-keep-alive-requests = 128 server.max-keep-alive-idle = 30 server.max-read-idle = 60 server.max-write-idle = 360 handling 128 keep-alive requests in a row on a single connection, waiting 30 seconds before a unused keep-alive connection get dropped by lighttpd. If you handle several connections at once under a high load (let's assume 500 connections in parallel for 24h) you might run into the out-of-fd problem described below. :: server.max-keep-alive-requests = 4 server.max-keep-alive-idle = 4 would release the connections earlier and would free file-descriptors without a to large performance loss. Disabling keep-alive completly is the last choice if you are still short in filedescriptors: :: server.max-keep-alive-requests = 0 Event Handlers -------------- The first one is the Event Handler which cares about notifying the server that one of the connections is ready to send or to recieve. As you can see every OS has at least the select() call which has some limitations. ============ ========== =============== OS Method Config-Value ============ ========== =============== all select select Unix poll poll Linux 2.4+ rt-signals linux-rtsig Linux 2.6+ epoll linux-sysepoll Solaris /dev/poll solaris-devpoll FreeBSD, ... kqueue freebsd-kqueue ============ ========== =============== For more infomation in this topic take a look at http://www.kegel.com/c10k.html Configuration ````````````` The event-handler can be set by specifying the 'Config-Value' from above in the ``server.event-handler`` variable e.g.: :: server.event-handler = "linux-sysepoll" Network Handlers ---------------- The basic network interface for all platforms at the syscalls read() and write(). Each modern OS provides its own syscall to help network servers to transfer files as fast as possible. If you want to send out a file from the webserver it does make any sense to copy the file into the webserver just to write() it back into a socket in the next step. sendfile() minimizes the work in the application and pushes a file directly into the network card (idealy spoken). lighttpd supports all major platform specific calls: ========== ========== OS Method ========== ========== all write Unix writev Linux 2.4+ sendfile Linux 2.6+ sendfile64 Solaris sendfilev FreeBSD sendfile ========== ========== They are selected automaticly on compile-time. If you have problems check ./src/network_backend.h and disable the corresponding USE\_... define. Max Connections --------------- As lighttpd is a single-threaded server its main resource limit is the number of file-descriptors which is (on most systems) set to 1024 by default. If you are running a high-traffic site you might want to increase this limit by setting :: server.max-fds = 2048 This only works if lighttpd is started as root. Out-of-fd condition ------------------- As fds are used for tcp/ip sockets, files, directories, ... a simple request for a PHP page might result in using 3 fds: 1. the TCP/IP socket to the client 2. the TCP/IP and Unix domain socket to the FastCGI process 3. the filehandle to the file in the document-root to check if it is really existing If lighttpd runs out of file-descriptors it will stop accepting new connections for while to use the currently available fds (file-descriptors) to handle the currently running requests. If more than 90% of the fds are used the the handling of new connections is disabled, if it dropes below 80% again new connection will accepted again. Under some circumstances you will see :: ... accept() failed: Too many open files in the error-log. This tells you the you had to many new requests at once and lighttpd could not disable the incomming connections soon enough. The connection is drop and the client will get a error-message like 'connection failed'. This is very rare and might only occur in test-setups. Increasing the ``server.max-fds`` limit will reduce the propability of this problem. Plattform Specific Notes ======================== Linux ----- For Linux 2.4.x should should think about compiling lighttpd with the option ``--disable-lfs`` to disable the support for files larger than 2Gb. lighttpd will fall back to the ``writev() + mmap()`` network calls which is ok, but not as fast as possible but support files larger than 2Gb. Disabling the TCP options reduces the overhead of each TCP packet and might help to get the last few percent of performance out of the server. - net.ipv4.tcp_sack = 0 - net.ipv4.tcp_timestamps = 0 Increasing the TCP send and receive buffers will increase the performance a lot if (and only if) you have a lot large files to send. - net.ipv4.tcp_wmem = 4096 65536 524288 - net.core.wmem_max = 1048576 If you have a lot large file uploads increasing the receive buffers will help. - net.ipv4.tcp_rmem = 4096 87380 524288 - net.core.rmem_max = 1048576 Keep in mind that the buffers have to multiplied by server.max-fds and be allocated in the Kernel area. Be carefull with that. FreeBSD ------- On FreeBSD you might gain some performance by enabling accept-filters. Just compile your kernel with: :: options ACCEPT_FILTER_HTTP For more ideas in tuning FreeBSD read: tuning(7) Reducing the recvspace should always be ok if the server only handles HTTP requests without large uploads. Increasing the sendspace would reduce the system-load if you have a lot large files to be sent, but keep in mind that you to provide the memory in kernel for each connection. 1024 * 64k would mean 64M of kernel-ram. Keep this in mind. - net.inet.tcp.recvspace = 4096