تحسين الأداء في Laravel: دليل شامل للـ Performance Optimization

Laravel

تحسين الأداء في Laravel: دليل شامل للـ Performance Optimization
استراتيجيات متقدمة لتحسين أداء تطبيقات Laravel، من Database Optimization إلى Caching وQueue Management.
#Laravel#Performance#Optimization#Caching#Database#Queues#Redis#Elasticsearch

تحسين الأداء في Laravel: دليل شامل للـ Performance Optimization

دليل تخصصي من علاء عامر – مطور ومصمم مواقع وتطبيقات محترف

تحسين أداء Laravel أساسي لبناء تطبيقات سريعة وقابلة للتطوير. تعلم أحدث استراتيجيات الأداء والتحسين.


1️⃣ Database Optimization استراتيجيات متقدمة

التحسينالتأثيرصعوبة التطبيقأولوية التنفيذ
Database Indexingعالي جداًمتوسط🔥 عاجل
Query Optimizationعاليمتوسط🔥 عاجل
Eager Loadingعاليسهل🔥 عاجل
Database Connection Poolمتوسطصعب⭐ مهم

Database Indexes المحسنة:

<?php
// database/migrations/add_performance_indexes.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddPerformanceIndexes extends Migration
{
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            // فهرسة مفردة للأعمدة المستخدمة بكثرة
            $table->index('status');
            $table->index('published_at');
            $table->index('created_at');
            $table->index('user_id');
            $table->index('category_id');

            // فهرسة مركبة للاستعلامات المعقدة
            $table->index(['status', 'published_at'], 'posts_status_published_idx');
            $table->index(['user_id', 'status'], 'posts_user_status_idx');
            $table->index(['category_id', 'status', 'published_at'], 'posts_category_status_published_idx');

            // فهرسة نصية للبحث
            $table->fulltext(['title', 'content'], 'posts_search_idx');
        });

        Schema::table('users', function (Blueprint $table) {
            $table->index('email'); // للتسجيل السريع
            $table->index('status');
            $table->index('created_at');
            $table->index(['status', 'email_verified_at'], 'users_active_verified_idx');
        });

        Schema::table('comments', function (Blueprint $table) {
            $table->index('post_id');
            $table->index('user_id');
            $table->index('parent_id');
            $table->index(['post_id', 'status'], 'comments_post_status_idx');
        });

        // جداول المحورة
        Schema::table('post_tag', function (Blueprint $table) {
            $table->index('post_id');
            $table->index('tag_id');
        });
    }

    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->dropIndex('posts_status_published_idx');
            $table->dropIndex('posts_user_status_idx');
            $table->dropIndex('posts_category_status_published_idx');
            $table->dropIndex('posts_search_idx');
            $table->dropIndex(['status']);
            $table->dropIndex(['published_at']);
            $table->dropIndex(['created_at']);
            $table->dropIndex(['user_id']);
            $table->dropIndex(['category_id']);
        });
        // باقي dropIndex commands...
    }
}

Query Optimization المتقدم:

<?php
// app/Repositories/PostRepository.php
namespace App\Repositories;

use App\Models\Post;
use Illuminate\Database\Query\Builder;
use Illuminate\Pagination\LengthAwarePaginator;

class PostRepository
{
    /**
     * استعلام محسن للمقالات المنشورة
     */
    public function getPublishedPosts(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = Post::query()
            ->select([
                'posts.id',
                'posts.title',
                'posts.slug',
                'posts.excerpt',
                'posts.featured_image',
                'posts.published_at',
                'posts.views_count',
                'posts.user_id',
                'posts.category_id'
            ])
            ->with([
                'author:id,name,avatar',
                'category:id,name,slug'
            ])
            ->withCount(['comments', 'likes'])
            ->where('posts.status', 'published')
            ->where('posts.published_at', '<=', now());

        // تطبيق الفلاتر
        $this->applyFilters($query, $filters);

        return $query->orderByDesc('posts.published_at')
                    ->paginate($perPage);
    }

    /**
     * استعلام محسن لمقال واحد مع العلاقات
     */
    public function findWithRelations(string $slug): ?Post
    {
        return Post::query()
            ->select([
                'posts.*',
                // حساب إحصائيات مباشرة في الاستعلام
                \DB::raw('(SELECT COUNT(*) FROM comments WHERE post_id = posts.id) as comments_count'),
                \DB::raw('(SELECT COUNT(*) FROM post_likes WHERE post_id = posts.id) as likes_count')
            ])
            ->with([
                'author' => function ($query) {
                    $query->select('id', 'name', 'avatar', 'bio', 'created_at');
                },
                'category:id,name,slug,description',
                'tags:id,name,slug',
                'comments' => function ($query) {
                    $query->select('id', 'content', 'user_id', 'post_id', 'created_at', 'parent_id')
                          ->with('user:id,name,avatar')
                          ->whereNull('parent_id')
                          ->latest()
                          ->limit(10);
                }
            ])
            ->where('slug', $slug)
            ->where('status', 'published')
            ->first();
    }

    /**
     * المقالات ذات الصلة (محسن)
     */
    public function getRelatedPosts(Post $post, int $limit = 5): \Illuminate\Database\Eloquent\Collection
    {
        return Post::query()
            ->select('id', 'title', 'slug', 'excerpt', 'featured_image', 'published_at')
            ->where('category_id', $post->category_id)
            ->where('id', '!=', $post->id)
            ->where('status', 'published')
            ->where('published_at', '<=', now())
            ->inRandomOrder()
            ->limit($limit)
            ->get();
    }

    /**
     * البحث المحسن باستخدام Full-Text Search
     */
    public function search(string $term, array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = Post::query()
            ->select([
                'posts.*',
                \DB::raw('MATCH(title, content) AGAINST(? IN BOOLEAN MODE) as relevance_score')
            ])
            ->whereRaw('MATCH(title, content) AGAINST(? IN BOOLEAN MODE)', ["+{$term}*"])
            ->with(['author:id,name', 'category:id,name,slug'])
            ->where('status', 'published')
            ->where('published_at', '<=', now());

        $this->applyFilters($query, $filters);

        return $query->orderByDesc('relevance_score')
                    ->orderByDesc('published_at')
                    ->paginate($perPage);
    }

    /**
     * إحصائيات محسنة
     */
    public function getStatsOptimized(): array
    {
        return \DB::table('posts')
            ->selectRaw('
                COUNT(*) as total_posts,
                SUM(CASE WHEN status = "published" THEN 1 ELSE 0 END) as published_posts,
                SUM(CASE WHEN status = "draft" THEN 1 ELSE 0 END) as draft_posts,
                SUM(views_count) as total_views,
                AVG(views_count) as avg_views_per_post
            ')
            ->first();
    }

    /**
     * Bulk operations محسنة
     */
    public function bulkUpdateViews(array $postIds): void
    {
        \DB::table('posts')
            ->whereIn('id', $postIds)
            ->increment('views_count');
    }

    /**
     * تطبيق الفلاتر
     */
    private function applyFilters(Builder $query, array $filters): void
    {
        if (!empty($filters['category'])) {
            $query->whereHas('category', function ($q) use ($filters) {
                $q->where('slug', $filters['category']);
            });
        }

        if (!empty($filters['author'])) {
            $query->where('user_id', $filters['author']);
        }

        if (!empty($filters['tag'])) {
            $query->whereHas('tags', function ($q) use ($filters) {
                $q->where('slug', $filters['tag']);
            });
        }

        if (!empty($filters['date_from'])) {
            $query->where('published_at', '>=', $filters['date_from']);
        }

        if (!empty($filters['date_to'])) {
            $query->where('published_at', '<=', $filters['date_to']);
        }
    }
}

// app/Models/Post.php - إضافة Scopes محسنة
class Post extends Model
{
    // استعلام محسن للمقالات الشائعة
    public function scopePopular($query, int $days = 7)
    {
        return $query->select('posts.*')
            ->selectRaw('(views_count + (SELECT COUNT(*) FROM post_likes WHERE post_id = posts.id) * 5 + (SELECT COUNT(*) FROM comments WHERE post_id = posts.id) * 3) as popularity_score')
            ->where('published_at', '>=', now()->subDays($days))
            ->orderByDesc('popularity_score');
    }

    // استعلام محسن للمقالات الجديدة
    public function scopeRecent($query, int $limit = 10)
    {
        return $query->select('id', 'title', 'slug', 'excerpt', 'featured_image', 'published_at')
            ->where('status', 'published')
            ->where('published_at', '<=', now())
            ->latest('published_at')
            ->limit($limit);
    }
}

2️⃣ Caching Strategy الشامل

Multi-Level Caching:

<?php
// app/Services/CacheService.php
namespace App\Services;

use Illuminate\Support\Facades\{Cache, Redis};
use Illuminate\Database\Eloquent\Model;

class CacheService
{
    const CACHE_PREFIXES = [
        'posts' => 'posts:',
        'users' => 'users:',
        'categories' => 'categories:',
        'stats' => 'stats:',
        'search' => 'search:'
    ];

    const CACHE_DURATIONS = [
        'short' => 300,      // 5 دقائق
        'medium' => 3600,    // ساعة
        'long' => 86400,     // يوم
        'permanent' => 604800 // أسبوع
    ];

    /**
     * تخزين مؤقت للمقالات مع استراتيجية متقدمة
     */
    public function cachePost(int $postId, callable $callback, string $duration = 'medium'): mixed
    {
        $key = self::CACHE_PREFIXES['posts'] . $postId;

        return Cache::tags(['posts', "post.{$postId}"])
            ->remember($key, self::CACHE_DURATIONS[$duration], $callback);
    }

    /**
     * تخزين مؤقت للاستعلامات المعقدة
     */
    public function cacheQuery(string $key, callable $callback, array $tags = [], string $duration = 'medium'): mixed
    {
        return Cache::tags($tags)
            ->remember($key, self::CACHE_DURATIONS[$duration], $callback);
    }

    /**
     * تخزين مؤقت للإحصائيات
     */
    public function cacheStats(string $type, callable $callback): mixed
    {
        $key = self::CACHE_PREFIXES['stats'] . $type;

        return Cache::tags(['stats'])
            ->remember($key, self::CACHE_DURATIONS['long'], $callback);
    }

    /**
     * تخزين مؤقت للبحث
     */
    public function cacheSearch(string $term, array $filters, callable $callback): mixed
    {
        $key = self::CACHE_PREFIXES['search'] . md5($term . serialize($filters));

        return Cache::tags(['search'])
            ->remember($key, self::CACHE_DURATIONS['short'], $callback);
    }

    /**
     * محو cache متقدم
     */
    public function invalidatePost(int $postId): void
    {
        // محو cache المقال المحدد
        Cache::tags("post.{$postId}")->flush();

        // محو cache المقالات المرتبطة
        Cache::tags(['posts', 'homepage', 'categories'])->flush();

        // محو cache البحث
        Cache::tags(['search'])->flush();
    }

    /**
     * محو cache المستخدم
     */
    public function invalidateUser(int $userId): void
    {
        Cache::tags("user.{$userId}")->flush();
        Cache::forget(self::CACHE_PREFIXES['users'] . $userId);
    }

    /**
     * Warm up cache للبيانات المهمة
     */
    public function warmUpCache(): void
    {
        // تحميل المقالات الشائعة
        $this->cacheQuery('popular_posts', function () {
            return \App\Models\Post::popular(7)->limit(10)->get();
        }, ['posts', 'popular'], 'long');

        // تحميل التصنيفات
        $this->cacheQuery('all_categories', function () {
            return \App\Models\Category::with('posts_count')->get();
        }, ['categories'], 'permanent');

        // تحميل إحصائيات الموقع
        $this->cacheStats('site_stats', function () {
            return [
                'total_posts' => \App\Models\Post::published()->count(),
                'total_users' => \App\Models\User::active()->count(),
                'total_views' => \App\Models\Post::sum('views_count'),
            ];
        });
    }

    /**
     * Redis cache للبيانات السريعة
     */
    public function setRedisCache(string $key, mixed $value, int $seconds = 3600): void
    {
        Redis::setex($key, $seconds, serialize($value));
    }

    public function getRedisCache(string $key): mixed
    {
        $value = Redis::get($key);
        return $value ? unserialize($value) : null;
    }

    /**
     * Rate limiting cache
     */
    public function checkRateLimit(string $identifier, int $maxAttempts = 60, int $decayMinutes = 1): bool
    {
        $key = 'rate_limit:' . $identifier;
        $attempts = (int) Redis::get($key);

        if ($attempts >= $maxAttempts) {
            return false;
        }

        Redis::multi();
        Redis::incr($key);
        Redis::expire($key, $decayMinutes * 60);
        Redis::exec();

        return true;
    }
}

// app/Http/Middleware/CacheHeaders.php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class CacheHeaders
{
    public function handle(Request $request, Closure $next, ...$options)
    {
        $response = $next($request);

        if ($request->method() === 'GET' && $response->getStatusCode() === 200) {
            $cacheType = $options[0] ?? 'default';

            switch ($cacheType) {
                case 'static':
                    $response->header('Cache-Control', 'public, max-age=31536000'); // سنة
                    break;
                case 'dynamic':
                    $response->header('Cache-Control', 'public, max-age=3600'); // ساعة
                    break;
                case 'private':
                    $response->header('Cache-Control', 'private, max-age=300'); // 5 دقائق
                    break;
                default:
                    $response->header('Cache-Control', 'public, max-age=1800'); // 30 دقيقة
            }

            $response->header('ETag', md5($response->getContent()));
        }

        return $response;
    }
}

View Caching المتقدم:

<?php
// app/Services/ViewCacheService.php
namespace App\Services;

use Illuminate\Support\Facades\{View, Cache};

class ViewCacheService
{
    /**
     * تخزين مؤقت للـ Views
     */
    public function cacheView(string $view, array $data = [], int $duration = 3600): string
    {
        $key = 'view:' . $view . ':' . md5(serialize($data));

        return Cache::remember($key, $duration, function () use ($view, $data) {
            return View::make($view, $data)->render();
        });
    }

    /**
     * Fragment caching للأجزاء المعقدة
     */
    public function cacheFragment(string $name, callable $callback, int $duration = 3600): string
    {
        $key = 'fragment:' . $name;

        return Cache::remember($key, $duration, $callback);
    }
}

// استخدام في Blade Templates
// resources/views/components/cached-sidebar.blade.php
@php
$cacheService = app(\App\Services\ViewCacheService::class);
@endphp

{!! $cacheService->cacheFragment('sidebar', function() {
    return view('partials.sidebar', [
        'categories' => \App\Models\Category::withCount('posts')->get(),
        'popular_posts' => \App\Models\Post::popular()->limit(5)->get(),
        'recent_posts' => \App\Models\Post::recent()->limit(5)->get()
    ])->render();
}, 3600) !!}

3️⃣ Queue System التحسين

Advanced Queue Configuration:

<?php
// config/queue.php - إعدادات محسنة
return [
    'default' => env('QUEUE_CONNECTION', 'redis'),

    'connections' => [
        'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => env('REDIS_QUEUE', 'default'),
            'retry_after' => 90,
            'block_for' => null,
            'after_commit' => false,
            'serializer' => 'json',
        ],

        'high_priority' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => 'high_priority',
            'retry_after' => 60,
        ],

        'low_priority' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => 'low_priority',
            'retry_after' => 300,
        ],
    ],

    'failed' => [
        'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
        'database' => env('DB_CONNECTION', 'mysql'),
        'table' => 'failed_jobs',
    ],
];

// app/Jobs/ProcessImageOptimization.php
namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\{InteractsWithQueue, SerializesModels};
use App\Models\Post;

class ProcessImageOptimization implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $tries = 3;
    public $timeout = 300;
    public $maxExceptions = 3;

    public function __construct(
        private Post $post,
        private string $imagePath
    ) {
        // تحديد الـ queue حسب الأولوية
        $this->onQueue('high_priority');

        // تأخير المعالجة إذا لزم الأمر
        $this->delay(now()->addSeconds(10));
    }

    public function handle()
    {
        try {
            // تحسين الصورة
            $optimizedPath = $this->optimizeImage($this->imagePath);

            // تحديث المقال
            $this->post->update(['featured_image' => $optimizedPath]);

            // إنشاء أحجام مختلفة
            $this->createThumbnails($optimizedPath);

            // محو الـ cache
            app(\App\Services\CacheService::class)->invalidatePost($this->post->id);

        } catch (\Exception $e) {
            // تسجيل الخطأ
            \Log::error('Image optimization failed', [
                'post_id' => $this->post->id,
                'image_path' => $this->imagePath,
                'error' => $e->getMessage()
            ]);

            throw $e; // لإعادة المحاولة
        }
    }

    public function failed(\Throwable $exception)
    {
        // إرسال إشعار بالفشل
        \Notification::route('slack', config('slack.webhook'))
            ->notify(new \App\Notifications\JobFailedNotification(
                'Image Optimization Failed',
                $this->post->id,
                $exception->getMessage()
            ));
    }

    private function optimizeImage(string $path): string
    {
        // منطق تحسين الصورة
        return $path;
    }

    private function createThumbnails(string $path): void
    {
        // إنشاء thumbnails
    }
}

// app/Jobs/BatchEmailJob.php - معالجة batch
namespace App\Jobs;

use Illuminate\Bus\{Batchable, Queueable};
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\{InteractsWithQueue, SerializesModels};

class BatchEmailJob implements ShouldQueue
{
    use Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(
        private array $recipients,
        private string $template,
        private array $data
    ) {
        $this->onQueue('low_priority');
    }

    public function handle()
    {
        if ($this->batch()->cancelled()) {
            return;
        }

        foreach ($this->recipients as $recipient) {
            \Mail::to($recipient)->send(new \App\Mail\NewsletterMail($this->template, $this->data));

            // تحديث progress
            $this->batch()->increment();
        }
    }
}

Queue Monitoring & Management:

<?php
// app/Console/Commands/QueueMonitor.php
namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\{Redis, Queue};

class QueueMonitor extends Command
{
    protected $signature = 'queue:monitor {--threshold=100}';
    protected $description = 'Monitor queue performance and send alerts';

    public function handle()
    {
        $threshold = $this->option('threshold');

        $queues = ['default', 'high_priority', 'low_priority'];

        foreach ($queues as $queueName) {
            $size = Queue::size($queueName);

            $this->info("Queue '{$queueName}': {$size} jobs");

            if ($size > $threshold) {
                $this->warn("⚠️ Queue '{$queueName}' has {$size} jobs (threshold: {$threshold})");

                // إرسال إنذار
                $this->sendAlert($queueName, $size);
            }
        }

        // مراقبة الـ failed jobs
        $failedJobs = \DB::table('failed_jobs')->count();
        if ($failedJobs > 10) {
            $this->error("❌ {$failedJobs} failed jobs detected");
            $this->sendFailedJobsAlert($failedJobs);
        }

        // مراقبة memory usage
        $memoryUsage = memory_get_usage(true) / 1024 / 1024;
        $this->info("Memory usage: {$memoryUsage} MB");
    }

    private function sendAlert(string $queue, int $size): void
    {
        // إرسال إشعار Slack أو email
    }

    private function sendFailedJobsAlert(int $count): void
    {
        // إرسال إشعار بالمهام الفاشلة
    }
}

// app/Console/Commands/QueueOptimizer.php
namespace App\Console\Commands;

use Illuminate\Console\Command;

class QueueOptimizer extends Command
{
    protected $signature = 'queue:optimize';
    protected $description = 'Optimize queue performance';

    public function handle()
    {
        // تنظيف الـ completed jobs القديمة
        $this->cleanOldJobs();

        // إعادة تشغيل الـ failed jobs القابلة للإصلاح
        $this->retryRecoverableJobs();

        // تحسين Redis memory
        $this->optimizeRedisMemory();

        $this->info('Queue optimization completed');
    }

    private function cleanOldJobs(): void
    {
        $this->call('queue:prune-batches', ['--hours' => 48]);
        $this->call('queue:flush');
    }

    private function retryRecoverableJobs(): void
    {
        // منطق إعادة المحاولة للمهام القابلة للإصلاح
    }

    private function optimizeRedisMemory(): void
    {
        \Redis::command('MEMORY', ['PURGE']);
    }
}

4️⃣ Front-end Optimization

Asset Optimization:

<?php
// webpack.mix.js - تحسين الأصول
const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js')
   .sass('resources/sass/app.scss', 'public/css')
   .options({
       processCssUrls: false,
       postCss: [
           require('autoprefixer'),
           require('cssnano')({
               preset: ['default', { discardComments: { removeAll: true } }]
           })
       ]
   })
   .version()
   .sourceMaps(false, 'source-map');

// تحسين الصور
mix.copy('resources/images', 'public/images')
   .then(() => {
       // ضغط الصور
       const imagemin = require('imagemin');
       const imageminPngquant = require('imagemin-pngquant');
       const imageminMozjpeg = require('imagemin-mozjpeg');

       imagemin(['public/images/*.{jpg,png}'], {
           destination: 'public/images/optimized',
           plugins: [
               imageminMozjpeg({ quality: 80 }),
               imageminPngquant({ quality: [0.6, 0.8] })
           ]
       });
   });

// Code splitting
mix.extract(['vue', 'axios', 'lodash']);

if (mix.inProduction()) {
    mix.options({
        terser: {
            terserOptions: {
                compress: {
                    drop_console: true,
                }
            }
        }
    });
}

CDN Integration:

<?php
// app/Services/CDNService.php
namespace App\Services;

class CDNService
{
    private array $cdnDomains;
    private bool $enabled;

    public function __construct()
    {
        $this->cdnDomains = config('cdn.domains', []);
        $this->enabled = config('cdn.enabled', false);
    }

    public function asset(string $path): string
    {
        if (!$this->enabled || empty($this->cdnDomains)) {
            return asset($path);
        }

        // توزيع الأصول على domains متعددة
        $domainIndex = crc32($path) % count($this->cdnDomains);
        $domain = $this->cdnDomains[$domainIndex];

        return rtrim($domain, '/') . '/' . ltrim($path, '/');
    }

    public function image(string $path, array $transformations = []): string
    {
        $url = $this->asset($path);

        if (!empty($transformations)) {
            $params = http_build_query($transformations);
            $url .= '?' . $params;
        }

        return $url;
    }
}

// Helper function
if (!function_exists('cdn_asset')) {
    function cdn_asset(string $path): string {
        return app(\App\Services\CDNService::class)->asset($path);
    }
}

// config/cdn.php
return [
    'enabled' => env('CDN_ENABLED', false),
    'domains' => [
        'https://cdn1.yoursite.com',
        'https://cdn2.yoursite.com',
        'https://cdn3.yoursite.com',
    ],
];

💡 Performance Monitoring

Advanced Performance Tracking:

<?php
// app/Middleware/PerformanceMonitor.php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\{DB, Log, Redis};

class PerformanceMonitor
{
    public function handle(Request $request, Closure $next)
    {
        $startTime = microtime(true);
        $startMemory = memory_get_usage(true);

        // تسجيل بداية الطلب
        $requestId = uniqid();
        $request->attributes->set('request_id', $requestId);

        // تشغيل query logging
        DB::enableQueryLog();

        $response = $next($request);

        $endTime = microtime(true);
        $endMemory = memory_get_usage(true);

        $metrics = [
            'request_id' => $requestId,
            'url' => $request->fullUrl(),
            'method' => $request->method(),
            'execution_time' => round(($endTime - $startTime) * 1000, 2), // ms
            'memory_usage' => round(($endMemory - $startMemory) / 1024 / 1024, 2), // MB
            'peak_memory' => round(memory_get_peak_usage(true) / 1024 / 1024, 2),
            'queries_count' => count(DB::getQueryLog()),
            'response_size' => strlen($response->getContent()),
            'status_code' => $response->getStatusCode(),
            'user_id' => auth()->id(),
            'ip' => $request->ip(),
            'timestamp' => now()->toISOString(),
        ];

        // تحليل الاستعلامات البطيئة
        $slowQueries = collect(DB::getQueryLog())
            ->where('time', '>', 100) // أبطأ من 100ms
            ->count();

        if ($slowQueries > 0) {
            $metrics['slow_queries_count'] = $slowQueries;
        }

        // إرسال البيانات للتحليل
        $this->sendMetrics($metrics);

        // إضافة headers للتشخيص
        $response->headers->set('X-Execution-Time', $metrics['execution_time'] . 'ms');
        $response->headers->set('X-Memory-Usage', $metrics['memory_usage'] . 'MB');
        $response->headers->set('X-Queries-Count', $metrics['queries_count']);

        return $response;
    }

    private function sendMetrics(array $metrics): void
    {
        // إرسال للـ Redis للتحليل السريع
        Redis::lpush('performance_metrics', json_encode($metrics));
        Redis::ltrim('performance_metrics', 0, 1000); // الاحتفاظ بآخر 1000 طلب

        // تسجيل الطلبات البطيئة
        if ($metrics['execution_time'] > 1000) { // أبطأ من ثانية
            Log::warning('Slow request detected', $metrics);
        }

        // إرسال للـ monitoring service (مثل New Relic, DataDog)
        if (config('monitoring.enabled')) {
            $this->sendToMonitoringService($metrics);
        }
    }

    private function sendToMonitoringService(array $metrics): void
    {
        // إرسال البيانات لخدمة المراقبة الخارجية
    }
}

الخطوة التالية

تعلم Deployment و DevOps في Laravel لنشر تطبيقاتك بكفاءة عالية.

📩 هل تحتاج مساعدة في تحسين أداء تطبيقك؟

aboutservicesprojectsBlogscontact