{"id":124,"date":"2012-06-11T03:16:58","date_gmt":"2012-06-11T03:16:58","guid":{"rendered":"http:\/\/rmohan.com\/?p=124"},"modified":"2012-06-11T03:28:55","modified_gmt":"2012-06-11T03:28:55","slug":"apache-performance-tuning","status":"publish","type":"post","link":"https:\/\/mohan.sg\/?p=124","title":{"rendered":"Apache Performance Tuning"},"content":{"rendered":"<p><strong>Apache Performance Tuning<\/strong><\/p>\n<p><strong>Forewarning:<\/strong><\/p>\n<p><strong>    &#8220;Premature optimization is the root of all evil.&#8221; &#8212; Donald Knuth.<\/strong><\/p>\n<p>Select MPM<br \/>\nChose the right MPM for the right job:<br \/>\nprefork [default MPM for Apache 2.0 and 1.3]:<br \/>\n\u2022\tApache 1.3-based.<br \/>\n\u2022\tMultiple processes, 1 thread per process, processes handle requests.<br \/>\n\u2022\tUsed for security and stability.<br \/>\n\u2022\tHas higher memory consumption and lower performance over the newer Apache 2.0-based threaded MPMs.<br \/>\nworker:<br \/>\n\u2022\tApache 2.0-based.<br \/>\n\u2022\tMultiple processes, many threads per process, threads handle requests.<br \/>\n\u2022\tUsed for lower memory consumption and higher performance.<br \/>\n\u2022\tDoes not provide the same level of isolation request-to-request, as a process-based MPM does.<br \/>\nwinnt:<br \/>\n\u2022\tThe only MPM choice under Windows.<br \/>\n\u2022\t1 parent process, exactly 1 child process with many threads, threads handle requests.<br \/>\n\u2022\tBest solution under Windows, as on this platform, threads are always &#8220;cheaper&#8221; to use over processes.<br \/>\nConfigure MPM<br \/>\nCore Features and Multi-Processing Modules<br \/>\nDefault Configuration<br \/>\n<IfModule prefork.c><br \/>\n  StartServers            8<br \/>\n  MinSpareServers         5<br \/>\n  MaxSpareServers        20<br \/>\n  MaxClients            150<br \/>\n  MaxRequestsPerChild  1000<br \/>\n<\/IfModule><\/p>\n<p><IfModule worker.c><br \/>\n  StartServers            2<br \/>\n  MaxClients            150<br \/>\n  MinSpareThreads        25<br \/>\n  MaxSpareThreads        75<br \/>\n  ThreadsPerChild        25<br \/>\n  MaxRequestsPerChild     0<br \/>\n<\/IfModule><\/p>\n<p><IfModule mpm_winnt.c><br \/>\n  ThreadsPerChild       250<br \/>\n  MaxRequestsPerChild     0<br \/>\n<\/IfModule><br \/>\n<strong><\/p>\n<p>Directives<\/strong><\/p>\n<p><strong>MaxClients, for prefork MPM<\/strong><\/p>\n<p>MaxClients sets a limit on the number of simultaneous connections\/requests that will be served.<\/p>\n<p>I consider this directive to be the critical factor to a well functioning server. Set this number too low and resources will go to waste. Set this number too high and an influx of connections will bring the server to a stand still. Set this number just right and your server will fully utilize the available resources.<\/p>\n<p>An approximation of this number should be derived by dividing the amount of system memory (physical RAM) available by the maximum size of an apache\/httpd process; with a generous amount spared for all other processes.<\/p>\n<p><strong>MaxClients ? (RAM &#8211; size_all_other_processes)\/(size_apache_process) <\/strong><\/p>\n<p>Use &#8216;ps -ylC httpd &#8211;sort:rss&#8217; to find process size. Divide number by 1024 to get megabytes. Also try &#8216;top&#8217;.<br \/>\nUse &#8216;free -m&#8217; for a general overview. The key figure to look at is the buffers\/cache used value.<\/p>\n<p>Use &#8216;vmstat 2 5&#8217; to display the number of runnable, blocked, and waiting processes; and swap in and swap out.<br \/>\nExample:<br \/>\n\u2022\tSystem: VPS (Virtual Private Server), CentOS 4.4, with 128MB RAM<br \/>\n\u2022\tApache: v2.0, mpm_prefork, mod_php, mod_rewrite, mod_ssl, and other modules<br \/>\n\u2022\tOther Services: MySQL, Bind, SendMail<br \/>\n\u2022\tReported System Memory: 120MB<br \/>\n\u2022\tReported httpd process size: 7-13MB<br \/>\n\u2022\tAssumed memory available to Apache: 90MB<br \/>\nOptimal settings:<br \/>\n\u2022\tStartServers 5<br \/>\n\u2022\tMinSpareServers 5<br \/>\n\u2022\tMaxSpareServers 10<br \/>\n\u2022\tServerLimit 15<br \/>\n\u2022\tMaxClients 15<br \/>\n\u2022\tMaxRequestsPerChild 2000<\/p>\n<p>With the above configuration, we start with 5-10 processes and set a top limit of 15. Anything above this number will cause serious swapping and thrashing under a load; due to the low amount of RAM available to the [virtual] Server. With a dedicated Server, the default values [ServerLimit 256] will work with 1-2GB of RAM.<\/p>\n<p>When calculating MaxClients, take into consideration that the reported size of a process and the effective size are two different values. In this setup, it might be safe to use 20 or more workers&#8230; Play with different values and check your system stats.<\/p>\n<p>Note that when more connections are attempted than there are workers, the connections are placed into a queue. The default queue size value is 511 and can be adjusted with the ListenBackLog directive.<br \/>\nThreadsPerChild, for winnt MPM<br \/>\nOn the Windows side, the only useful directive is ThreadsPerChild, which is usually set to a value of 250 [defaults to 64 without a value]. If you expect more, or less, concurrent connections\/requests, set this directive appropriately. Check process size with Task Manager, under different values and server load.<br \/>\nMaxRequestsPerChild<br \/>\nDirective MaxRequestsPerChild is used to recycle processes. When this directive is set to 0, an unlimited amount of requests are allowed per process.<br \/>\nWhile some might argue that this increases server performance by not burdening Apache with having to destroy and create new processes, there is the other side to the argument&#8230;<br \/>\nSetting this value to the amount of requests that a website generates per day, divided by the number of processes, will have the benefit of keeping memory leaks and process bloat to a minimum [both of which are a common problem]. The goal here is to recycle each process once per day, as apache threads gradually increase their memory allocation as they run.<br \/>\nNote that under the winnt MPM model, recycling the only request serving process that Apache contains, can present a problem for some sites with constant and heavy traffic.<br \/>\nRequests vs. Client Connections<br \/>\nOn any given connection, to load a page, a client may request many URLs: page, site css files, javascript files, image files, etc.<br \/>\nMultiple requests from one client in rapid succession can have the same effect on a Server as &#8220;concurrent&#8221; connections [threaded MPMs and directive KeepAlive taken into consideration]. If a particular website requires 10 requests per page, 10 concurrent clients will require MPM settings that are geared more towards 20-70 clients. This issue manifests itself most under a process-based MPM [prefork].<\/p>\n<p>Separate Static and Dynamic Content<\/p>\n<p>Use separate servers for static and dynamic content. Apache processes serving dynamic content will carry overhead and swell to the size of the content being served, never decreasing in size. Each process will incur the size of any loaded PHP or Perl libraries. A 6MB-30MB process size [or 10% of server&#8217;s memory] is not unusual, and becomes a waist of resources for serving static content.<br \/>\nFor a more efficient use of system memory, either use mod_proxy to pass specific requests onto another Apache Server, or use a lightweight server to handle static requests:<br \/>\n\u2022\tlighttpd [has experimental win32 builds]<br \/>\n\u2022\ttux [patched into RedHat, runs inside the Linux kernel and is at the top of the charts in performance]<br \/>\nThe Server handling the static content goes up front.<br \/>\nNote that configuration settings will be quite different between a dynamic content Server and a static content Server<\/p>\n<p><strong>mod_deflate<\/strong><\/p>\n<p>Reduce bandwidth by 75% and improve response time by using mod_deflate.<br \/>\nLoadModule deflate_module modules\/mod_deflate.so<br \/>\n<Location \/><br \/>\nAddOutputFilterByType DEFLATE text\/html text\/plain text\/css text\/xml application\/x-javascript<br \/>\n<\/Location><br \/>\nLoaded Modules<br \/>\nReduce memory footprint by loading only the required modules.<br \/>\nSome also advise to statically compile in the needed modules, over building DSOs (Dynamic Shared Objects). Very bad advice. You will need to manually rebuild Apache every time a new version or security advisory for a module is put out, creating more work, more build related headaches, and more downtime.<br \/>\nmod_expires<br \/>\nInclude mod_expires for the ability to set expiration dates for specific content; utilizing the &#8216;If-Modified-Since&#8217; header cache control sent by the user&#8217;s browser\/proxy. Will save bandwidth and drastically speed up your site for [repeat] visitors.<br \/>\nNote that this can also be implemented with mod_headers.<br \/>\nKeepAlive<br \/>\nEnable HTTP persistent connections to improve latency times and reduce server load significantly [25% of original load is not uncommon].<br \/>\nprefork MPM:<br \/>\nKeepAlive On<br \/>\nKeepAliveTimeout 2<br \/>\nMaxKeepAliveRequests 80<br \/>\nworker and winnt MPMs:<br \/>\nKeepAlive On<br \/>\nKeepAliveTimeout 15<br \/>\nMaxKeepAliveRequests 80<\/p>\n<p>With the prefork MPM, it is recommended to set &#8216;KeepAlive&#8217; to &#8216;Off&#8217;. Otherwise, a client will tie up an entire process for that span of time. Though in my experience, it is more useful to simply set the &#8216;KeepAliveTimeout&#8217; value to something very low [2 seconds seems to be the ideal value]. This is not a problem with the worker MPM [thread-based], or under Windows [which only has the thread-based winnt MPM].<br \/>\nWith the worker and winnt MPMs, the default 15 second timeout is setup to keep the connection open for the next page request; to better handle a client going from link to link. Check logs to see how long a client remains on each page before moving on to another link. Set value appropriately [do not set higher than 60 seconds].<\/p>\n<p><strong>SymLinks<\/strong><br \/>\nMake sure &#8216;Options +FollowSymLinks -SymLinksIfOwnerMatch&#8217; is set for all directories. Otherwise, Apache will issue an extra system call per filename component to substantiate that the filename is NOT a symlink; and more system calls to match an owner.<br \/>\n<Directory \/><br \/>\nOptions FollowSymLinks<br \/>\n<\/Directory><br \/>\nAllowOverride<br \/>\nSet a default &#8216;AllowOverride None&#8217; for your filesystem. Otherwise, for a given URL to path translation, Apache will attempt to detect an .htaccess file under every directory level of the given path.<br \/>\n<Directory \/><br \/>\nAllowOverride None<br \/>\n<\/Directory><br \/>\nExtendedStatus<br \/>\nIf mod_status is included, make sure that directive &#8216;ExtendedStatus&#8217; is set to &#8216;Off&#8217;. Otherwise, Apache will issue several extra time-related system calls on every request made.<br \/>\nExtendedStatus Off<\/p>\n<p>ExtendedStatus<br \/>\nIf mod_status is included, make sure that directive &#8216;ExtendedStatus&#8217; is set to &#8216;Off&#8217;. Otherwise, Apache will issue several extra time-related system calls on every request made.<br \/>\nExtendedStatus Off<br \/>\nTimeout<br \/>\nLower the amount of time the server will wait before failing a request.<br \/>\nTimeout 45<\/p>\n<p>Other\/Specific<br \/>\nCache all PHP pages, using Squid, and\/or a PHP Accelerator and Encoder application, such as APC. Also take a look at mod_cache under Apache 2.2.<br \/>\nConvert\/pre-render all PHP pages that do not change request-to-request, to static HTML pages. Use &#8216;wget&#8217; or &#8216;HTTrack&#8217; to crawl your site and perform this task automatically.<br \/>\nPre-compress content and pre-generate headers for static pages; send-as-is using mod_asis. Can use &#8216;wget&#8217; or &#8216;HTTrack&#8217; for this task. Make sure to set zlib Compression Level to a high value (6-9). This will take a considerable amount of load off the server.<br \/>\nUse output buffering under PHP to generate output and serve requests without pauses.<br \/>\nAvoid content negotiation for faster response times.<br \/>\nMake sure log files are being rotated. Apache will not handle large (2gb+) files very well.<br \/>\nGain a significant performance improvement by using SSL session cache.<br \/>\nOutsource your images to Amazon&#8217;s Simple Storage Service (S3).<br \/>\nMeasuring Web Server Performance<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Apache Performance Tuning<\/p>\n<p>Forewarning:<\/p>\n<p> &#8220;Premature optimization is the root of all evil.&#8221; &#8212; Donald Knuth.<\/p>\n<p>Select MPM Chose the right MPM for the right job: prefork [default MPM for Apache 2.0 and 1.3]: \u2022 Apache 1.3-based. \u2022 Multiple processes, 1 thread per process, processes handle requests. \u2022 Used for security and stability. \u2022 Has [&#8230;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[],"_links":{"self":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/124"}],"collection":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=124"}],"version-history":[{"count":3,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/124\/revisions"}],"predecessor-version":[{"id":131,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/124\/revisions\/131"}],"wp:attachment":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=124"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=124"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=124"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}