Django Performans Rehberi: Ölçeklenebilir Uygulama Geliştirme
Yazar: Burak Balkı | Kategori: Performance | Okuma Süresi: 9 dk
Django uygulamalarında veritabanı, caching ve asenkron işlem optimizasyonlarını kapsayan, ölçeklenebilir mimariler için hazırlanan kapsamlı teknik performans...
## Django Performans Yönetimine Giriş
Django, 'pilleri dahil' (batteries-included) felsefesiyle hızlı geliştirme imkanı sunan güçlü bir framework olsa da, ölçeklenebilir uygulamalar için **performans optimizasyonu** kritik bir gerekliliktir. Django performans yönetimi, sadece kod yazımıyla sınırlı değildir; veritabanı etkileşimi, bellek yönetimi, sunucu yapılandırması ve asenkron işlem mimarisini kapsayan bütünsel bir süreçtir.
Bu rehberde, bir Django uygulamasının darboğazlarını nasıl tespit edeceğinizi ve kurumsal düzeyde bir hız optimizasyonunu nasıl gerçekleştireceğinizi adım adım inceleyeceğiz.
## Veritabanı Optimizasyonu: QuerySet ve ORM Verimliliği
Django uygulamalarındaki en yaygın performans sorunu veritabanı sorgularıdır. **N+1 sorgu problemi**, uygulamanın gereksiz yere yüzlerce küçük sorgu yapmasına neden olarak yanıt sürelerini artırır.
### select_related ve prefetch_related Kullanımı
`select_related`, yabancı anahtar (ForeignKey) ve bire-bir (OneToOne) ilişkilerde kullanılır ve SQL düzeyinde `JOIN` işlemi gerçekleştirir. `prefetch_related` ise çoktan-çoğa (ManyToMany) ve ters yabancı anahtar ilişkileri için Python tarafında birleştirme yapar.
```python
# Kötü Uygulama (N+1 Problemi)
books = Book.objects.all()
for book in books:
print(book.author.name) # Her döngüde yeni bir sorgu yapılır
# İyi Uygulama (Optimizasyon)
books = Book.objects.select_related('author').all()
for book in books:
print(book.author.name) # Tek bir JOIN sorgusu ile veriler gelir
```
### Veritabanı İndeksleme
Sık sorgulanan alanlarda **Database Index** kullanmak, arama işlemlerini O(n) karmaşıklığından O(log n) seviyesine indirir.
```python
class Customer(models.Model):
email = models.EmailField(db_index=True) # İndeks eklendi
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
indexes = [
models.Index(fields=['email', 'created_at']),
]
```
## Caching Stratejileri: Redis ve Memcached Kullanımı
Önbellekleme (Caching), aynı verinin tekrar tekrar hesaplanmasını veya veritabanından çekilmesini engelleyerek sistem yükünü minimize eder. Django, farklı seviyelerde önbellekleme desteği sunar.
| Seviye | Açıklama | Kullanım Durumu |
| :--- | :--- | :--- |
| Per-View Cache | Tüm sayfanın önbelleğe alınması | Statik içerikli sayfalar |
| Template Fragment Cache | Şablonun belirli bölümlerinin saklanması | Karmaşık yan menüler, footer |
| Low-Level Cache | Belirli veri veya objelerin saklanması | API yanıtları, hesaplanmış veriler |
### Redis ile Önbellek Yapılandırması
```python
# settings.py
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
```
### View Düzeyinde Önbellekleme
```python
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) # 15 dakika önbelleğe al
def my_view(request):
# Ağır işlemler buraya gelir
return render(request, 'heavy_template.html')
```
## Middleware ve Request/Response Döngüsünü Hızlandırma
Middleware katmanları her istekte çalışır. Gereksiz middleware kullanımı, her HTTP isteğine ek milisaniyeler ekler. Kullanılmayan veya verimsiz yazılmış middleware'leri temizlemek performansı doğrudan etkiler.
> **Önemli Not:** `GZipMiddleware` kullanarak yanıt boyutlarını küçültebilirsiniz. Ancak bunu güvenlik riskleri (BREACH saldırısı) nedeniyle dikkatli yapılandırmalısınız.
```python
# settings.py
MIDDLEWARE = [
'django.middleware.gzip.GZipMiddleware', # Yanıtları sıkıştırır
'django.middleware.common.CommonMiddleware',
# ... diğer middleware'ler
]
```
## Asenkron İşlemler: Celery ve Redis Entegrasyonu
E-posta gönderimi, dosya işleme veya dış API çağrıları gibi zaman alan işlemler, ana istek döngüsünü (request cycle) bloke etmemelidir. Bu tür işlemler için **Celery** gibi bir task queue (görev kuyruğu) kullanılmalıdır.
### Celery Görevi Tanımlama
```python
# tasks.py
from celery import shared_task
@shared_task
def send_welcome_email(user_id):
user = User.objects.get(pk=user_id)
# E-posta gönderme mantığı
return f"{user.email} adresine e-posta gönderildi."
```
## Statik Dosya ve Medya Yönetimi: CDN Kullanımı
Django, statik dosyaları (CSS, JS, Görseller) sunmak için tasarlanmamıştır. Üretim ortamında bu dosyalar **Nginx** veya **Amazon S3** gibi servisler üzerinden, tercihen bir **CDN (Content Delivery Network)** aracılığıyla sunulmalıdır.
- **WhiteNoise:** Statik dosyaları doğrudan Python üzerinden sunmak için optimize edilmiş bir kütüphanedir.
- **ManifestStaticFilesStorage:** Dosya isimlerine hash ekleyerek tarayıcı önbelleklemesini (cache busting) yönetir.
```python
# settings.py
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
```
## Django Templates ve Frontend Optimizasyonu
Şablon motoru tarafında gereksiz mantık yürütmekten kaçınılmalıdır. `with` etiketiyle tekrarlanan hesaplamalar saklanabilir.
```html
{% with total=business.employees.count %}
Toplam Çalışan: {{ total }}
Kapasite Durumu: {{ total|add:"10" }}
{% endwith %} ``` ## Sunucu ve Deployment Yapılandırması: Gunicorn ve Nginx Django uygulamaları genellikle bir WSGI sunucusu (Gunicorn) ve bir ters vekil sunucu (Nginx) arkasında çalıştırılır. Worker sayısı, sunucu çekirdek sayısına göre optimize edilmelidir. ```bash # Gunicorn çalışma komutu örneği gunicorn --workers 3 --bind 0.0.0.0:8000 myproject.wsgi:application ``` Genel formül: `(2 x CPU Çekirdek Sayısı) + 1` şeklindedir. ## İzleme ve Profilleme Araçları: Django Debug Toolbar Geliştirme aşamasında darboğazları görmek için en etkili araç **Django Debug Toolbar**'dır. SQL sorgularını, cache isabet oranlarını ve sinyal sürelerini anlık olarak gösterir. ```python # settings.py (Sadece development ortamında) INSTALLED_APPS += ['debug_toolbar'] MIDDLEWARE = ['debug_toolbar.middleware.DebugToolbarMiddleware'] + MIDDLEWARE INTERNAL_IPS = ['127.0.0.1'] ``` ## Toplu İşlemler (Bulk Operations) Veritabanına tek tek kayıt eklemek yerine toplu işlemler kullanmak, veritabanı bağlantı yükünü azaltır. ```python # Kötü: 100 ayrı INSERT sorgusu for item in data_list: Entry.objects.create(name=item) # İyi: Tek bir INSERT sorgusu Entry.objects.bulk_create([ Entry(name=item) for item in data_list ]) ``` ## Sık Yapılan Hatalar ve Çözümleri 1. **Gereksiz QuerySet Değerlendirmesi:** `if queryset:` yerine `if queryset.exists():` kullanın. Tüm objeleri belleğe yüklemeden kontrol sağlar. 2. **Büyük Veri Setlerinde len() Kullanımı:** `len(queryset)` yerine `queryset.count()` kullanın. SQL düzeyinde `COUNT(*)` çalıştırır. 3. **İhtiyaç Duyulmayan Alanları Çekmek:** Sadece belirli alanlar lazımsa `only()` veya `defer()` kullanın. ```python # Sadece isim ve soyisim alanlarını çek users = User.objects.only('first_name', 'last_name').all() ``` ## Sık Sorulan Sorular (FAQ) **1. Django performansını artırmak için ilk nereden başlamalıyım?** Öncelikle veritabanı sorgularınızı optimize etmelisiniz. `select_related` ve `prefetch_related` kullanımı genellikle %50'den fazla performans artışı sağlar. **2. Redis mi yoksa Memcached mi kullanmalıyım?** Redis, veri yapıları desteği ve kalıcı depolama özellikleri nedeniyle modern Django projelerinde daha çok tercih edilmektedir. **3. Django asenkron (ASGI) desteği performansı nasıl etkiler?** I/O yoğunluklu işlemlerde (web sockets, uzun süreli API çağrıları) asenkron yapı büyük avantaj sağlar ancak CPU yoğunluklu işlerde standart WSGI yeterlidir. **4. Database pooling nedir?** Veritabanı bağlantılarının her istekte açılıp kapanması yerine açık tutulup tekrar kullanılmasıdır. `django-db-geventpool` veya `PgBouncer` gibi araçlarla yapılabilir. **5. Django'da sorgu sayısını nasıl takip edebilirim?** `django.db.connection.queries` listesini kontrol edebilir veya `Django Debug Toolbar` kullanabilirsiniz. ## Özet ve Sonuç Django performans optimizasyonu, veritabanı seviyesinden başlar, uygulama mantığıyla devam eder ve sunucu yapılandırmasıyla tamamlanır. **N+1 sorgu problemi**ni çözmek, **caching** stratejilerini doğru uygulamak ve ağır işleri **Celery** ile arka plana atmak, uygulamanızın binlerce eşzamanlı kullanıcıyı sorunsuz karşılamasını sağlar. Performans sürekli bir izleme sürecidir; düzenli olarak profilleme araçlarıyla sisteminizi denetlemelisiniz.