Get 20% off web development packages
Laravel Performance Optimization: Advanced Techniques & Monitoring
Laravel Performance Optimization: Advanced Techniques & Monitoring
Expert Guide by Alaa Amer – Professional Web Developer & Applications Designer
Laravel performance optimization is crucial for scalable applications. Master caching strategies, database optimization, queue management, and advanced monitoring techniques.
2️⃣ Advanced Caching Strategies
Multi-Layer Caching Implementation:
<?php
// app/Services/CacheService.php
namespace App\Services;
use Illuminate\Support\Facades\{Cache, Redis};
use Illuminate\Contracts\Cache\Repository;
class CacheService
{
protected $cache;
protected $redis;
public function __construct(Repository $cache)
{
$this->cache = $cache;
$this->redis = Redis::connection();
}
/**
* Multi-layer caching with fallback
*/
public function remember(string $key, $ttl, callable $callback, array $tags = [])
{
// Layer 1: Memory cache (fastest)
static $memoryCache = [];
if (isset($memoryCache[$key])) {
return $memoryCache[$key];
}
// Layer 2: Application cache (Redis/Memcached)
$value = $this->cache->tags($tags)->remember($key, $ttl, function () use ($callback, &$memoryCache, $key) {
$result = $callback();
$memoryCache[$key] = $result; // Store in memory for this request
return $result;
});
return $value;
}
/**
* Smart cache invalidation
*/
public function invalidate(string $pattern): int
{
$keys = $this->redis->keys($pattern);
if (empty($keys)) {
return 0;
}
return $this->redis->del($keys);
}
/**
* Cache warming for critical data
*/
public function warm(array $keys): void
{
foreach ($keys as $key => $config) {
if (!$this->cache->has($key)) {
$value = call_user_func($config['callback']);
$this->cache->put($key, $value, $config['ttl'] ?? 3600);
}
}
}
/**
* Distributed cache lock
*/
public function lock(string $key, int $timeout = 10): ?Lock
{
return $this->cache->lock($key, $timeout);
}
/**
* Cache statistics
*/
public function getStats(): array
{
$info = $this->redis->info('memory');
return [
'used_memory' => $info['used_memory_human'] ?? 'N/A',
'hit_rate' => $this->getHitRate(),
'key_count' => $this->redis->dbsize(),
'expired_keys' => $info['expired_keys'] ?? 0,
'evicted_keys' => $info['evicted_keys'] ?? 0
];
}
protected function getHitRate(): string
{
$info = $this->redis->info('stats');
$hits = $info['keyspace_hits'] ?? 0;
$misses = $info['keyspace_misses'] ?? 0;
$total = $hits + $misses;
if ($total === 0) {
return '0%';
}
return round(($hits / $total) * 100, 2) . '%';
}
}
// app/Services/PostCacheService.php - Domain-specific caching
namespace App\Services;
class PostCacheService
{
protected $cacheService;
public function __construct(CacheService $cacheService)
{
$this->cacheService = $cacheService;
}
public function getPopularPosts(int $limit = 10)
{
return $this->cacheService->remember(
"posts.popular.{$limit}",
3600, // 1 hour
function () use ($limit) {
return Post::published()
->withCount(['likes', 'comments', 'views'])
->orderByDesc('likes_count')
->limit($limit)
->get();
},
['posts', 'popular']
);
}
public function getPost(int $id)
{
return $this->cacheService->remember(
"posts.{$id}",
7200, // 2 hours
function () use ($id) {
return Post::with(['user', 'category', 'tags'])->find($id);
},
['posts', "post.{$id}"]
);
}
public function getCategoryPosts(int $categoryId, int $page = 1)
{
return $this->cacheService->remember(
"posts.category.{$categoryId}.page.{$page}",
1800, // 30 minutes
function () use ($categoryId, $page) {
return Post::where('category_id', $categoryId)
->published()
->with(['user', 'tags'])
->paginate(15, ['*'], 'page', $page);
},
['posts', "category.{$categoryId}"]
);
}
public function invalidatePost(Post $post): void
{
$tags = [
'posts',
"post.{$post->id}",
"category.{$post->category_id}",
"user.{$post->user_id}.posts"
];
Cache::tags($tags)->flush();
// Also invalidate related caches
if ($post->is_featured) {
Cache::tags(['popular', 'featured'])->flush();
}
}
public function warmCache(): void
{
$this->cacheService->warm([
'posts.popular.10' => [
'callback' => fn() => $this->getPopularPosts(10),
'ttl' => 3600
],
'posts.recent.20' => [
'callback' => fn() => Post::published()->latest()->limit(20)->get(),
'ttl' => 1800
],
'categories.with_counts' => [
'callback' => fn() => Category::withCount('posts')->get(),
'ttl' => 7200
]
]);
}
}
Response Caching Middleware:
<?php
// app/Http/Middleware/CacheResponse.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
class CacheResponse
{
public function handle(Request $request, Closure $next, int $ttl = 300)
{
// Only cache GET requests
if ($request->method() !== 'GET') {
return $next($request);
}
// Don't cache authenticated requests by default
if (auth()->check() && !$request->has('public')) {
return $next($request);
}
$cacheKey = $this->getCacheKey($request);
// Try to get cached response
$cachedResponse = Cache::get($cacheKey);
if ($cachedResponse) {
return response($cachedResponse['content'])
->withHeaders($cachedResponse['headers'])
->header('X-Cache-Status', 'HIT');
}
// Generate response
$response = $next($request);
// Only cache successful responses
if ($response->getStatusCode() === 200) {
$cacheData = [
'content' => $response->getContent(),
'headers' => [
'Content-Type' => $response->headers->get('Content-Type'),
'Cache-Control' => 'public, max-age=' . $ttl
]
];
Cache::put($cacheKey, $cacheData, $ttl);
$response->header('X-Cache-Status', 'MISS');
}
return $response;
}
protected function getCacheKey(Request $request): string
{
$url = $request->fullUrl();
$acceptHeader = $request->header('Accept', 'text/html');
return 'response_cache:' . md5($url . $acceptHeader);
}
}
// Usage in routes
Route::middleware(['cache.response:3600'])->group(function () {
Route::get('/blog', [BlogController::class, 'index']);
Route::get('/blog/{post}', [BlogController::class, 'show']);
});
4️⃣ Queue & Job Optimization
High-Performance Queue Configuration:
<?php
// app/Jobs/OptimizedEmailJob.php
namespace App\Jobs;
use Illuminate\Bus\{Queueable, Batchable};
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\{InteractsWithQueue, SerializesModels, Middleware\WithoutOverlapping};
class OptimizedEmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Batchable;
public $timeout = 120;
public $maxExceptions = 3;
public $backoff = [10, 30, 60]; // Exponential backoff
protected $userId;
protected $emailData;
public function __construct(int $userId, array $emailData)
{
$this->userId = $userId;
$this->emailData = $emailData;
// Optimize queue routing
$this->onQueue('emails');
}
public function middleware(): array
{
return [
// Prevent duplicate jobs
new WithoutOverlapping($this->userId),
// Rate limiting
(new RateLimited('emails'))->allow(100)->everyMinute(),
];
}
public function handle(): void
{
$user = User::find($this->userId);
if (!$user || !$user->email_notifications_enabled) {
return;
}
try {
Mail::to($user)->send(new UserNotification($this->emailData));
// Update user activity
$user->touch('last_email_sent_at');
} catch (Exception $e) {
// Log the error
Log::error('Email job failed', [
'user_id' => $this->userId,
'error' => $e->getMessage(),
'attempts' => $this->attempts()
]);
// Release job for retry if attempts remaining
if ($this->attempts() < $this->maxExceptions) {
$this->release($this->backoff[$this->attempts() - 1] ?? 60);
} else {
$this->fail($e);
}
}
}
public function failed(Exception $exception): void
{
// Handle permanent failure
Log::critical('Email job permanently failed', [
'user_id' => $this->userId,
'exception' => $exception->getMessage()
]);
// Notify administrators
NotificationFacade::route('slack', '#alerts')
->notify(new JobFailedNotification($this, $exception));
}
}
// app/Console/Commands/OptimizeQueues.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\{Queue, Redis};
class OptimizeQueues extends Command
{
protected $signature = 'queue:optimize';
protected $description = 'Optimize queue performance and clean up failed jobs';
public function handle(): void
{
$this->info('Optimizing queue performance...');
// Clean up old failed jobs
$this->cleanupFailedJobs();
// Balance queue workers
$this->balanceWorkers();
// Monitor queue health
$this->monitorQueueHealth();
$this->info('Queue optimization completed!');
}
protected function cleanupFailedJobs(): void
{
$olderThan = now()->subDays(7);
$deleted = DB::table('failed_jobs')
->where('failed_at', '<', $olderThan)
->delete();
$this->line("Cleaned up {$deleted} old failed jobs");
}
protected function balanceWorkers(): void
{
$queueSizes = [
'default' => Queue::size('default'),
'emails' => Queue::size('emails'),
'high' => Queue::size('high'),
'low' => Queue::size('low')
];
$this->table(
['Queue', 'Size', 'Recommended Workers'],
collect($queueSizes)->map(function ($size, $name) {
$workers = $this->calculateOptimalWorkers($size);
return [$name, $size, $workers];
})->values()->toArray()
);
}
protected function calculateOptimalWorkers(int $queueSize): int
{
if ($queueSize === 0) return 1;
if ($queueSize <= 10) return 2;
if ($queueSize <= 100) return 5;
if ($queueSize <= 1000) return 10;
return 20;
}
protected function monitorQueueHealth(): void
{
$redis = Redis::connection();
$info = $redis->info('memory');
$memoryUsage = $info['used_memory_human'] ?? 'Unknown';
$this->line("Redis memory usage: {$memoryUsage}");
// Check for stuck jobs
$stuckJobs = DB::table('jobs')
->where('reserved_at', '<', now()->subMinutes(30))
->whereNotNull('reserved_at')
->count();
if ($stuckJobs > 0) {
$this->warn("Found {$stuckJobs} potentially stuck jobs");
}
}
}
Queue Monitoring Dashboard:
<?php
// app/Http/Controllers/Admin/QueueMonitorController.php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\{Queue, DB, Redis};
class QueueMonitorController extends Controller
{
public function dashboard()
{
$stats = [
'queue_sizes' => $this->getQueueSizes(),
'failed_jobs' => $this->getFailedJobsStats(),
'worker_status' => $this->getWorkerStatus(),
'throughput' => $this->getThroughputStats(),
'memory_usage' => $this->getMemoryUsage()
];
return view('admin.queue-dashboard', compact('stats'));
}
protected function getQueueSizes(): array
{
return [
'default' => Queue::size('default'),
'high' => Queue::size('high'),
'emails' => Queue::size('emails'),
'low' => Queue::size('low')
];
}
protected function getFailedJobsStats(): array
{
return [
'total' => DB::table('failed_jobs')->count(),
'last_24h' => DB::table('failed_jobs')
->where('failed_at', '>=', now()->subDay())
->count(),
'by_queue' => DB::table('failed_jobs')
->select('queue', DB::raw('COUNT(*) as count'))
->groupBy('queue')
->get()
->pluck('count', 'queue')
->toArray()
];
}
protected function getWorkerStatus(): array
{
// This would integrate with your process manager
return [
'active_workers' => 5, // Get from supervisor/systemd
'idle_workers' => 2,
'busy_workers' => 3
];
}
protected function getThroughputStats(): array
{
$hourly = [];
for ($i = 23; $i >= 0; $i--) {
$hour = now()->subHours($i)->format('Y-m-d H:00:00');
$hourly[$hour] = DB::table('job_batches')
->where('finished_at', '>=', $hour)
->where('finished_at', '<', now()->subHours($i-1)->format('Y-m-d H:00:00'))
->sum('total_jobs') ?? 0;
}
return $hourly;
}
protected function getMemoryUsage(): array
{
$redis = Redis::connection();
$info = $redis->info();
return [
'used_memory' => $info['used_memory_human'] ?? 'N/A',
'peak_memory' => $info['used_memory_peak_human'] ?? 'N/A',
'fragmentation_ratio' => $info['mem_fragmentation_ratio'] ?? 'N/A'
];
}
}
Next Steps
Deploy your optimized Laravel application with Deployment & DevOps strategies for production environments.
📩 Need help with Laravel performance?
Article Category
Laravel Performance Optimization: Advanced Techniques & Monitoring
Master Laravel performance optimization with caching, database optimization, queue management, profiling tools, and enterprise-level scaling strategies.
Consultation & Communication
Direct communication via WhatsApp or phone to understand your project needs precisely.
Planning & Scheduling
Creating clear work plan with specific timeline for each project phase.
Development & Coding
Building projects with latest technologies ensuring high performance and security.
Testing & Delivery
Comprehensive testing and thorough review before final project delivery.
Services Related to This Article
All ServicesWant to apply this article to your project?
If this topic is relevant to your current project, you can jump to one of the services above or browse the services page to choose the most suitable solution.