Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions guide/en/tutorial/performance-tuning.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Performance tuning

There are many factors affecting the performance of your application. Some are environmental, some are related

Check notice on line 3 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L3

[Microsoft.Passive] 'are related' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'are related' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 3, "column": 100}}}, "severity": "INFO"}
to your code, while some others are related to Yii itself. In this section, we will count most of these

Check notice on line 4 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L4

[Microsoft.Passive] 'are related' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'are related' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 4, "column": 33}}}, "severity": "INFO"}

Check warning on line 4 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L4

[Microsoft.We] Try to avoid using first-person plural like 'we'.
Raw output
{"message": "[Microsoft.We] Try to avoid using first-person plural like 'we'.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 4, "column": 77}}}, "severity": "WARNING"}
factors and explain how you can improve your application performance by adjusting these factors.


## Optimizing your PHP Environment <span id="optimizing-php"></span>

Check notice on line 8 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L8

[Microsoft.Headings] 'Optimizing your PHP Environment' should use sentence-style capitalization.
Raw output
{"message": "[Microsoft.Headings] 'Optimizing your PHP Environment' should use sentence-style capitalization.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 8, "column": 4}}}, "severity": "INFO"}

Check warning on line 8 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L8

[Microsoft.HeadingAcronyms] Avoid using acronyms in a title or heading.
Raw output
{"message": "[Microsoft.HeadingAcronyms] Avoid using acronyms in a title or heading.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 8, "column": 20}}}, "severity": "WARNING"}

A well-configured PHP environment is important. To get maximum performance:

Expand All @@ -16,23 +16,43 @@
- Make sure [XDebug](https://xdebug.org/) isn't installed in the production environment.
- Try [PHP 7 preloading](https://wiki.php.net/rfc/preload).

## Optimizing your code <span id="optimizing-code"></span>

Beyond environment configuration, there are code-level optimizations that can improve your application's performance:

- Look out for [algorithm complexity](https://en.wikipedia.org/wiki/Time_complexity).
Especially give attention to `foreach` within `foreach` loops but look out for using
[heavy PHP functions](https://stackoverflow.com/questions/2473989/list-of-big-o-for-php-functions) in loops as well.
- [Speeding up array_merge()](https://www.exakat.io/speeding-up-array_merge/)
- [Move that foreach() inside the method](https://www.exakat.io/move-that-foreach-inside-the-method/)
- [Array, classes and anonymous classes memory usage](https://www.exakat.io/array-classes-and-anonymous-memory-usage/)
- Use fully qualified function names with leading backslashes to optimize opcache performance.
When calling [certain global functions](https://github.com/php/php-src/blob/944b6b6bbd6f05ad905f5f4ad07445792bee4027/Zend/zend_compile.c#L4291-L4353)
from within a namespace, PHP first searches in the current namespace before falling back to the global namespace.
Adding a leading backslash (e.g., `\count()` instead of `count()`) tells PHP to directly use the global function,

Check failure on line 32 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L32

[Microsoft.Foreign] Use 'for example' instead of 'e.g.,'.
Raw output
{"message": "[Microsoft.Foreign] Use 'for example' instead of 'e.g.,'.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 32, "column": 31}}}, "severity": "ERROR"}
avoiding the namespace lookup and improving opcache efficiency. This optimization is best implemented automatically
using tools like [PHP-CS-Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) with the `native_function_invocation` rule.

The above optimizations would give you a significant performance boost only if the code in question is executed

Check notice on line 36 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L36

[Microsoft.Vocab] Verify your use of 'above' with the A-Z word list.
Raw output
{"message": "[Microsoft.Vocab] Verify your use of 'above' with the A-Z word list.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 36, "column": 5}}}, "severity": "INFO"}

Check notice on line 36 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L36

[Microsoft.Passive] 'is executed' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'is executed' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 36, "column": 101}}}, "severity": "INFO"}
frequently. That is usually the case for big loops or batch processing.

Check failure on line 37 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L37

[Microsoft.Contractions] Use 'that's' instead of 'That is'.
Raw output
{"message": "[Microsoft.Contractions] Use 'that's' instead of 'That is'.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 37, "column": 13}}}, "severity": "ERROR"}

## Using caching techniques <span id="using-caching-techniques"></span>

You can use various caching techniques to significantly improve the performance of your application. For example,

Check notice on line 41 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L41

[Microsoft.SentenceLength] Try to keep sentences short (< 30 words).
Raw output
{"message": "[Microsoft.SentenceLength] Try to keep sentences short (\u003c 30 words).", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 41, "column": 102}}}, "severity": "INFO"}
if your application allows users to enter text in Markdown format, you may consider caching the parsed Markdown

Check notice on line 42 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L42

[Microsoft.Vocab] Verify your use of 'allows' with the A-Z word list.
Raw output
{"message": "[Microsoft.Vocab] Verify your use of 'allows' with the A-Z word list.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 42, "column": 21}}}, "severity": "INFO"}
content to avoid parsing the same Markdown text repeatedly in every request. Please refer to

Check warning on line 43 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L43

[Microsoft.Adverbs] Remove 'repeatedly' if it's not important to the meaning of the statement.
Raw output
{"message": "[Microsoft.Adverbs] Remove 'repeatedly' if it's not important to the meaning of the statement.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 43, "column": 49}}}, "severity": "WARNING"}
the [Caching](../caching/overview.md) section to learn about the caching support provided by Yii.


## Optimizing session storage <span id="optimizing-session-storage"></span>

By default, session data is stored in files. The implementation is locking a file from opening a session to the point it's

Check notice on line 49 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L49

[Microsoft.Passive] 'is stored' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'is stored' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 49, "column": 26}}}, "severity": "INFO"}
closed either by `$session->close()` or at the end of request.
While the session file is locked, all other requests that are trying to use the same session are blocked. That's waiting for the

Check notice on line 51 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L51

[Microsoft.Passive] 'is locked' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'is locked' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 51, "column": 24}}}, "severity": "INFO"}

Check notice on line 51 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L51

[Microsoft.Passive] 'are blocked' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'are blocked' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 51, "column": 94}}}, "severity": "INFO"}
initial request to release a session file. This is fine for development and probably small projects. But when it comes
to handling massive concurrent requests, it's better to use more sophisticated storage, such as Redis.

It could be done either by [configuring PHP via php.ini](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-redis-server-as-a-session-handler-for-php-on-ubuntu-14-04)

Check notice on line 55 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L55

[Microsoft.Passive] 'be done' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'be done' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 55, "column": 10}}}, "severity": "INFO"}
or [implementing SessionHandlerInterface](https://www.sitepoint.com/saving-php-sessions-in-redis/) and configuring
session service as follows:

Expand All @@ -51,7 +71,7 @@
fetching the latest data could be prohibitively expensive without a proper database and query design.

A general technique to improve the performance of DB queries is to create indices for table columns that
need to be filtered by. For example, if you need to look for a user record by `username`, you should create an index

Check notice on line 74 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L74

[Microsoft.Passive] 'be filtered' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'be filtered' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 74, "column": 9}}}, "severity": "INFO"}
on `username`. Note that while indexing can make SELECT queries much faster, it will slow down INSERT, UPDATE and DELETE queries.

For complex DB queries, it's recommended that you create database views to save the query parsing and preparation time.
Expand All @@ -62,7 +82,7 @@

## Optimizing composer autoloader <span id="optimizing-autoloader"></span>

Because Composer autoloader is used to include most third-party class files, you should consider optimizing it

Check notice on line 85 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L85

[Microsoft.Passive] 'is used' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'is used' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 85, "column": 29}}}, "severity": "INFO"}
by executing the following command:

```
Expand All @@ -85,22 +105,22 @@
In the pull method, whenever a request involves some complex operation, you create a task and save it in a persistent
storage, such as a database. You then use a separate process (such as a cron job) to pull the tasks and process them.
This method is straightforward to implement, but it has some drawbacks. For example, the task process needs to periodically pull
from the task storage. If the pull frequency is too low, the tasks may be processed with great delay, but if the frequency

Check notice on line 108 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L108

[Microsoft.Passive] 'be processed' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'be processed' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 108, "column": 72}}}, "severity": "INFO"}
is too high, it will introduce high overhead.

In the push method, you would use a message queue (e.g., RabbitMQ, ActiveMQ, Amazon SQS, etc.) to manage the tasks.

Check failure on line 111 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L111

[Microsoft.Foreign] Use 'for example' instead of 'e.g.,'.
Raw output
{"message": "[Microsoft.Foreign] Use 'for example' instead of 'e.g.,'.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 111, "column": 52}}}, "severity": "ERROR"}

Check notice on line 111 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L111

[Microsoft.Acronyms] 'SQS' has no definition.
Raw output
{"message": "[Microsoft.Acronyms] 'SQS' has no definition.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 111, "column": 85}}}, "severity": "INFO"}
Whenever a new task is put in the queue, it will initiate or notify the task handling process to trigger the task processing.

Check notice on line 112 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L112

[Microsoft.Passive] 'is put' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'is put' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 112, "column": 21}}}, "severity": "INFO"}

## Using preloading

As of PHP 7.4.0, PHP can be configured to preload scripts into the opcache when the engine starts.

Check notice on line 116 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L116

[Microsoft.Passive] 'be configured' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'be configured' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 116, "column": 26}}}, "severity": "INFO"}
You can read more in the [documentation](https://www.php.net/manual/en/opcache.preloading.php)
and the corresponding [RFC](https://wiki.php.net/rfc/preload).

Check notice on line 118 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L118

[Microsoft.Acronyms] 'RFC' has no definition.
Raw output
{"message": "[Microsoft.Acronyms] 'RFC' has no definition.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 118, "column": 24}}}, "severity": "INFO"}

Note that the optimal tradeoff between performance and memory may vary with the application. "Preload everything"
may be the easiest strategy, but not necessarily the best strategy.

For example, we conducted a simple [yiisoft/app](https://github.com/yiisoft/app) application template benchmark.

Check warning on line 123 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L123

[Microsoft.We] Try to avoid using first-person plural like 'we'.
Raw output
{"message": "[Microsoft.We] Try to avoid using first-person plural like 'we'.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 123, "column": 14}}}, "severity": "WARNING"}
Without preloading and with preloading of the entire composer class map.

### Preloading benchmarks
Expand All @@ -108,20 +128,20 @@
The application template benchmark includes configuring classes to injected dependencies in the bootstrap script.

For both variants, [ApacheBench](https://httpd.apache.org/docs/2.4/programs/ab.html)
was used with the following run parameters:

Check notice on line 131 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L131

[Microsoft.Passive] 'was used' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'was used' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 131, "column": 1}}}, "severity": "INFO"}

```shell
ab -n 1000 -c 10 -t 10
```

Also, the debug mode was disabled. And an optimized autoloader of the [Composer](https://getcomposer.org) was used

Check notice on line 137 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L137

[Microsoft.Passive] 'was disabled' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'was disabled' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 137, "column": 22}}}, "severity": "INFO"}

Check notice on line 137 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L137

[Microsoft.Accessibility] Don't use language (such as 'disabled') that defines people by their disability.
Raw output
{"message": "[Microsoft.Accessibility] Don't use language (such as 'disabled') that defines people by their disability.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 137, "column": 26}}}, "severity": "INFO"}

Check notice on line 137 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L137

[Microsoft.Passive] 'was used' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'was used' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 137, "column": 107}}}, "severity": "INFO"}
and development dependencies weren't used:

```shell
composer install --optimize-autoloader --no-dev
```

With preloading enabled, the entire composer class map (825 files) was used:

Check notice on line 144 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L144

[Microsoft.Passive] 'was used' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'was used' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 144, "column": 68}}}, "severity": "INFO"}

```php
$files = require 'vendor/composer/autoload_classmap.php';
Expand All @@ -135,12 +155,12 @@

| Benchmark | Preloaded files | Opcache memory used | Per request memory used | Time per request | Requests per second |
|--------------------|-----------------|---------------------|-------------------------|------------------|---------------------|
| Without preloading | 0 | 12.32 mb | 1.71 mb | 27.63 ms | 36.55 rq/s |

Check warning on line 158 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L158

[Microsoft.Terms] Prefer 'MB' over 'mb'.
Raw output
{"message": "[Microsoft.Terms] Prefer 'MB' over 'mb'.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 158, "column": 48}}}, "severity": "WARNING"}

Check warning on line 158 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L158

[Microsoft.Terms] Prefer 'MB' over 'mb'.
Raw output
{"message": "[Microsoft.Terms] Prefer 'MB' over 'mb'.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 158, "column": 69}}}, "severity": "WARNING"}
| With preloading | 825 | 17.86 mb | 1.82 mb | 26.21 ms | 38.42 rq/s |

Check warning on line 159 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L159

[Microsoft.Terms] Prefer 'MB' over 'mb'.
Raw output
{"message": "[Microsoft.Terms] Prefer 'MB' over 'mb'.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 159, "column": 48}}}, "severity": "WARNING"}

Check warning on line 159 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L159

[Microsoft.Terms] Prefer 'MB' over 'mb'.
Raw output
{"message": "[Microsoft.Terms] Prefer 'MB' over 'mb'.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 159, "column": 69}}}, "severity": "WARNING"}

As you can see, the test results aren't much different, since this is just a clean application template
that contains a few classes. More discussion of preloading, including benchmarks,
can be found in the [composer's issue](https://github.com/composer/composer/issues/7777).

Check notice on line 163 in guide/en/tutorial/performance-tuning.md

View workflow job for this annotation

GitHub Actions / vale

[vale] guide/en/tutorial/performance-tuning.md#L163

[Microsoft.Passive] 'be found' looks like passive voice.
Raw output
{"message": "[Microsoft.Passive] 'be found' looks like passive voice.", "location": {"path": "guide/en/tutorial/performance-tuning.md", "range": {"start": {"line": 163, "column": 5}}}, "severity": "INFO"}

## Performance profiling <span id="performance-profiling"></span>

Expand Down
Loading