Ваш проект на Yii2 внезапно начал тормозить, когда пользователей стало больше сотни? Или вы только планируете запуск, который должен выдержать тысячи запросов в секунду? Тогда эта статья для вас. Мы разберём, как превратить обычное приложение на Yii2 в высоконагруженную систему без боли и лишних костылей.
Почему Yii2 — не тормоз, а просто требует настройки
Многие думают: «Yii2 — это для средних проектов, для высоких нагрузок нужен Go или Node.js». Это заблуждение. Yii2 — это фреймворк, который может работать быстро, если понимать, как он устроен. Он не медленный, он просто «умный»: по умолчанию делает много лишнего, чтобы разработчику было удобно. Но когда приходит нагрузка, эту «умность» нужно отключать.
Представьте, что вы едете на внедорожнике по трассе. Комфортно, но бензин жрёт. А если нужно обогнать всех — включаете спортивный режим. Вот и с Yii2 так же: есть режим «разработка», а есть «продакшн под нагрузкой».
Кэширование: ваш главный союзник
Если вы не используете кэш, вы выбрасываете деньги и ресурсы на ветер. В Yii2 есть несколько уровней кэширования, и их нужно комбинировать.
Первый уровень — кэш данных. Это когда вы сохраняете результат тяжёлого запроса в Redis или Memcached. Например, вместо того чтобы каждый раз считать количество товаров в категории, вы кэшируете это число на 5 минут.
$count = Yii::$app->cache->get('category_count_' . $categoryId);
if ($count === false) {
$count = Product::find()->where(['category_id' => $categoryId])->count();
Yii::$app->cache->set('category_count_' . $categoryId, $count, 300);
}
return $count;
Второй уровень — кэш фрагментов. Если у вас есть блок «Популярные товары», который одинаков для всех пользователей, кэшируйте его целиком.
beginCache('popular_products', ['duration' => 3600])): ?>
= $product->name ?>
endCache(); endif; ?>
Третий уровень — HTTP-кэш. Отдавайте статику с заголовками Cache-Control и ETag. Браузер сам будет кэшировать картинки и стили, не дёргая ваш сервер.
Работа с базой данных: где чаще всего рвётся
База данных — это узкое место 90% высоконагруженных приложений. И Yii2 даёт вам инструменты, чтобы это место расширить.
1. Избегайте N+1 запросов. Это когда вы в цикле делаете запрос для каждой записи. Используйте жадную загрузку (with).
// Плохо: 100 запросов
$orders = Order::find()->all();
foreach ($orders as $order) {
echo $order->user->name;
}
// Хорошо: 2 запроса
$orders = Order::find()->with('user')->all();
foreach ($orders as $order) {
echo $order->user->name;
}
2. Используйте репликацию. Настройте master-slave: запись идёт на master, чтение — на slave. В Yii2 это делается в конфиге компонента db.
'db' => [
'class' => 'yii\db\Connection',
'masters' => [
['dsn' => 'mysql:host=master;dbname=app'],
],
'slaves' => [
['dsn' => 'mysql:host=slave1;dbname=app'],
['dsn' => 'mysql:host=slave2;dbname=app'],
],
],
3. Индексы — это не роскошь. Проверьте EXPLAIN для каждого тяжёлого запроса. Если видите «Using filesort» или «Using temporary» — добавьте индекс.
Вот таблица, которая поможет быстро понять, какой тип кэша или оптимизации использовать в разных ситуациях:
| Проблема | Решение | Инструмент Yii2 |
|---|---|---|
| Много одинаковых запросов к БД | Кэш данных | Yii::$app->cache |
| Тяжёлые выборки с JOIN | Репликация + индексы | db->masters/slaves |
| Долгие операции (отправка почты, генерация отчётов) | Очереди | yii\queue\Queue |
| Медленный рендеринг страниц | Кэш фрагментов | beginCache/endCache |
Очереди и фоновые задачи: не заставляйте пользователя ждать
Если пользователь нажал «Отправить заказ», он не должен ждать, пока вы сформируете PDF, отправите письмо и обновите статистику. Всё это нужно делать в фоне.
Yii2 имеет официальное расширение yii2-queue. Оно поддерживает Redis, RabbitMQ, AMQP, базы данных. Настройка проста:
// config/main.php
'components' => [
'queue' => [
'class' => 'yii\queue\redis\Queue',
'hostname' => 'localhost',
'port' => 6379,
'database' => 0,
],
],
Теперь в контроллере вы не делаете тяжёлую работу, а просто кидаете задачу в очередь:
Yii::$app->queue->push(new SendOrderEmailJob([
'orderId' => $order->id,
]));
А воркер (отдельный процесс) будет разгребать эти задачи. Это позволяет обрабатывать тысячи заказов, не блокируя веб-сервер.
Профилирование и мониторинг: без цифр вы слепы
Нельзя оптимизировать то, что не измеряешь. В Yii2 есть встроенный профайлер, но для продакшна он не подходит — слишком тяжёлый. Используйте Xdebug или Blackfire для локальной разработки, а на сервере — APM-системы (New Relic, Tideways).
Как минимум, включите логирование медленных запросов в MySQL:
// В конфиге db
'enableLogging' => YII_DEBUG,
'enableProfiling' => YII_DEBUG,
А для продакшна настройте slow query log на уровне MySQL (long_query_time = 1). Все запросы дольше секунды должны попадать в лог и разбираться.
Также обязательно используйте кэш схемы БД. Yii2 по умолчанию загружает метаданные таблиц при каждом запросе. Включите кэширование схемы:
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=app',
'enableSchemaCache' => true,
'schemaCacheDuration' => 3600,
'schemaCache' => 'cache',
],
Что в итоге: короткое резюме
Высоконагруженное приложение на Yii2 — это не магия, а набор простых правил. Кэшируйте всё, что можно. Избегайте N+1 запросов. Используйте репликацию и очереди. Следите за медленными запросами. И не забывайте про мониторинг.
Если вы только начинаете — внедряйте эти практики с самого начала. Если у вас уже есть проект — начните с профилирования, найдите узкое место и устраните его. Yii2 выдержит и миллион запросов в день, если подойти с умом.
Помните: производительность — это не разовое действие, а процесс. Постоянно измеряйте, оптимизируйте и тестируйте.


