diff --git a/performance.md b/performance.md index 510eb2a..42e1c97 100644 --- a/performance.md +++ b/performance.md @@ -1,162 +1,225 @@ # Performance -This section will cover the basics on configuring services for performance with WordPress. +WordPress is a stable system but depends on the performance of the operating system, web server, PHP and database to function properly. As it is a software running on the server, every time a user arrives it will run completely. -## Caching +This is why some improvements and changes are recommended to improve the performance of the whole system. -WordPress has a lot of dynamic functionality, but this comes at a cost. Tasks such as processing PHP, querying the database and collecting information from external APIs all take resources and time. +## Caching in WordPress -> Caching saves time for potentially heavy tasks by reusing previously computed results, rather than calculating them for every page view. +WordPress by default is 100% dynamic, which means that every time someone accesses it, everything has to be generated completely, which is highly calculated. Some of these elements that can slow down the process are database queries, the execution of PHP itself, calls to external APIs... -Caches typically expire after a certain amount of time and are regenerated so the most recent content is displayed. When items are served from cache they have a faster response time, often coming from memory, and take load off the server. +This is why it is recommended to cache. This process allows reusing previously calculated results on several occasions following a series of rules, which reduces the consumption of repetitive tasks. -In a typical page load, various caches might be checked in the following order: +Usually the cache is renewed after a predefined period of time, so that during the time the cache is active the results are quickly returned, as they are usually recovered from disk or memory and do not have to be calculated. -1. Local Browser cache / Local Storage / Web App Manifest -2. [Content Delivery Network (CDN)](#Content-Distribution-Network-CDN-Cache) -3. [Full Page Cache](#Full-Page-Cache) (Reverse Proxy; RAM or SSD with Nginx+) -4. [Full Page Cache](#Full-Page-Cache) (Static; PHP) -5. [Opcode Cache](#Opcode-Cache) -6. [Object Cache](#Object-Cache) (wp\_options, transient API) -7. [Fragment Cache](#Fragment-Cache) (Database, static files, transient API) -8. Transients API (Object Cache or Database Cache) -9. Database Cache -10. File Storage Cache (Static Files, SSD or spinning disk) +There are many cache layers, and each one can be handled differently. WordPress, in conjunction with system settings and plugins, is able to use them. They are usually called in this order: -Each caching instance may be a different domain, server, or compute instance, either routed by the local machine, the remote server cluster, or any intermediary computer along the request chain. +- Browser Cache, Local Cache, or Web App Manifest +- CDN (Content Delivery Network) +- Page cache, on web server or proxy +- Page caching, static or by PHP +- Opcode cache +- Cache of objects +- Cache of fragments +- Transient API +- Database cache +- File cache on disk -Each cache may have any configuration of: -Data storage: RAM, SSD, or spinning hard drives. Physical connection, or data over network. -Input/Output latency: Connection from local or remote server motherboard to RAM, Data I/O, or network I/O. +Each cache system works in a different way, it can be on the same server or on several, it can be in the same domain or in different ones, it can even be a chain of calls. In addition, each cache system may require certain settings that are not enabled by default, such as different storage, RAM, different physical connections, latency times ... this means that the optimization of the cache, in many cases, will also depend on the configuration of the machines that manage them. For example, access to RAM memory is faster than access to an SSD disk which is faster than access to an SATA disk. -For any given page load, speed and user experience will result from the combined latency of all services, and the order they are processed as users interact with a web application. +### Browser cache -(**Example**: CSS; Generated by JavaScript, PHP or pre-processor. Sent over network. Earliest display: Inline script within first HTTP packet of first HTML response. Typical: Loaded by many plugins in many files over many requests. Middle-ground: combined file, cached locally, to CDN, or server RAM or SSD.) +The web browsers we use to visit the sites allow us to store information that may be needed at various times throughout your navigation of the site. Therefore, the first visit to a website will most likely be slower, but subsequently the loading speed will increase, as some of the information is stored. -### Content Distribution Network (CDN) Cache +An example would be to add to the .htaccess file (in the case of using an Apache HTTPD web server) the following content, which forces to store the different types the indicated seconds: -Content distribution networks are designed to optimize the network latency between servers and visitors from different geographical locations. Data is distributed amongst endpoints and then visitors get served from the endpoint which is closest to them. +``` + + ExpiresActive on + # Others + ExpiresByType application/pdf A2592000 + ExpiresByType image/x-icon A2592000 + ExpiresByType image/vnd.microsoft.icon A2592000 + ExpiresByType image/svg+xml A2592000 + # Images + ExpiresByType image/jpg A2592000 + ExpiresByType image/jpeg A2592000 + ExpiresByType image/png A2592000 + ExpiresByType image/gif A2592000 + ExpiresByType image/webp A2592000 + # Media + ExpiresByType video/ogg A2592000 + ExpiresByType audio/ogg A2592000 + ExpiresByType video/mp4 A2592000 + ExpiresByType video/webm A2592000 + # CSS/JS + ExpiresByType text/css A2592000 + ExpiresByType text/javascript A2592000 + ExpiresByType application/javascript A2592000 + ExpiresByType application/x-javascript A2592000 + # Fonts + ExpiresByType application/x-font-ttf A2592000 + ExpiresByType application/x-font-woff A2592000 + ExpiresByType application/font-woff A2592000 + ExpiresByType application/font-woff2 A2592000 + ExpiresByType application/vnd.ms-fontobject A2592000 + ExpiresByType font/ttf A2592000 + ExpiresByType font/woff A2592000 + ExpiresByType font/woff2 A2592000 + +``` -In addition to optimizing networking latency, CDNs can act as another layer of static and/or full-page caching running on all those endpoints. +### CDN – Content Distribution Network -It’s important to make sure that CDNs are working well with all your other caching systems and that it purges caches on all endpoints when you request that from your main server. Otherwise, people in certain areas may get old results which is generally an issue that’s difficult to troubleshoot. +The content distribution networks are designed to reduce latency, response times, when serving content in different geographical areas. If your WordPress project is international, it is certainly a good option for, at least, static content such as JavaScript or CSS as well as images and media content. If your project is quite local, it's best to have a connected infrastructure in that country. -### Full Page Cache +Also, generally, CDNs are also used as a caching layer, since by having the contents and only serving the static ones, they don't have to make calculations and are optimized to serve themselves as quickly as possible. If you work with several cache layers, you have to make sure that it is purged at all levels, because you can clean up at one level, but not at another, and still serve something that has not been invalidated. -In order to display your content, WordPress does a lot of work under the hood, and all those calculations require server resources and time to complete. For starters, the PHP service on the server has to process the request, load WordPress core, your theme PHP files and all PHP scripts coming from your plugins. The majority of those PHP files make requests to your database, too, which adds to the overall resource footprint of your site. +### Page Cache -The best way to cache these requests is to use a reverse proxy like NGINX or Varnish which stores the output directly into the server memory. That saves a lot of processing power because cached content is served straight out of the reverse proxy without hitting your web server, the PHP service, or your database service at all. If a reverse proxy is not available on your current server setup, you can fallback to storing cached content into your file system. It's slower than reverse proxies and a hit reaches your web server and your PHP service at least once, so it can direct the request to the proper cached file but still - it's much faster than doing all the computing for every request. +When a request is made for a page, for example the main page of a blog, several processes are executed in PHP, the calculation for the retrieval of the contents in the database is made, personalized configurations are calculated and finally the page is painted on the screen. In many occasions, the contents between a request and another one has not changed so why not showing the information calculated in the first of those two occasions? -Full Page Caching stores the HTML output of a request, but all the CSS, JS, images and font files will have to be loaded separately too. They are handled separately and optimizing them is worth investing the time and effort. Static caching can have great effect on those resources. You can often use the same reverse proxy to static resources in the server memory - CSS, JS, Fonts, Images and serve them directly. +The best way to cache data is usually to put a system between the user and the web server. That way the information is requested, served, and then the changes are verified or left the same until the information is invalidated. This intermediate layer can be a proxy, usually managed by tools such as [nginx (reverse proxy)](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) or [Varnish Cache](https://varnish-cache.org/) that store a copy of the request and serve it until the system is invalidated manually or automatically when it reaches the expiration time. These systems usually store a copy in memory, so it is served much faster than any other system. -It's important to have the ability to expire caches when necessary to avoid serving visitors old data. When available, selective caching is preferred over purging the entire cache, to avoid the cost of WordPress regenerating every page for the site. Furthermore, it's good practice to exclude certain types of pages from your full page caching completely because they are different for each user. For example, if you have an online store, it's imperative that your cart, checkout and profile pages are completely dynamic. In general, it’s a good idea to exclude all logged in users from the cache because they are supposed to see personalized content. Another important aspect is the default caching period, which can be different for each website depending on how often data is changed. +If you don't have such a system, you can always make that copy on the web server itself; it's not the fastest option but it's always better than having to calculate everything. Most caching plugins for WordPress use this system. -![](https://make.wordpress.org/hosting/files/2018/08/full-page-caching-response-example.png) +In the case of images, scripts, style sheets and similar, it is best to serve them directly if they exist and not to go through processing systems such as PHP. -### Object Cache +If you use any of these systems, remember that it is always useful to have a system that invalidates the information, for example, when new information is published on the site. The best thing is that you can use a system that only removes those pages that are affected and not the whole site. + +Remember also that there will be pages that should never be cached, as they are different for each user, such as the shopping cart page of an e-commerce, or the payment process and beyond. + +Another element to keep in mind when configuring caches is the usual time in which the information will be saved until it is invalidated. For example, a corporate website could cache the information for 1 week, a blog in which it is published infrequently, once a day would be enough but, on the other hand, an e-commerce website could cache it for only 1 hour. -> In 2005, WordPress introduced its internal object cache — a way of automatically storing any data from the database (not just objects) in PHP memory to prevent unnecessary queries. However, out of the box, WordPress will discard all of those objects at the end of the request, requiring them to be rebuilt from scratch for the next page load. +Some interesting plugins to manage the cache could be: [WP Super Cache](https://wordpress.org/plugins/wp-super-cache/), [WP Fastest Cache](https://wordpress.org/plugins/wp-fastest-cache/), [W3 Total Cache](https://wordpress.org/plugins/w3-total-cache/), [Simple Cache](https://wordpress.org/plugins/simple-cache/). -###### source: [scalewp.io](https://www.scalewp.io/object-caching/) -What does this mean? Think of a standard WordPress homepage displaying the most recent posts. Each of these posts has quite a bit of information associated with it WordPress must look up such as the author, categories, tags, and excerpt. +In case you work with systems like nginx or LiteSpeed you have these: [LiteSpeed Cache](https://wordpress.org/plugins/litespeed-cache/), [Nginx Cache](https://wordpress.org/plugins/nginx-cache/). -Support for a persistent object cache gives WordPress, plugins, and themes, a place to store that data for reuse. While these items are cached, PHP execution time is improved while lessening the load on the database. It's particularly helpful in situations where much of the page is difficult to cache from the front-end, like for authenticated traffic or e-commerce applications. +### Opcode cache -For these reasons, persistent object caching support is commonly offered with managed WordPress hosting. +Every time a request comes to your web server, PHP has to execute and calculate everything, but PHP allows an internal operation caching system, which means that a copy of each execution is stored in memory or on disk. If it is active and the same operation is executed again, the system will take advantage of this system to return the calculation much faster, since it does not have to calculate everything completely. -![](https://make.wordpress.org/hosting/files/2018/08/wordpress-object-caching-example.png) +If your hosting provider has it active and configured, you can make use of it, but always taking into account that you may need a plugin to make the invalidation of the contents when necessary, considering `opcache.validate_timestamps` may or may not be configured. -> Transients are inherently sped up by caching plugins, where normal Options are not. A memcached plugin, for example, would make WordPress store transient values in fast memory instead of in the database. For this reason, transients should be used to store any data that is expected to expire, or which can expire at any time. Transients should also never be assumed to be in the database, since they may not be stored there at all. +Some plugins that can be useful: [OPcache Reset](https://wordpress.org/plugins/opcache-reset/), [WP OPcache](https://wordpress.org/plugins/flush-opcache/), [OPCache Scripts](https://wordpress.org/plugins/opcache-scripts/). -###### source: [WordPress Codex](https://codex.wordpress.org/Transients_API) +### Object Cache + +It has been possible for many versions of WordPress to store some items in the so-called object cache. These objects are mainly pre-calculated items associated with search queries. -### Opcode Cache +Thanks to this system and with the help of external storage servers such as [memcached](https://memcached.org/) or [Redis](https://redis.io/) we can store the calculated data in systems designed for a very fast reading without having to store them in the database. In this way, the system will not have to execute the calculations again but they will be read directly from a storage. -The web server must read, compile, and run each PHP script. An opcode cache stores a compiled copy of each PHP script in memory or on disk. When the web server starts processing PHP scripts for WordPress, the web server checks the opcode cache for a cached copy of the PHP script. If there is a cached copy, the web server can skip straight to running the PHP script using the cached copy instead of having to read and compile the script again. Skipping this reading and compiling PHP scripts can greatly improve the web server's resource usage and enable WordPress to serve many more requests than it might have been able to otherwise. It's particularly helpul for dynamic content and authenticated traffic, where full page caching isn't as effective. +The interesting thing about this system is that it does not cache the whole calculated page, but only parts of it, which means that in pages that cannot be completely cached, certain parts that do not have to change do so. -As with any cache, opcode caches can keep changes from taking effect until the cache expires or is purged. With opcode cache specifically, this means older versions of the compiled PHP code will be loaded. When updating plugins, themes, or WordPress core, the appropriate files should be purged from the cache to avoid continuing to load the older versions. +Some plugins that can be useful: [Redis Object Cache](https://wordpress.org/plugins/redis-cache/), [WP Redis](https://wordpress.org/plugins/wp-redis/), [WP Memcached Manager](https://wordpress.org/plugins/wp-memcached-manager/). ### Fragment Cache -This caching method allows saving sections of otherwise non-cacheable dynamic website content. It can help especially for sites where the majority of the page is static, but has certain dynamic elements, like a shopping cart, or for membership sites. +This type of cache allows you to have cache by parts within the whole of the same page. The best known system is the [ESI (Edge Side Includes)](https://en.wikipedia.org/wiki/Edge_Side_Includes) and, with external systems that support it, would allow to have several cached parts and merge them before offering them to the final client. + +With this system, for example, a page of a store could be cached by parts, being able to have a common part and other separate parts, such as the cart that would vary according to each user and would only change if something is added to it. -In the WordPress context, developers often store parts of the page using the WordPress transients/object cache API. In these cases, providing a persistent object cache will allow that caching to happen outside of the database. +WordPress does not have this system by default, although it can be partially managed with systems like [LiteSpeed Cache](https://wordpress.org/plugins/litespeed-cache/) or [Varnish Cache](https://varnish-cache.org/). -Storing these fragments separately in a front end cache is not natively supported by WordPress, and means both manually configuring the sections of the page to be cached, and configuring your front-end cache, whether it be Nginx, Varnish, or otherwise, to support fragment caching. This is usually an advanced technique, and reserved for sites or hosting platforms with very high dynamic traffic needs. +## PHP in WordPress -## Purging / Busting / Clearing Caches +Without a doubt, the performance of PHP is basic for the proper functioning of WordPress, since most of the system depends on it. That's why the optimal configuration of PHP in your hosting is essential. PHP is an interpreted language that runs on the server, so the weight of optimization is there. -Purging caches is as important as storing them. You have to make sure that all layers of caching are cleared when necessary. +### PHP Version -Fragment caching is the temporary storage of expensive or long-running server-side operations to avoid taxing web servers and delayed delivery to visitors. It's become a common practice for operations such as generating Menu markup, Widget markup and slow MySQL or HTTP responses. Core currently uses transients to cache HTTP calls to WordPress.org APIs for updates and events. +No doubt for the good functioning of WordPress we should use PHP 7.x, currently recommended PHP 7.4.x, PHP 7.3.x or PHP 7.2.x. It's known that versions prior to PHP 7.x (i.e. PHP 5.6 and earlier) have a 30% lower performance than the current versions. In addition, a major change was made in PHP 7.1 regarding encryption, so it's recommended to use at least that version. -Fragment caching is particularly beneficial when appropriately paired with full-page caching. Perhaps there's uniform `