Time To First Byte have number of components :
- DNS Lookup: Find the IP address of the domain (possible improvement: more numerous/distributed/responsive DNS servers)
- Connection time: Open a socket to the server, negotiate the connection (typical value should be around ‘ping’ time – a round trip is usually necessary – keepalive should help for subsequent requests)
- Waiting: initial processing required before first byte can be sent (his is where your improvement should be – it will be most significant for dynamic content.
We can test TTFB with ApacheBenchmark and we can see in output processing time which is sum of waiting plus complete transfer of content - if the transfer time is significantly longer than what would be expected to download the quantity of data received. further processing, after TTFB, is occuring (eg. the page is flushing content as it is available).
With few exceptions, the problem lies in the backend processing, which usually comes down to overly complex/inefficient code, or poorly configured SQL server.
A good way to approach this problem is through a series of comparisons that will eliminate various aspects of server setup. A good comparison should keep as much constant as possible to help narrow down the problem.
Let see simple and stupid comparisons
- Identical site running on old server and new server
- Difference : server
- Result : old server is fast, new server is slow
- Notes : what is needed here to quantify the differences between these servers – both in terms of the stack used (Apache, Nginx, Lighthttpd, ..) and the hardware (is the old server faster because it is more powerful machine?)
- Conclusion : the code may be able to run fast on right setup
- Test site vs full site on new server
- Difference : content. themes, plugins, ..
- Result : test site is fast, full site is slow
- Notes : in theory, this test should help eliminate a lot of aspects of server setup - DNS, network, even stack setup.
- Conclusion : the extra content is having a significant impact on performance
The ideal test would have duplicate (exact match) web site, but deleted all content except for one article and associated comments. The point of this test would be to conclusively determine if the large amount of content is the problem or if other aspects of server setup (wordpress plugins, theme, etc) are the cause. Everyone would essentially compare the performance of identical sites, on the same server – loading the same page – with the only difference being the total site content (e.g. there is a good chance that some plugin does not scale well with increased content).
Without changing anything, there are some other comparisons we can do:
- Test from a remote location vs. local – this will help identify if network, latency, dns, .. is the cause
- We have already done this and mostly concluded that we don’t have a network problem.
- Test via Varnish vs nginx directly – we will try not to change configuration between tests – we will just use the correct port. This will show us the impact of Varnish. Since Varnish is a caching layer, it should serve all requests after the first one very quickly – essentially, it should bypass the backend and the processing that is needed to generate a dynamic page, and serve the cached copy very quickly.
- We have done this and demonstrated that Varnish has a significant positive impact on our performance.
By this point we should have either found the problem or concluded that it lies in our backend. That leaves us with Nginx, PHP, or MySQL.
Nginx is just taking requests and either serving static content or shifting the requests to PHP-FPM – there usually isn’t much to optimize with Nginx.
- Set workers = number of threads
- Enable keepalive
- Disable unneeded logging
- Increase buffer sizes if needed
- Avoid if statements
Ideally, our test blog and cloned blog have identical configs, in which case, we have effectively eliminated Nginx as the problem.
In the case where we are trying to identify a problem in our code (for instance a slow plugin, ..) the slow logs are the place to start.
- We will enable the MySQL slow log and the PHP-FPM slow log, we will run benchmark and see what is coming up as slow.
- We will increase our caches and run mysqltuner.pl to get a good starting point.
- we can disable unneeded extensions,
- also we can disable register_globals, magic_quotes_*, expose_php, register_argc_argv, always_populate_raw_post_data
- increase the memory_limit
- open_basedir and safe_mode have significant performance implications, but also can provide an additional layer of defense. We can test with and without them, to determine if their impact on performance is tolerable.
- Adjusting the pm.* values – increase them to deal with high load
It is worth noting that our htop results show php-fpm as consuming the bulk of the CPU – and our problem does appear to be directly related to this.
Once we have optimized each likely bottleneck, we can start caching.
- We have an opCode cache (APC, XCache, ..) already, if not we can install it – we need to ensure that it is working – check your cache hit rates, and also if possible we will configure APC to write in memory instead on disks.
- We can setup our code to use static cache if possible (eg. W3 Total Cache)
- With nginx we can setup FastCGI caching – but since we have Varnish, this is best avoided.
- Add more caching for components of our site – e.g. Memcached if applicable
Sometimes, given the limitations of our application and hardware, we may not be able to improve backend performance that much – however, that is the point of caching – to minimize the use of the backend.
Source : serverfault.com