Оптимизация TTFB (Time to First Byte)
TTFB — время от отправки запроса до получения первого байта ответа сервера. Хорошее значение: ≤ 800 мс (Google считает приемлемым до 600 мс). TTFB напрямую влияет на LCP: невозможно иметь хороший LCP при плохом TTFB.
Из чего складывается TTFB
DNS → TCP → TLS → Запрос → Обработка на сервере → Первый байт ответа
Типичное разбивка:
- DNS lookup: 10–100 мс (решается через preconnect + CDN)
- TCP + TLS: 30–150 мс (решается через HTTP/2, CDN)
- Server processing: 50–3000+ мс (самая управляемая часть)
Full Page Cache
Самый эффективный способ: закешировать готовый HTML.
// spatie/laravel-responsecache или кастомное решение
// Middleware добавляется для гостевых запросов GET
class FullPageCache
{
private const TTL = 300; // 5 минут
public function handle(Request $request, Closure $next): Response
{
if (!$this->isCacheable($request)) {
return $next($request);
}
$key = $this->cacheKey($request);
if (Cache::has($key)) {
return response(Cache::get($key))
->header('X-Cache', 'HIT')
->header('Content-Type', 'text/html; charset=UTF-8');
}
$response = $next($request);
if ($response->getStatusCode() === 200) {
Cache::put($key, $response->getContent(), self::TTL);
}
return $response->header('X-Cache', 'MISS');
}
private function isCacheable(Request $request): bool
{
return $request->isMethod('GET')
&& !auth()->check()
&& !$request->hasCookie(session()->getName());
}
private function cacheKey(Request $request): string
{
return 'fpc:' . sha1($request->fullUrl());
}
}
Nginx FastCGI Cache
Кеш на уровне nginx — быстрее чем кеш в PHP/Redis:
# nginx.conf
fastcgi_cache_path /var/cache/nginx/fcgi
levels=1:2
keys_zone=LARAVEL:10m
inactive=60m
max_size=1g;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
server {
location ~ \.php$ {
fastcgi_cache LARAVEL;
fastcgi_cache_valid 200 5m;
fastcgi_cache_valid 404 1m;
# Не кешировать для авторизованных
fastcgi_cache_bypass $cookie_laravel_session $http_authorization;
fastcgi_no_cache $cookie_laravel_session $http_authorization;
add_header X-Fastcgi-Cache $upstream_cache_status;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
}
Инвалидация по тегу (через nginx-cache-purge модуль):
curl -X PURGE https://example.ru/products/iphone-15-pro
Оптимизация запросов к базе данных
// Медленный запрос: N+1 problem
$products = Product::all();
foreach ($products as $product) {
echo $product->category->name; // N+1 запросов к categories
}
// Быстро: eager loading
$products = Product::with(['category', 'images', 'brand'])->get();
// Профилирование медленных запросов
DB::listen(function ($query) {
if ($query->time > 100) {
Log::warning('Slow query', [
'sql' => $query->sql,
'time' => $query->time,
]);
}
});
Redis для кеширования данных
// Кеш результатов тяжёлых запросов
$categories = Cache::remember('categories:tree', 3600, function () {
return Category::with('children')
->whereNull('parent_id')
->orderBy('sort_order')
->get();
});
// Кеш счётчиков
$stats = Cache::remember('product:stats:' . $productId, 300, function () use ($productId) {
return [
'views' => ProductView::where('product_id', $productId)->count(),
'sales' => OrderItem::where('product_id', $productId)->sum('quantity'),
'wishlist' => WishlistItem::where('product_id', $productId)->count(),
];
});
DNS и сетевые оптимизации
<!-- Preconnect к критическим ресурсам -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.ru" crossorigin>
<link rel="dns-prefetch" href="https://analytics.google.com">
OPcache для PHP
; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; 0 в production
opcache.jit=tracing
opcache.jit_buffer_size=64M
Целевые значения по типам запросов
| Тип страницы | С кешем | Без кеша |
|---|---|---|
| Главная | < 50 мс | < 300 мс |
| Каталог | < 50 мс | < 400 мс |
| Карточка товара | < 50 мс | < 200 мс |
| API-эндпоинты | — | < 100 мс |
Срок оптимизации: 2–3 дня для настройки кеширования и профилирования запросов.







