İçeriğe Atla
Mustafa Erbay
Teknoloji · 8 dk okuma · görüntülenme Read in English

Strangler Fig vs Big Bang: Modüler Mimarilere Geçişte 3 Neden

Monolitik sistemleri modüler mimariye taşırken Strangler Fig ve Big Bang yaklaşımlarının teknik risklerini, veritabanı stratejilerini ve pratik geçiş…

100%

Yazılım mimarisini kökten değiştirmeye karar verdiğinizde önünüzde iki temel yol belirir: Her şeyi yıkıp yeniden yapmak (Big Bang) veya eski yapıyı yavaş yavaş yeniye dönüştürmek (Strangler Fig). Strangler Fig vs Big Bang karşılaştırmasında, sahada edindiğim tecrübeyle söyleyebilirim ki, her şeyi tek seferde değiştirmeye çalışmak genellikle hüsranla sonuçlanır. Büyük sistemleri taşırken operasyonel sürekliliği korumak, veritabanı tutarlılığını sağlamak ve ekipleri yönetmek hayati önem taşır.

Bu yazıda, bir üretim ERP’si üzerinde çalışırken ve büyük ölçekli altyapıları taşırken edindiğim tecrübelere dayanarak, neden Strangler Fig desenini Big Bang yaklaşımına tercih etmeniz gerektiğini 3 temel teknik neden üzerinden anlatacağım. Lafı dolandırmadan, doğrudan kod, konfigürasyon ve gerçek dünya senaryolarıyla konuyu masaya yatıralım.

1. Strangler Fig vs Big Bang Karşılaştırmasında Risk Yönetimi ve Canlıda Dağıtım Güvenliği

Big Bang yaklaşımında, tüm sistemi tek bir günde (genellikle uykusuz geçecek bir hafta sonu gecesinde) yeni sürüme geçirmeyi hedeflersiniz. Bu durum, sistemin tüm bileşenlerinin aynı anda kusursuz çalışmasını gerektirir. Gerçek hayatta ise bu durum neredeyse imkansızdır. Strangler Fig deseni ise eski monolitik yapının etrafına yeni mikro servisleri veya modülleri aşamalı olarak örerek, eski sistemi zamanla “boğarak” yok etmeyi amaçlar.

Buradaki en kritik bileşen, trafiği yöneten yönlendirme (routing) katmanıdır. Nginx veya bir API Gateway kullanarak, monolitik uygulamanın belirli endpoint’lerini aşamalı olarak yeni servisimize yönlendirebiliriz. Örneğin, /api/v1/orders yolunu yeni yazdığımız modüler servise yönlendirirken, geri kalan tüm trafiği eski monolite bırakabiliriz.

Aşağıdaki Nginx konfigürasyonu, bu aşamalı geçişi production ortamında nasıl güvenle uygulayabileceğimizi gösteriyor:

# nginx.conf - Strangler Fig Trafik Yönlendirme Örneği
upstream old_monolith {
    server 10.0.1.50:8080; # Eski monolit sunucusu
}

upstream new_orders_service {
    server 10.0.1.60:3000; # Yeni modüler sipariş servisi
}

server {
    listen 80;
    server_name api.sirket.com;

    # Yeni servise taşınan endpoint
    location /api/v1/orders {
        proxy_pass http://new_orders_service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # Timeout değerlerini düşük tutarak yeni servisteki tıkanmaları monolite yansıtmayalım
        proxy_connect_timeout 2s;
        proxy_read_timeout 5s;
    }

    # Henüz taşınmamış, eski monolith üzerinde çalışan tüm diğer endpointler
    location / {
        proxy_pass http://old_monolith;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Bu yöntemin en büyük avantajı, yeni serviste bir bellek sızıntısı (memory leak) veya beklenmeyen bir hata (crash) meydana geldiğinde, sadece ilgili endpoint’in etkilenmesidir. Tüm ERP veya muhasebe sistemi çökmez. Üstelik acil bir durumda Nginx konfigürasyonunu eski haline getirip nginx -s reload yapmak sadece milisaniyeler sürer. Risk yönetimi açısından bu esneklik, Big Bang’in sunduğu “geri dönüşü çok zor olan dev veritabanı yedeğine geri dönme” kabusundan katbekat üstündür.

2. Veritabanı Paylaşımı ve Veri Tutarlılığı (Data Consistency) Çıkmazı

Modüler mimariye geçişte en büyük hata, sadece kod katmanını ayırıp veritabanını ortak bırakmaktır. “Shared Database” anti-pattern’i, mikro servislerin bağımsız dağıtılabilmesini engeller. Ancak Big Bang ile tüm veritabanı şemasını tek seferde değiştirmeye kalktığınızda, veri kaybı yaşama ihtimaliniz son derece yüksektir.

Strangler Fig deseninde veritabanı dönüşümü de aşamalı yapılır. Yeni servis kendi veritabanına (örneğin PostgreSQL 14+) sahip olur. Eski monolit ile yeni servis arasındaki veri senkronizasyonu için transactional outbox deseni veya PostgreSQL mantıksal replikasyonu (logical replication) kullanılabilir.

Daha önce ele aldığım postgresql-index-optimize yazısında veritabanı yükünü azaltmaktan bahsetmiştim. Burada ise amacımız çift yazma (dual-write) risklerini yönetmektir. Uygulama katmanında çift yazma yapmak yerine, veritabanı seviyesinde bir Outbox tablosu kullanmak veri tutarlılığını garanti altına alır.

Aşağıdaki Python ve FastAPI kod örneği, yeni sipariş servisine gelen veriyi işlerken, aynı transaction içinde bir outbox tablosuna olay (event) kaydetme yöntemini gösteriyor:

# database.py - Transactional Outbox Pattern Örneği
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from sqlalchemy import create_engine, text
import json

app = FastAPI()
DATABASE_URL = "postgresql://user:[email protected]:5432/orders_db"
engine = create_engine(DATABASE_URL)

def get_db():
    db = engine.connect()
    trans = db.begin()
    try:
        yield db
        trans.commit()
    except Exception as e:
        trans.rollback()
        raise e
    finally:
        db.close()

@app.post("/api/v1/orders")
def create_order(order_data: dict, db: Session = Depends(get_db)):
    # 1. Siparişi ana tabloya kaydet
    insert_order_query = text("""
        INSERT INTO orders (id, customer_id, total_amount, status) 
        VALUES (:id, :customer_id, :total_amount, :status)
    """)
    db.execute(insert_order_query, order_data)
    
    # 2. Eski monoliti besleyecek event'i Outbox tablosuna yaz (Aynı Transaction içinde!)
    outbox_event = {
        "event_type": "ORDER_CREATED",
        "payload": json.dumps(order_data)
    }
    insert_outbox_query = text("""
        INSERT INTO outbox (event_type, payload, processed) 
        VALUES (:event_type, :payload, false)
    """)
    db.execute(insert_outbox_query, outbox_event)
    
    return {"status": "success", "order_id": order_data["id"]}

Arka planda çalışan bağımsız bir systemd servisi (bir CDC - Change Data Capture aracı veya basit bir Python script’i), bu outbox tablosunu sürekli sorgulayarak işlenmemiş kayıtları eski monolitin veritabanına senkronize eder. Bu sayede, iki veritabanı arasında geçici tutarlılık (eventual consistency) sağlanır ve eski monolit çalışmaya devam ederken yeni servis de kendi izole veritabanıyla hayatına başlar.

3. Geliştirme Hızı ve Ekip Organizasyonu (Conway Yasası)

Conway Yasası der ki: “Organizasyonlar, tasarladıkları sistemlerin yapılarını kendi iletişim yapılarına uydururlar.” Monolitik bir yapıyı Big Bang ile değiştirmeye kalktığınızda, tüm yazılım ekibini aylarca sürecek, yeni özellik geliştirmeyi durduran bir kilitlenmeye mahkum edersiniz. “Feature freeze” ilan ettiğiniz an, iş birimleri üzerinize baskı kurmaya başlar ve sonunda aceleyle canlıya alınan, test edilmemiş, eski hataları barındıran yeni bir monolit elde edersiniz.

Strangler Fig modelinde ise ekipleri modüler sınırlara göre bölebilirsiniz. Örneğin, 5 kişilik bir ekibi sadece “Tedarik Zinciri ve Stok Modülü” üzerine yoğunlaştırabilirsiniz. Bu ekip, eski monolitin kod tabanına dokunmadan, kendi CI/CD süreçleriyle tamamen bağımsız çalışabilir.

Metrik Big Bang Yaklaşımı Strangler Fig Deseni
Geliştirme Kesintisi (Feature Freeze) 6 - 18 Ay (Yüksek Risk) Sıfır Kesinti (Sürekli Teslimat)
Hata Etki Alanı (Blast Radius) Tüm Sistem Sadece İlgili Modül / Servis
Dağıtım Sıklığı (Deploy Frequency) Ayda 1 veya Yılda 1 Günde birden fazla (Aşama aşama)
Geri Alım (Rollback) Maliyeti Çok Yüksek (Veri kaybı riski var) Çok Düşük (Sadece routing değişimi)
İlk Değer Üretim Süresi (Time to Value) Proje sonu (Aylar sonra) İlk hafta (İlk endpoint canlıda)

Bir üretim ERP’sini modüler hale getirirken bu stratejiyi bizzat uyguladık. Sevkiyat modülünü ayırmak için ekibe odaklı ve sınırlı bir hedef verdik. Tüm sistemi durdurmak yerine, sadece sevkiyat fişlerinin kesildiği ekranı ve arka plan servislerini ayırdık. Başarısız olsaydık bile kaybedeceğimiz tek şey o tek modülün emeği olacaktı, tüm şirketin operasyonu değil.

4. Performans ve Kaynak Tüketimi (CPU/Memory ve Autoscaling)

Monolitik uygulamaların en büyük dertlerinden biri dikey ölçekleme (vertical scaling) zorunluluğudur. Sistemdeki tek bir ağır raporlama sorgusu yüzünden tüm uygulamanın belleği (RAM) tükenebilir ve sistem OOM-killed (Out Of Memory) olabilir. Strangler Fig ile ayırdığımız modüller, kendi kaynak limitleriyle (cgroups) çalışır.

Eski monoliti 16 GB RAM’lik bare-metal sunucularda tutarken, yeni yazdığımız modülleri Docker Compose veya hafif container yapılarında, kaynak limitlerini net belirleyerek çalıştırabiliriz. Böylece tek bir modülün çökmesi, diğer kritik servislerin çalışmasını engellemez.

Aşağıdaki systemd unit dosyası, yeni modüler sipariş servisimizin kaynaklarını işletim sistemi seviyesinde nasıl limitleyebileceğimizi gösteriyor:

# /etc/systemd/system/orders-service.service
[Unit]
Description=Yeni Moduler Siparis Servisi
After=network.target postgresql.service

[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/orders-service
ExecStart=/var/www/orders-service/venv/bin/uvicorn main:app --host 127.0.0.1 --port 3000
Restart=always
RestartSec=3

# Kaynak Limitleri (cgroups) - Monolitin kaynaklarini sömürmesini engellemek icin
MemoryHigh=256M
MemoryMax=512M
CPUQuota=50%

# Loglama Ayarlari
StandardOutput=journal
StandardError=journal
SyslogIdentifier=orders-service

[Install]
WantedBy=multi-user.target

Bu systemd konfigürasyonu sayesinde, sipariş servisi ne yaparsa yapsın işletim sisteminin %50 CPU’sundan fazlasını tüketemez ve 512 MB RAM sınırını aşarsa sistem genelini çökertmeden sadece kendi kendini yeniden başlatır. Monolitik sistemlerde bu seviyede bir izolasyon sağlamak neredeyse imkansızdır.

5. Rollback Stratejileri ve Hata Yönetimi (Fault Tolerance)

Bir mimari geçiş planlarken en çok mesai harcamanız gereken yer, her şeyin ters gittiği andır. Big Bang geçişlerinde “her şeyi geri alma” senaryosu tam bir felakettir. Canlıya geçtikten saatler sonra fark edilen sessiz bir veri bozulması (silent data corruption), sizi geçmişe dönük verileri manuel düzeltmek zorunda bırakır.

Strangler Fig deseninde ise hata yönetimi dinamiktir. Nginx üzerinde uygulayacağımız ufak bir split_clients testi (canary deployment) ile yeni yazdığımız modüle gelen trafiğin sadece %10’unu yönlendirip hataları gözlemleyebiliriz.

# nginx.conf - Canary Deployment ve Yüzdesel Trafik Dağıtımı
split_clients "${remote_addr}AAA" $destination_upstream {
    10%     new_orders_service;
    *       old_monolith;
}

server {
    listen 80;
    server_name api.sirket.com;

    location /api/v1/orders {
        proxy_pass http://$destination_upstream;
        proxy_set_header Host $host;
        
        # Hata durumunda otomatik olarak eski sisteme yönlendir (Fallback)
        proxy_next_upstream error timeout http_502 http_503;
        proxy_next_upstream_timeout 1s;
        proxy_next_upstream_tries 2;
    }
}

Bu konfigürasyonla, eğer yeni sipariş servisi 502 veya 503 hatası verirse ya da 1 saniye içinde yanıt vermezse, Nginx isteği kullanıcılara hissettirmeden otomatik olarak eski monolite paslar. İşte bu, gerçek anlamda sıfır kesintili (zero-downtime) ve güvenli bir mimari geçişin formülüdür.

6. Strangler Fig Uygulama Rehberi: Adım Adım Modüler Dönüşüm

Teoriyi pratiğe dökmek için izlemeniz gereken yol haritasını netleştirelim. Dönüşüm sürecini planlarken acele etmeyin ve adımları sırasıyla uygulayın.

  1. Yönlendirme Katmanını Kurun: Mevcut monolitin önüne Nginx, HAProxy veya benzeri bir ters proxy (reverse proxy) yerleştirin. Tüm trafik önce buraya gelmeli.
  2. En Kolay ve Bağımsız Modülü Seçin: İlk olarak en karmaşık modülü (örneğin muhasebe veya stok) değil, bağımlılığı en az olan modülü (örneğin bildirim veya basit bir raporlama servisi) seçin.
  3. Veritabanı Sınırlarını Belirleyin: Seçilen modülün tablolarını belirleyin. Bu tablolara sadece yeni servisin doğrudan erişmesini sağlayın. Monolit artık bu tablolara doğrudan sorgu atmamalı, gerekirse API üzerinden konuşmalı.
  4. Outbox ve CDC Mekanizmasını Kurun: Veri tutarlılığını sağlamak için yukarıda bahsettiğimiz transactional outbox yapısını kurgulayın.
  5. Canary Dağıtımla Trafiği Aktarın: Trafiği önce %5, sonra %25, %50 ve en nihayetinde %100 olacak şekilde yeni servise yönlendirin.
  6. Eski Kodları Temizleyin: Trafik tamamen yeni servise kaydıktan sonra, eski monolit içindeki ilgili kod bloklarını silin ve veritabanı tablolarını drop edin.

Daha önce kaleme aldığım zero-trust-network-mimari yazısında sistemlerin birbiriyle güvenli konuşmasından bahsetmiştim. Yeni oluşturduğunuz bu modüllerin kendi aralarındaki iletişimini de mutlaka şifreli (mTLS) veya güvenli API anahtarlarıyla koruma altına alın.

Sonuç olarak; Strangler Fig vs Big Bang mücadelesinde kazanan her zaman pragmatik, kontrollü ve aşamalı ilerleyen Strangler Fig yaklaşımıdır. Büyük sistemleri dönüştürmek bir sprint değil, maratondur. Adım adım ilerleyin, her adımda sistemin metriklerini izleyin ve hata yaptığınızda hızlıca geri dönebilecek esnekliği elinizde tutun.

Bir sonraki yazıda, mikro servisler arasında event-driven iletişim kurarken karşılaşılan “idempotency” (aynı isteğin tekrar etmesi) sorununu ve çözüm yollarını inceleyeceğiz.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

Sıkça Sorulanlar

Bu makale ile ilgili okurların sorduğu yaygın sorular.

Strangler Fig yaklaşımını Big Bang yerine neden tercih etmeliyim?
Ben, 20 yıllık tecrübeme dayanarak, Big Bang yaklaşımının genellikle hüsranla sonuçlandığını gördüm. Strangler Fig deseni ise eski yapının etrafına yeni mikro servisleri veya modülleri aşamalı olarak örerek, eski sistemi zamanla 'boğarak' yok etmeyi amaçlar. Bu yaklaşım, teknik riskleri azaltır ve operasyonel sürekliliği korur.
Strangler Fig desenini uygularken hangi araçları kullanmalıyım?
Ben, Nginx veya bir API Gateway kullanarak, monolitik uygulamanın belirli endpoint'lerini aşamalı olarak yeni servise yönlendirmeyi öneririm. Bu, trafiği yöneten yönlendirme katmanını oluşturmak için idealdir. Ayrıca, gerçek dünya senaryolarını test etmek için konfigürasyon ve kod örneklerini kullanabilirsiniz.
Strangler Fig desenini uygularken karşılaşılabilecek hatalara karşı nasıl önlem almalıyım?
Ben, karşılaşılabilecek hatalara karşı önlem almak için, sistemdeki değişikliklerin aşamalı olarak uygulanması ve her adımda test edilmesi gerektiğini düşünüyorum. Ayrıca, geri dönüşü kolaylaştırmak için, eski sistemin bir kopyasını tutmak ve आवश olduğunda geri dönebilmek önemlidir.
Strangler Fig desenini uygularken kaç sefer denemek gerekir?
Ben, Strangler Fig desenini uygularken, sabır ve titizlik gerektiğini düşünüyorum. Her adımda test etmek ve gerekli ayarlamaları yapmak önemlidir. Deneme sayısı, sistemlerin komplexitesine ve ekiplerin tecrübesine bağlı olarak değişebilir. Ancak, genel olarak, birkaç deneme之后, sistemlerin stabilize edildiğini ve çalıştığını görebilirsiniz.
ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Yorumlar

Sunucu Taraflı AI Moderasyon

Yorumlar sunucuda yapay zeka ile denetlenir ve kalıcı olarak saklanır.

?
0/2000

Sunucu taraflı AI denetim

✉️ Ücretsiz · Spam yok · İstediğin an çık

Yeni yazılardan haberdar olun

Yeni içerikler ve teknik notlar e-postanıza gelsin.

  • 📌
    Haftanın en iyisi Sadece okumaya değer tek yazı
  • 🔧
    Alet çantası Bu hafta kullandığım araçlar
  • 🧠
    Perde arkası Blog'a girmeyen notlar

Spam yapmıyoruz. İstediğiniz zaman ayrılabilirsiniz. · Sadece Umami (self-hosted, Google yok) ile takip.

Okuma İstatistikleriniz

0

Yazı Okundu

0dk

Okuma Süresi

0

Gün Serisi

-

Favori Kategori

İlgili Yazılar