PHP performance analysis Article 3: performance tuning practices
Note: This is the third article in our PHP performance analysis series. Click here to read PHP performance analysis article 1: XHProf & XHGui introduction, or PHP performance analysis article 2: in-depth study of XHGui.
In the first part of this series, we introduced XHProf. In the second article, we have thoroughly studied the XHGui UI. now, let's use the XHProf/XHGui knowledge in our work!
Performance Tuning
Code that does not need to be run is the perfect code. Others are just good code. Therefore, the best choice for performance tuning is to ensure that as few code as possible is run first.
OpCode cache
First, the fastest and simplest option is to enable OpCode caching. More information about OpCode cache can be found here.
In, we can see the situation after Zend OpCache is enabled. The last line is our benchmark, that is, the cache is not enabled.
In the middle line, we can see a small performance improvement and a significant reduction in memory usage. Small Performance Improvement (probably) comes from Zend OpCache optimization, rather than OpCode cache.
The first line is the results after Optimization and OpCode cache. we can see a great improvement in performance.
Now let's look at the changes before and after APC. As shown in, compared with Zend OpCache, with the establishment of the cache, we can see that the performance of the initial (intermediate line) request is degraded, and the performance in terms of consumption duration and memory usage is significantly reduced.
Then, with the establishment of opcode cache, we can see similar performance improvements.
Content cache
The second thing we can do is cache the content ?? This is a piece of cake for WordPress. It provides many easy-to-install plug-ins to implement content caching, including WP Super Cache. WP Super Cache creates a static version of the website. This version automatically expires based on website settings when a comment event occurs. (For example, in very high loads, you may want to disable cache expiration for any reason ).
The content cache can only run effectively when there are almost no write operations. write operations will invalidate the cache, but read operations will not.
You should also cache the content received by the application from a third-party API to reduce the latency and dependency caused by API availability.
WordPress has two Cache plug-ins, which can greatly improve website performance: W3 Total Cache and WP Super Cache.
Both plug-ins will create static HTML copies of the website, instead of generating pages every time a request is received, thus compressing the response time.
If you are developing your own applications, most frameworks have cache modules:
Zend Framework 2: Zend \ Cache
Symfony 2: Multiple options
Laravel 4: Laravel Cache
ThinkPHP 3.2.3: ThinkPHP Cache
Query cache
Another caching option is query cache. For MySQL, a general query cache is of great help. For other databases, the query result set is cached in memory such as Memcached or cassandra, which is also very effective.
Like the content cache, the query cache is most effective in scenarios that contain a large number of read operations. A small amount of data changes will invalidate a large block of cache, especially the MySQL Query cache cannot be used to improve performance.
The query cache may improve the performance when generating the content cache.
As shown in, when we enable the query cache, the actual running time is reduced by 40%, although the memory usage has not changed significantly.
There are three types of cache options:Query_cache_typeControl settings.
Set the value0OrOFFCache disabled
Set the value1OrONBesidesSELECT SQL _NO_CACHEAll options except the beginning
Set the value2OrDEMANDOnlySELECT SQL _CACHEStart
In addition, you shouldQuery_cache_sizeSet to a non-zero value. Setting it to zero will disable caching, regardlessQuery_cache_typeWhether to set.
For more information about cache settings, see the mysql-tuning-primer script.
The main problem with MySQL Query cache is that it is global. Any changes to the table composed of the cache result set will result in invalid cache. In applications with frequent write operations, this will make the cache almost ineffective.
However, you have many other options to create more intelligent caches based on your needs and datasets, such as Memcached, riak, cassandra, or redis.
Query optimization
As mentioned above, database queries are often the cause of slow program execution, and query optimization can bring more immediate benefits than code optimization.
Query Optimization helps to improve the performance when generating content caching, and it is also beneficial if the content cannot be cached in the worst case.
In addition to analysis, MySQL also has an option to help identify slow queries ?? Slow query logs. Slow query logs record all queries that take longer than the specified time and do not use indexes (the latter is optional ).
You canMy. cnfUse the following configuration to enable logging.
[mysqld]log_slow_queries =/var/log/mysql/mysql-slow.log long_query_time =1log-queries-not-using-indexes
If any query is slowerLong_query_time(In seconds), the query records the log file.Log_slow_queries. The default value is 10 seconds, and the minimum value is 1 second.
In addition,Log-queries-not-using-indexesYou can capture any queries that do not use indexes to logs.
Then we can bind it with MySQL.MysqldumpslowCommand to check logs.
Use these options during WordPress installation. after the homepage is loaded and running, the following data is obtained:
$ mysqldumpslow -g "wp_" /var/log/mysql/mysql-slow.logReading mysql slow query log from /var/log/mysql/mysql-slow.logCount: 1 Time=0.00s (0s) Lock=0.00s (0s) Rows=358.0(358), user[user]@[host] SELECT option\_name, option\_value FROM wp_options WHERE autoload ='S'Count: 1 Time=0.00s (0s) Lock=0.00s (0s) Rows=41.0(41), user[user]@[host] SELECT user\_id, meta_key, meta_value FROM wp_usermeta WHERE user_id IN (N)
First, note that all string values areSIn the formatN. You can add-To display these values.
Next, note that both queries consume 0.00 s, which means that they consume less than 1 second of threshold and no index is used.
You can check the causes of performance degradation by using EXPLAIN in the MySQL console:
mysql> EXPLAIN SELECT option_name, option_value FROM wp_options WHERE autoload = 'S'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: wp_options type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 433 Extra: Using where
Here, we can seePossible_keysIs NULL to confirm that no index is used.
EXPLAINIs a powerful tool for optimizing MySQL queries. For more information, see here.
PostgreSQL also includes an EXPLAIN statement (which differs greatly from MySQL), while MongoDB has a $ EXPLAIN element operator.
Code Optimization
Generally, you can adjust the code only when you cache as much content as possible without being limited by PHP (by using OpCode cache) and optimize the query.
Code and query optimization can improve the performance to create other caches. the higher the performance of code in the worst environment (no cache), the more stable the application, the faster the cache is rebuilt.
Let's see how (potentially) we can optimize our WordPress installation.
First, let's look at the slowest function:
To my surprise, the first item in the listNoMySQL (in factMysql_query ()Is fourth),Apply_filter ()Function.
The WordPress code library features that the event-based filtering system performs a variety of data conversions, and the execution order is in the order that the data is added by the kernel, plug-in, or callback.
Apply_filter ()Functions are the place where these callback applications are located.
First, you may notice that the function is called 4194 times. If you click to view more details, you can sort the "parent function" in descending order according to the "number of calls" to findTranslate ()The _ apply_filter () _ function is called 778 times.
This is interesting because I don't actually use any translation. I (and suspect most users) set the language to English when using WordPress software.
Therefore, let's Click to view details to further viewTranslate ()What is the function doing.
Here we can see two interesting things. First, one of the parent functions is called 773 times :__().
After checking the source code of the function, we find that it isTranslate ()Package.
According to empirical rules, function calls are expensive and should be avoided as much as possible. Now we always call _ () insteadTranslate (), We should change the aliasTranslate ()To maintain backward compatibility, while _ () does not call unnecessary functions.
However, in fact, this change will not bring about much difference, but only micro-optimization ?? But it does improve the code readability and simplify the call diagram.
Continue, let's look at the sub-function:
Now, go deep into this function and we can see that three functions or methods are called every 778 times:
Sort by actual inclusive running time in descending order. we can see thatApply_filter ()Is the most time-consuming call so far.
View the code:
translate( $text ), $text, $domain ); } ?>
The purpose of this code is to retrieve a translation object and then pass the result of $ translations-> translate ()Apply_filter (). We found that $ translations isNOOP_TranslationsClass.
Based only on the name (_ NOOP _), and confirmed by the comments in the code, we found that the translator actually does not have any action!
Therefore, we can avoid such code!
By performing small-scale debugging on the code, we can see that the default domain is currently used. we can modify the code to ignore the translator:
translate( $text ), $text, $domain ); } ?>
Next, we will analyze it again to make sure you want to runAt least twice?? Make sure that all the caches are created. this is a fair comparison!
This operation is indeed faster! But how fast? Why?
You can find the answer by comparing and running XHGui. Return to our initial run, click "compare here to run" in the upper-right corner, and select a new run from the list.
We found that the number of function calls was reduced by 3%, the actual inclusive running time was reduced by 9%, and the inclusive CPU time was reduced by 12%!
The details page can be sorted in descending order of the number of calls, which confirms (as we expected)Get_translations_for_domain ()AndNOOP_Translations: translate ()The number of function calls is reduced. Likewise, unexpected changes can be identified.
30 minutes of work brings about 9-12% performance improvement, which is very gratifying. This means the real-world performance gains, even after applying opcache.
Now we can repeat this process for its functions until more optimization points are not found.
Note:This change has been submitted to WordPress.org and updated. You can track and discuss WordPress Bug Tracker and view the practice process. This update plan is included in WordPress 4.1.
Other tools
In addition to excellent XHProf/XHGui, there are also some good tools.
New Relic & OneAPM
Both New Relic and OneAPM provide frontend and backend performance analysis and insight into background stack information, including SQL query and code analysis, front-end DOM and CSS presentation, and Javascript statements. _ OneAPM _ more functions (OneAPM online DEMO)
Uprofiler
Uprofiler is a Facebook XHProf branch that is not released yet. it is planned to delete the CIA required by Facebook. Currently, the two have the same features, and only some of them are renamed.
XHProf. io
XHProf. io is another user interface of XHProf. XHProf. io uses MySQL for configuration file storage, which is less user-friendly than XHGui.
Xdebug
Before XHProf appeared, Xdebug already exists ?? Xdebug is an active performance analyzer, which means it should not be used in the production environment, but can gain a deep understanding of the code.
However, it must be used with another tool to read analyzer output, such as KCachegrind ). However, it is difficult to install KCachegrind on a non-linux machine. Another choice is Webgrind.
Webgrind cannot provide those features of KCachegrind, but it is a PHP Web application that is easy to install in any environment.
With KCachegrind, you can easily explore and discover performance problems. (In fact, this is my favorite profiling tool !)
Conclusion
Analysis and performance tuning are very complex projects. With the right tools and understanding how to make good use of these tools, we can greatly improve the code quality ?? Even the code library we are not familiar.
It is definitely worth the time to explore and learn these tools.
Note: This is the third article in our PHP performance analysis series. Read the first article in PHP performance analysis: XHProf & XHGui introduction, and the second article in PHP performance analysis: in-depth study of XHGui. (This article is compiled by OneAPM engineers, a leader in application performance management.)