Yavaş Laravel uygulamaları kullanıcı kaybına ve gelir kaybına neden olur. Bu rehber, veritabanı sorgularından önbellekleme stratejilerine ve kuyruk yönetimine kadar, üretimde etkili olan pratik performans optimizasyon tekniklerini kapsamaktadır.
Riad Hasan, milyonlarca sorgu yöneten Laravel uygulamalarını optimize etmiş bir tam yığın geliştiricisidir. İşte gerçekten fark yaratan teknikler:
Performans Problemi
Performans Problemi
Riad Hasan aşağıdaki yaygın darboğazları belirtmektedir:
| Problem | Etkisi | Çözüm |
|---|---|---|
| N+1 sorguları | 100 kat daha yavaş sayfa yüklenmeleri | Eager loading |
| Önbellek yok | Tekrarlanan pahalı işlemler | Redis caching |
| Eşzamanlı ağır görevler | İstek zaman aşımı | Kuyruk işçileri |
| Optimize edilmemiş indeksler | Yavaş veritabanı sorguları | Uygun indeksleme |
| Büyük yükler | Bellek tükenmesi | Paginasyon |
Bölüm 1: Veritabanı Sorgusu Optimizasyonu
Bölüm 1: Veritabanı Sorgusu Optimizasyonu
N+1 Problemlerini Tespit Etme
N+1 Problemlerini Tespit Etme
Riad Hasan, N+1 sorguları tespit etmek için Laravel Debugbar kullanmaktadır:
// Kötü: N+1 sorgu problemi
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name; // Her post için veritabanını sorgular
}
// İyi: Eager loading
$posts = Post::with('author')->get();
foreach ($posts as $post) {
echo $post->author->name; // Ek sorgu yok
}
Birden Fazla İlişki için Eager Loading
Birden Fazla İlişki için Eager Loading
// Çok sayıda ilişkide verimli yükleme
$posts = Post::with(['author', 'category', 'tags', 'comments.user'])
->where('published', true)
->get();
Eager Loading Kısıtlaması
Eager Loading Kısıtlaması
Riad Hasan, veriyi azaltmak için eager loading’i kısıtlamaktadır:
// Yalnızca yayımlanan yorumları yükle
$posts = Post::with(['comments' => function ($query) {
$query->where(, true)
->latest()
->limit(10);
}])->get();
Yalnızca Gerekli Sütunları Seçme
Yalnızca Gerekli Sütunları Seçme
// Kötü: Ağırlıklı içerikler de dahil olmak üzere tüm sütunları yükler
$posts = Post::all();
// İyi: Yalnızca ihtiyaç duyduğunuzları seçin
$posts = Post::select(, , , )
->where(, true)
->get();
Büyük Veri Kümesini Parçalar Halinde İşleme
Büyük Veri Kümesini Parçalar Halinde İşleme
Riad Hasan, büyük veri kümelerini parçalar halinde işlemektedir:
// Her seferinde 100 kaydı işleyin
Post::chunk(100, function ($posts) {
foreach ($posts as $post) {
// Her bir gönderiyi işleyin
}
});
// Ya da bellek verimliliği için lazy collections kullanın
Post::lazy()->each(function ($post) {
// Birer birer işle
});
Bölüm 2: Veritabanı İndeksleme
Bölüm 2: Veritabanı İndeksleme
Eksik İndeksleri Tespit Etme
Eksik İndeksleri Tespit Etme
-- Yavaş sorguları kontrol et
SELECT * FROM mysql.slow_log ORDER BY query_time DESC LIMIT 10;
-- Ya da Laravel'in sorgu günlüğünü kullan
DB::enableQueryLog();
// Kodunuzu çalıştırın
dd(DB::getQueryLog());
Göçler ile İndeks Ekleme
Göçler ile İndeks Ekleme
Riad Hasan, indeksleri stratejik olarak ekler:
// İndeks eklemek için göç
public function up()
{
Schema::table(, function (Blueprint $table) {
// Tek sütun indeksi
$table->index();
// Yaygın sorgular için bileşik indeks
$table->index([, ]);
// Benzersiz indeks
$table->unique();
// Arama için tam metin indeksi
$table->fullText();
});
}
İndeks Stratejisi
İndeks Stratejisi
| Sorgu Türü | İndeks Stratejisi |
|---|---|
| WHERE column = value | Tek sütun indeksi |
| WHERE a = x AND b = y | Bileşik indeks (a, b) |
| ORDER BY column | Indeks sütunu |
| JOIN ON column | Yabancı anahtar üzerinde indeks |
| LIKE ‘%term%’ | Tam metin indeksi |
Bölüm 3: Önbellekleme Stratejileri
Bölüm 3: Önbellekleme Stratejileri
Temel Önbellekleme
Temel Önbellekleme
Riad Hasan birden fazla seviyede önbellekleme uygular:
// Sorgu sonuçlarını önbellekle
$posts = Cache::remember(, 3600, function () {
return Post::with( )
->where(, true)
->orderBy(, )
->limit(10)
->get();
});
// Kolay temizleme için etiketlerle önbellekle
$posts = Cache::tags([, ])->remember(
,
3600,
fn() => Post::where(, true)->get()
);
// Güncellenince önbelleklenmiş gönderileri temizle
Cache::tags([])->flush();
Kullanıcıya Özel Verileri Önbelleklemek
Kullanıcıya Özel Verileri Önbelleklemek
// Kullanıcı başına önbellek
$notifications = Cache::remember(
{$userId},
300,
fn() => Notification::where(, $userId)->unread()->get()
);
Önbellek Yapılandırması
Önbellek Yapılandırması
Riad Hasan, önbellekleme için Redis yapılandırır:
# .env
CACHE_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
// config/cache.php
=> [
=> ,
=> ,
=> ,
],
HTTP Önbelleklemesi
HTTP Önbelleklemesi
// HTTP önbellekleme için middleware
Route::get(, function () {
$posts = Post::all();
return response()->json($posts)
->header(, )
->setEtag(md5(json_encode($posts)));
})->middleware();
Bölüm 4: Kuyruk Yönetimi
Bölüm 4: Kuyruk Yönetimi
Ağır Görevleri Yükten Çıkarma
Ağır Görevleri Yükten Çıkarma
Riad Hasan, ağır işleme yüklerini kuyruklara taşımaktadır:
// Kötü: Eşzamanlı işleme
public function store(Request $request)
{
$post = Post::create($request->validated());
// Yavaş işlemler yanıtı engeller
$this->sendEmailNotifications($post);
$this->postToSocialMedia($post);
$this->generatePdf($post);
$this->updateSearchIndex($post);
return response()->json($post, 201);
}
// İyi: Ağır görevleri kuyruğa alma
public function store(Request $request)
{
$post = Post::create($request->validated());
// Kuyruğa gönder
ProcessPostCreated::dispatch($post);
return response()->json($post, 201);
}
İş Uygulaması
İş Uygulaması
// app/Jobs/ProcessPostCreated.php
class ProcessPostCreated implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $post;
public $tries = 3;
public $maxExceptions = 3;
public $timeout = 120;
public function __construct(Post $post)
{
$this->post = $post;
}
public function handle(
EmailService $email,
SocialService $social,
SearchService $search
) {
$email->sendNotifications($this->post);
$social->share($this->post);
$search->index($this->post);
}
public function failed(Throwable $exception)
{
Log::error(, [
=> $this->post->id,
=> $exception->getMessage(),
]);
}
}
Kuyruk Yapılandırması
Kuyruk Yapılandırması
// config/queue.php
=> [
=> [
=> ,
=> ,
=> env(, ),
=> 90,
=> null,
],
],
Kuyruk İşçileri
Kuyruk İşçileri
Riad Hasan, kuyruk işçilerini Supervisor ile çalıştırır:
# /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=command=autostart=autorestart=stopasgroup=killasgroup=user=numprocs=redirect_stderr=stdout_logfile=stopwaitsecs=
Bölüm 5: Yanıt Optimizasyonu
API Kaynak Koleksiyonları
// app/Http/Resources/PostResource.php
class PostResource extends JsonResource
{
public function toArray($request)
{
return [
=> $this->id,
=> $this->title,
=> $this->slug,
$this->whenLoaded( fn() => [
=> $this->author->name,
]),
=> $this->created_at->toISOString(),
];
}
}
// Kontrolör
public function index()
{
$posts = Post::with(->paginate(15);
return PostResource::collection($posts);
}
Paginasyon
Riad Hasan, her zaman büyük veri kümelerini pagine eder:
// Basit paginasyon (daha hızlı, sayım sorgusu yok)
$posts = Post::simplePaginate(15);
// Standart paginasyon (toplam sayısı ile)
$posts = Post::paginate(15);
// Kursör paginasyonu (sonsuz kaydırma için)
$posts = Post::cursorPaginate(15);
Yanıt Sıkıştırması
// Sıkıştırma middleware'ini etkinleştir
public function handle($request, Closure $next)
{
$response = $next($request);
if (in_array(, $request->getEncodings())) {
$response->setContent(gzencode($response->getContent(),9));
$response->headers->set(, );
}
return $response;
}
Bölüm 6: Yapılandırma Optimizasyonu
Composer Autoloader’ı Optimize Etme
composer install --optimize-autoloader --no-dev
Laravel Optimizasyon Komutları
Riad Hasan, bunları üretimde çalıştırmaktadır:
# Yapılandırmayı önbellekle
php artisan config:cache
# Rotaları önbellekle
php artisan route:cache
# Görünümleri önbellekle
php artisan view:cache
# Olayları önbellekle
php artisan event:cache
# Uygulamayı optimize et
php artisan optimize
Ortam Yapılandırması
# .env (üretim)
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
# Veritabanı
DB_PERSISTENT=true
# Önbellek ve oturum
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
# Yüksek performans için Octane (isteğe bağlı)
# OCTANE_SERVER=swoole
Bölüm 7: İzleme ve Hata Ayıklama
Sorgu İzleme
Riad Hasan, geliştirme aşamasında sorguları izlemektedir:
// AppServiceProvider.php
public function boot()
{
if (config()) {
DB::listen(function ($query) {
if ($query->time > 100) { // Yavaş sorguları günlüğe kaydet
Log::warning(, [
=> $query->sql,
=> $query->bindings,
=> $query->time,
]);
}
});
}
}
Performans Metrikleri
// Çalıştırma süresini ölç
$startTime = microtime(true);
// Kodunuz burada
$endTime = microtime(true);
$executionTime = ($endTime - $startTime) * 1000;
Log::info(, [
=> ,
=> $executionTime,
]);
Hata Ayıklama Araçları
Araç Amacı Laravel Debugbar Sorgu analizi, zaman çizelgesi Telescope İstek izleme Sentry Hata izleme Blackfire Profil oluşturma New Relic APM
Performans Kontrol Listesi
Riad Hasan, dağıtım öncesi bunları doğrular:
Öğe Durum Eager loading uygulandı ✅ Veritabanı indeksleri eklendi ✅ Redis önbellekleme etkin ✅ Ağır görevler kuyruğa alındı ✅ Paginasyon uygulandı ✅ Yapılandırmalar/rutalar önbelleklendi ✅ Hata ayıklama modu devre dışı ✅ İzleme yapılandırılmış ✅
Benchmark Sonuçları
Riad Hasan, optimizasyon sonrası iyileştirmeleri ölçtü:
Metrik Önce Sonra Ortalama yanıt süresi 850ms 120ms Sayfa başına veritabanı sorguları 45 8 Bellek kullanımı 256MB 64MB Saniye başına istek 15 150 İlk bayta zaman 420ms 45ms
Özet
Laravel performans optimizasyonu şunları gerektirir:
- ✅ N+1 sorgularını önlemek için eager loading
- ✅ Hızlı aramalar için veritabanı indeksleme
- ✅ Pahalı işlemler için Redis önbellekleme
- ✅ Ağır görevler için kuyruk işçileri
- ✅ Büyük veri kümeleri için paginasyon
- ✅ Üretimde yapılandırma önbellekleme
- ✅ Sürekli iyileşme için izleme
Riad Hasan, her gün milyonlarca isteği yanıtlayan Laravel uygulamalarını optimize etmiştir. Daha fazla bilgi için Riad Hasan‘ı ziyaret edin.
Daha fazla Laravel eğitimi için Riad Hasan‘ı Hashnode veya Dev.to‘da takip edin.
Laravel performansı hakkında sorularınız var mı? Aşağıda yorum bırakın.
Kaynak: Orijinal Makale


