EN Versiyonu
Echo Echo Support / SRE • • 3.177 kelime • 16 dk okuma

Sanal Bekleme Odası Mimarisi: Bilet Siteleri Nasıl Çökmez?

Milyonlarca istek altında veritabanını koruyan sanal bekleme odası mimarisi: Edge HMAC biletleri, Token Bucket hız sınırı ve atomik koltuk kilitleme.

#high-traffic #rate-limiting #distributed-systems #sre
Sanal Bekleme Odası Mimarisi: Bilet Siteleri Nasıl Çökmez?

Kısa Özet (TL;DR — Doğrudan Yanıt): Sanal bekleme odası (Virtual Waiting Room), ani trafik patlamalarında milyonlarca eşzamanlı kullanıcıyı CDN uç (edge) noktalarında karşılayıp kaynak sunucuya (origin) kontrollü hızda aktaran durumsuz kabul kontrol mimarisidir. Veritabanı bağlantı havuzu doygunluğunu, kilitlenme (deadlock) fırtınalarını ve CPU çöküşünü engellediği için yüksek trafikli biletleme sistemlerinde hayati önem taşır. Doğru kurgulanan HMAC-SHA256 tabanlı uç kuyruk ve PostgreSQL SKIP LOCKED kombinasyonu, 10 milyon RPS seviyesindeki yıkıcı trafiğin %99,8'ini uç katmanda emerek uç gecikmesini 5 ms altında tutar ve veritabanı IOPS yükünü sabit 2.000 TPS sınırına kilitler. Pahalı dağıtık kilit servisleri yerine standart kriptografi ve yerleşik veritabanı atomikliği en yüksek hayatta kalma oranını sağlar.

Thundering Herd Anatomisi: Saat 10:00:00 UTC Felaketi

Saat 10:00:00 UTC. Popüler stadyum konseri satışa çıkar. On milyon hayran ve yüz binlerce bilet botu aynı saniyede yenile tuşuna basar. Hazırlıksız altyapı otuz saniye içinde erir. Mesele bant genişliği değil; çekirdek kuyrukları, kriptografik el sıkışma maliyeti ve veritabanı kilit çekişmesidir.

Çekirdek (Kernel) Soket Kuyrukları ve TLS El Sıkışma Çöküşü

İlk darbe ağ kartı (NIC) ve işletim sistemi çekirdeğine iner. Milyonlarca TCP SYN paketi yük dengeleyiciye çarpar. Linux çekirdeğinde yarı açık bağlantıları tutan net.ipv4.tcp_max_syn_backlog ve kabul bekleyen tam bağlantıları tutan net.core.somaxconn kuyrukları milisaniyeler içinde dolar. Çekirdek yeni paketleri sessizce düşürür. İstemci işletim sistemleri düşen paketleri kayıp sayıp üstel geri çekilme (exponential backoff) olmadan yeniden gönderir. Paket fırtınası kendi kendini besler.

TCP el sıkışmasını geçen bağlantılar TLS 1.3 duvarına toslar. ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) anahtar değişimi asimetrik kriptografi çalıştırır. Her yeni oturum CPU çekirdeklerinde yoğun modüler aritmetik işlem tüketir. Donanım hızlandırma olsa dahi saniyede yüz binlerce yeni TLS el sıkışması kullanıcı alanı (user-space) iş parçacıklarını aç bırakır. Çekirdek sürekli bağlam değiştirir (context switch), L1 ve L2 CPU önbellekleri kirlenir, yararlı iş üretimi sıfıra yaklaşır. Canlı trafik simülasyonlarında çekirdek kuyruklarının nasıl dolduğunu görmek için AI Playground üzerindeki yük senaryoları incelenebilir.

Bağlantı Havuzu Doygunluğu ve Veritabanı Kilitlenme (Deadlock) Zinciri

TLS katmanını aşan istekler uygulama sunucularına ulaşır. Uygulama katmanı PgBouncer veya yerel bağlantı havuzundan veritabanı soketi ister. Havuz sınırı dolduğunda bekleyen goroutine veya iş parçacığı sayısı patlar, bellek tüketimi tavan yapar. Yanlışlıkla PostgreSQL max_connections değeri yükseltilirse felaket büyür; her PostgreSQL arka plan süreci yaklaşık 10 MB RAM harcar ve süreçler arası paylaşımlı bellek (shared buffers) kilitleri üzerinde kavga başlatır.

Asıl ölüm vuruşu koltuk tablosunda yaşanır. Elli bin eşzamanlı sorgu aynı popüler ön sıra koltuklarını okur ve güncellemeye çalışır. PostgreSQL içindeki LockManager hafif kilit (LWLock) tablosu darboğaza girer. Satır kilitleri (RowExclusiveLock) kuyruğa dizilir. İşlemler zaman aşımına uğrayıp geri alındıkça (rollback) tabloda ölü satır sürümleri (dead tuples) birikir. autovacuum ölü satırları temizlemeye yetişemez, B-tree indeks taramaları yavaşlar, disk okuma/yazma kuyruğu kilitlenir. Yük dengeleyici arka uçtan yanıt alamayınca HTTP 502 ve 504 hataları döner. Hata ekranını gören milyonlarca kullanıcı tekrar yenile tuşuna basar. Sistem tamamen komaya girer.

Edge Kabul Kontrolü (Admission Control) ve Durumsuz Kuyruk Mimarisi

Kaynak sunucuyu kurtarmanın tek yolu düşmanı kaleye sokmamaktır. Trafik doğduğu coğrafi noktada, yani Anycast CDN uç (edge) sunucularında durdurulmalıdır. Uç katmanda merkezi veritabanı veya merkezi Redis kümesi sorgulamak intihardır; kıtalararası ağ gecikmesi (RTT) ve tekil anahtar (hotkey) doygunluğu uç katmanı da çökertir. Çözüm sıfır durumlu (stateless) kriptografik bilet mimarisidir.

Durumsuz (Stateless) HMAC-SHA256 Bilet Mimarisi

İstemci uç sunucuya ilk ulaştığında bellek içi atomik sayaçtan sıra zaman dilimi (slot_ts) alır. Uç çalışanı (Edge Worker) veritabanına yazmadan istemciye imzalı HTTP çerezi verir. Çerez yükü kullanıcı tekil kimliği, tahsis edilen giriş zaman dilimi, son geçerlilik süresi ve tek kullanımlık rastgele sayıdan (uid|slot_ts|exp|nonce) oluşur. Yükün sonuna gizli anahtarla hesaplanan HMAC-SHA256 özeti eklenir.

Sonraki her istekte uç sunucu yalnızca SHA-256 hesaplaması yapar. Disk okuması yok, ağ çağrısı yok, kilit beklemesi yok. Modern CPU üzerinde tek HMAC doğrulaması mikrosaniyeler sürer. İstemcinin slot_ts zamanı henüz gelmemişse uç sunucu statik bekleme odası HTML sayfasını önbellekten döner ve isteği orada sonlandırır. Kaynak sunucu bu isteğin varlığından haberdar bile olmaz.

Güvenlik Uyarısı: Durumsuz bilet imzalamada kullanılan gizli anahtar en az 256 bit kriptografik entropiye sahip olmalı ve kaynak kod deposunda kesinlikle saklanmamalıdır. İmza doğrulaması yapılırken standart metin karşılaştırma operatörleri (==) kullanılırsa zamanlama yan kanal saldırıları (timing side-channel attacks) ile saldırganlar bayt bayt doğru imzayı tahmin edebilir; bu nedenle her zaman sabit zamanlı (constant-time) karşılaştırma fonksiyonları zorunlu tutulmalıdır. Ayrıca anahtar sızıntısı riskine karşı uç düğümlerde aktif ve eski anahtarı aynı anda tanıyan anahtar kimliği (kid) tabanlı kesintisiz rotasyon mekanizması bulundurulmalıdır.

Adalet Mekanizmaları: FIFO Kuyruk ve Piyango (Lottery) Dağıtımı

Saf ilk gelen ilk girer (FIFO) kuralı kağıt üzerinde adil görünür, pratikte bilet karaborsacılarını ödüllendirir. Veri merkezinden kiralanan sanal sunucu 1 milisaniye gecikmeyle uç noktaya vururken mobil ağdaki gerçek kullanıcı 80 milisaniye geride kalır. Saat tam 10:00:00.001 olduğunda ilk yüz bin sırayı botlar kapatır.

Gerçek adalet iki aşamalı hibrit kuyrukla sağlanır. Satıştan otuz dakika önce (09:30 UTC) "Ön Bekleme Odası" açılır. 09:30 ile 10:00 arasında gelen tüm istemcilere geçici katılım jetonu verilir; erken gelmenin hiçbir avantajı yoktur. Saat tam 10:00:00 UTC vurduğunda sistem ön odadaki havuzu kriptografik özet fonksiyonuyla (SHA256(secret + client_id)) rastgele karıştırır ve her istemciye deterministik sıra numarası atar. Saat 10:00:00 sonrasında gelen geç kullanıcılar ise piyango havuzunun arkasına standart FIFO sırasıyla eklenir. Karaborsa botlarının düşük ağ gecikmesi avantajı bu hamleyle tamamen sıfırlanır.

Trafik Kontrol Stratejileri Karşılaştırması ve Performans Metrikleri

Yüksek trafik altında her hız sınırlama (rate limiting) tekniği aynı sonucu vermez. Yanlış strateji seçimi kaynak sunucuyu korumak yerine ağ katmanında ikincil yıkım yaratır.

Hız Sınırlama (Rate Limiting) ve Bekleme Odası Yaklaşımları

Sert HTTP 429 (Too Many Requests) döndürmek API servisleri için uygundur, son kullanıcı biletleme siteleri için felakettir. Tarayıcıda hata sayfası gören insan panikler ve saniyede üç kez yenile tuşuna basar. Trafik azalmak yerine dörde katlanır; buna yeniden deneme çarpanı (retry amplification) denir.

Uygulama katmanı ters vekil (L7 Reverse Proxy) üzerinde Leaky Bucket (Sızdıran Kova) kurmak ikinci yaygın hatadır. İstekler vekil sunucu belleğinde kuyruğa alınır, açık TCP soketleri bekletilir. Milyonlarca açık soket dosya tanımlayıcı (file descriptor) sınırını aşar, çekirdek tcp_mem bellek baskısı moduna girer ve Linux OOMKiller devreye girip vekil sunucuyu öldürür.

Merkezi Redis tabanlı bekleme odası (ZADD / ZRANK) orta ölçekte çalışır. Ancak 10 milyon kullanıcı her 5 saniyede sıra sorguladığında saniyede 2 milyon Redis komutu oluşur. Tek parçalı sıralı küme (Sorted Set) tek CPU çekirdeğini %100 doyurur ve kuyruk servisi bizzat darboğaz olur. Farklı kuyruk algoritmalarının darboğaz davranışlarını test etmek için İnteraktif Simülasyon Araçları sayfasındaki modeller kullanılabilir.

Üretim Ortamı Mimari Karşılaştırma Tablosu

Aşağıdaki tablo, 5 milyon eşzamanlı kullanıcı ve 2.000 TPS veritabanı kapasitesi varsayımı altında dört farklı trafik kontrol mimarisinin üretim metriklerini karşılaştırır:

Mimari / Yöntem Gecikme (Latency) Bellek / CPU Avantaj Üretim Riski
Sert HTTP 429 (Origin Rate Limit) p99: 850 ms+ (TLS yığılması) Yüksek Origin CPU (%95+ kripto yükü) Sıfır durum, kolay kurulum Yeniden deneme fırtınası trafiği 4 kat büyütür, müşteri kaybı yaratır
L7 Proxy Leaky Bucket (Bellek İçi) p99: 12.000 ms+ (Soket bekletme) Aşırı RAM (64 GB+ açık soket tamponu) İstekleri düşürmeden yumuşatır Dosya tanımlayıcı tükenmesi ve OOMKiller kaynaklı tam vekil çöküşü
Merkezi Redis Kuyruğu (ZSET) p99: 140 ms (Ağ + tek iş parçacığı) Orta RAM, Tek Redis Çekirdeği %100 Kesin küresel sıra numarası verir Sıcak anahtar (hotkey) doygunluğu ile kuyruk veritabanının kilitlenmesi
Edge Stateless HMAC + Token Bucket p99: 3.2 ms (Edge), 38 ms (Origin) Düşük RAM, Dağıtık CDN PoP CPU %99,8 origin yük düşüşü, sonsuz ölçek CDN düğümleri arası saat kayması (clock skew) ve yaklaşık sıra tahmini

Tablo net gerçeği gösterir: kesin küresel sıra numarası takıntısı sistemi öldürür. Yaklaşık sıra tahmini ve zaman dilimi bazlı durumsuz uç biletler, kaynak veritabanı IOPS tüketimini %99,8 azaltarak p99 gecikmesini 40 milisaniye altında sabitler.

Üretim Ortamı Uygulaması: Sıfır Bağımlılıklı Kod ve Atomik Kilitler

Karmaşık dış kütüphaneler, Kafka kuyrukları ve dağıtık kilit yöneticileri kriz anında ilk bozulan parçalardır. Standart kütüphane kriptografisi ve yerleşik ilişkisel veritabanı kilitleri milyonlarca isteği tek başına göğüsler.

Uçtan Uca Sanal Bekleme Odası Akış Diyagramı

[ 10 Milyon İstemci: Gerçek Tarayıcılar ve Bilet Botları ]
                            |
                            | BGP Anycast / TLS 1.3 Sonlandırma
                            v
+-------------------------------------------------------------------+
| CDN UÇ KATMANI (Stateless Edge Worker - 300+ Küresel PoP)         |
|  1. TLS JA4 Parmak İzi ve Hafif PoW Kontrolü (Bot Filtreleme)     |
|  2. Çerez Yoksa: HMAC-SHA256 İmzalı Zaman Dilimi Bileti Üret      |
|  3. Zaman Gelmediyse: Önbellekten Statik Bekleme HTML Dön (HTTP 200)|
|  4. Zaman Geldiyse: Sabit Zamanlı İmza Doğrula ve Origin'e İlet   |
+-------------------------------------------------------------------+
                            |
                            | Yalnızca Geçerli Biletler (Maks 2.000 RPS)
                            v
+-------------------------------------------------------------------+
| KAYNAK UYGULAMA KATMANI (Go Standart HTTP Sunucusu)               |
|  1. İkincil HMAC Doğrulaması (Doğrudan IP Sızıntısı Koruması)     |
|  2. Yerel Token Bucket Hız Sınırı Kontrolü                        |
+-------------------------------------------------------------------+
                            |
                            | PgBouncer İşlem Havuzu (Sabit 100 Bağlantı)
                            v
+-------------------------------------------------------------------+
| VERİTABANI KATMANI (PostgreSQL Birincil Düğüm)                    |
|  1. UNIQUE(used_nonce) Kısıtı ile Tekrar Oynatma (Replay) Engeli  |
|  2. FOR UPDATE SKIP LOCKED ile Sıfır Beklemeli Atomik Koltuk Seçimi|
+-------------------------------------------------------------------+

Bir isteğin sistem içerisindeki yaşam döngüsü şu sıralı adımlarla gerçekleşir:

  1. İstemci satış sayfasına istek gönderdiğinde en yakın CDN uç düğümü TLS bağlantısını sonlandırır ve isteğin bot parmak izini denetler.
  2. İstek üzerinde geçerli bir bekleme odası çerezi bulunmuyorsa uç düğüm istemciye ileri tarihli bir zaman dilimi (slot_ts) atar, veriyi HMAC-SHA256 ile imzalar ve statik bekleme ekranını döndürür.
  3. Tarayıcı, rastgele gecikme (jitter) eklenmiş aralıklarla uç düğümü yoklar; tahsis edilen slot_ts zamanı şimdiki zamandan büyük olduğu sürece istekler uç düğümden geri döner ve kaynak sunucuya hiçbir paket iletilmez.
  4. İstemcinin giriş zaman dilimi geldiğinde uç düğüm imzayı sabit zamanlı olarak doğrular ve isteğin kaynak uygulama sunucusuna geçişine izin verir.
  5. Kaynak Go sunucusu çerez imzasını ikinci kez doğrular ve koltuk tahsisi için PgBouncer üzerinden PostgreSQL veritabanında tek bir atomik işlem (transaction) başlatır.
  6. Veritabanı bilet içerisindeki nonce değerini tekillik tablosuna kaydeder, kilitli satırları atlayarak (SKIP LOCKED) ilk boş koltuğu kullanıcıya kilitler ve sonucu döndürür.

Go Standart Kütüphane ile Edge Bilet Doğrulayıcı

package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"strconv"
	"strings"
	"time"
)

// ponytail: Tek statik anahtar ~100k RPS PoP sınırına kadar yeter; sıfır kesintili rotasyon gerektiğinde [2][]byte anahtar dizisine geç.
func IssueToken(secret []byte, uid string, slotUnix, expUnix int64, nonce string) (string, error) {
	if len(secret) < 32 || uid == "" || nonce == "" || expUnix <= slotUnix {
		return "", errors.New("invalid token input")
	}
	payload := uid + "|" + strconv.FormatInt(slotUnix, 10) + "|" + strconv.FormatInt(expUnix, 10) + "|" + nonce
	mac := hmac.New(sha256.New, secret)
	mac.Write([]byte(payload))
	return payload + "|" + hex.EncodeToString(mac.Sum(nil)), nil
}

func VerifyAdmission(secret []byte, token string, nowUnix int64) (nonce string, err error) {
	if len(secret) < 32 {
		return "", errors.New("weak secret")
	}
	idx := strings.LastIndexByte(token, '|')
	if idx <= 0 || idx == len(token)-1 {
		return "", errors.New("malformed token")
	}
	payload, sigHex := token[:idx], token[idx+1:]
	sig, err := hex.DecodeString(sigHex)
	if err != nil {
		return "", errors.New("bad hex")
	}
	mac := hmac.New(sha256.New, secret)
	mac.Write([]byte(payload))
	if !hmac.Equal(sig, mac.Sum(nil)) {
		return "", errors.New("forged signature")
	}
	parts := strings.Split(payload, "|")
	if len(parts) != 4 {
		return "", errors.New("invalid fields")
	}
	slot, err1 := strconv.ParseInt(parts[1], 10, 64)
	exp, err2 := strconv.ParseInt(parts[2], 10, 64)
	if err1 != nil || err2 != nil || nowUnix < slot || nowUnix > exp {
		return "", errors.New("outside admission window")
	}
	return parts[3], nil
}

func main() {
	secret := []byte("0123456789abcdef0123456789abcdef")
	now := time.Now().Unix()
	tok, err := IssueToken(secret, "u42", now-5, now+300, "n9981")
	if err != nil {
		panic(err)
	}
	if n, err := VerifyAdmission(secret, tok, now); err != nil || n != "n9981" {
		panic("valid token rejected")
	}
	if _, err := VerifyAdmission(secret, strings.Replace(tok, "u42", "u99", 1), now); err == nil {
		panic("tampered token accepted")
	}
	if _, err := VerifyAdmission(secret, tok, now+301); err == nil {
		panic("expired token accepted")
	}
}

Atlanan: JWT kütüphanesi ve JSON serileştirme, ekle: üçüncü parti servislerle şema paylaşımı zorunlu olduğunda. Atlanan: Dağıtık Redis iptal listesi (revocation list), ekle: tekil kullanıcıları 5 dakikalık TTL dolmadan anında engellemek gerektiğinde.

PostgreSQL SKIP LOCKED ile Atomik Koltuk Tahsisi

CREATE TABLE IF NOT EXISTS seats (
    id BIGSERIAL PRIMARY KEY,
    event_id INT NOT NULL,
    section TEXT NOT NULL,
    status TEXT NOT NULL CHECK (status IN ('FREE', 'HELD', 'SOLD')),
    held_by TEXT,
    held_until TIMESTAMPTZ
);

CREATE TABLE IF NOT EXISTS consumed_nonces (
    nonce TEXT PRIMARY KEY,
    used_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_seats_avail ON seats (event_id, section, id) WHERE status = 'FREE';

-- ponytail: Tek PostgreSQL düğümü 15k TPS koltuk kilitlemeye kadar yeter; 50k+ TPS aşılırsa section bazlı tablo bölümlemeye (HASH partitioning) geç.
DO $$
DECLARE
    v_seat_id BIGINT;
BEGIN
    INSERT INTO seats (event_id, section, status) VALUES (101, 'A', 'FREE');

    WITH nonce_guard AS (
        INSERT INTO consumed_nonces (nonce) VALUES ('n9981')
        RETURNING nonce
    ),
    candidate AS (
        SELECT s.id
        FROM seats s, nonce_guard
        WHERE s.event_id = 101 AND s.section = 'A' AND s.status = 'FREE'
        ORDER BY s.id
        LIMIT 1
        FOR UPDATE OF s SKIP LOCKED
    )
    UPDATE seats
    SET status = 'HELD', held_by = 'u42', held_until = NOW() + INTERVAL '8 minutes'
    FROM candidate
    WHERE seats.id = candidate.id
    RETURNING seats.id INTO v_seat_id;

    ASSERT v_seat_id IS NOT NULL, 'koltuk tahsis edilemedi';
END $$;

Atlanan: Redis Redlock dağıtık kilit servisi, ekle: koltuk verisi birden fazla bağımsız veritabanı kümesine bölündüğünde. Atlanan: Arka plan cron temizleyici işçisi, ekle: süresi dolan sepetleri okuma anında tembel (lazy) sıfırlamak yetmediğinde.

Üretimde Hata Modları (Failure Modes) ve Savunma Hatları

Mükemmel görünen tasarım üretim ortamındaki kaosla tanıştığında beklenmedik köşelerden kırılır. Sanal bekleme odalarında dört kritik arıza modu sistemi içten çökertir.

Saat Kayması (Clock Skew) ve Bilet Yeniden Oynatma (Replay) Saldırıları

Anycast yönlendirmesi dinamiktir. BGP rota güncellemesi sırasında mobil kullanıcının paketi Frankfurt CDN düğümünden Viyana düğümüne kayabilir. İki sunucu arasında NTP (Network Time Protocol) senkronizasyon farkı veya artık saniye (leap second) kayması varsa Frankfurt düğümünün verdiği slot_ts bileti Viyana düğümünde "henüz zamanı gelmedi" hatasıyla reddedilir. Kullanıcı bekleme odası ile satış sayfası arasında sonsuz yönlendirme döngüsüne (redirect loop) girer. Çözüm: tüm zaman damgalarında UTC Unix saniyesi kullanmak ve doğrulayıcıya 5 saniyelik esneklik payı (clock leeway) tanımaktır.

İkinci tehlike bilet yeniden oynatma (Token Replay) saldırısıdır. Saldırgan yasal yoldan tek bekleme odası bileti alır, süresi dolmadan bileti kopyalayıp 500 paralel curl iş parçacığına verir. Uç katman durumsuz olduğu için 500 isteğin hepsini geçerli sayıp kaynak sunucuya geçirir. Savunma veritabanı katmanındadır: SQL kodunda yer alan consumed_nonces birincil anahtar kısıtı, aynı nonce değerine sahip 500 işlemden yalnızca ilkinin koltuk kilitlemesine izin verir; kalan 499 işlem tekillik hatasıyla anında reddedilir.

Bot Çiftlikleri (Queue Stuffing) ve Sepet Süresi Dolumu (Cart Expiry) Fırtınası

Gelişmiş karaborsa çeteleri satış öncesi bekleme odasına 5 milyon sahte tarayıcı oturumu (Queue Stuffing) sokar. Piyango çekildiğinde havuzun %80'i botlara ait olduğundan gerçek insanların şansı matematiksel olarak biter. IP engelleme işe yaramaz; botlar konut vekil ağları (residential proxies) kullanır. Savunma uç katmanda TLS JA4 parmak izi analizi ve hafif İş Kanıtı (Proof-of-Work) bulmacasıdır. İstemci User-Agent başlığında iPhone Safari olduğunu iddia ederken TLS el sıkışmasındaki şifreleme paketi sırası Go crypto/tls kütüphanesini ele veriyorsa bağlantı anında kesilir. Kalan şüphelilere tarayıcıda 150 milisaniye süren SHA-256 sıfır ön ek bulmacası çözdürülür; tek makinede 10.000 bot koşturan saldırganın CPU maliyeti patlar.

Unutulan bir diğer felaket "İkincil Thundering Herd" dalgasıdır. Saat 10:00:00'da içeri alınan 50.000 kişi koltukları 10 dakikalığına kilitler. Ödeme yapmayan 15.000 kişinin sepeti saat tam 10:10:00'da çalışan zamanlanmış görevle (cron job) aynı saniyede boşa düşer. Boş koltuk bildirimini gören yüz binlerce kişi aynı anda saldırır ve veritabanı ikinci kez kilitlenir. Çözüm sepet kilit sürelerine rastgele sapma (jitter) eklemektir: sabit 600 saniye yerine 480 + rand(0..180) saniye verildiğinde koltukların boşa düşüşü zamana yayılır.

Vaka Analizi: Taylor Swift Eras Tour ve Ticketmaster Çöküşü

15 Kasım 2022 tarihinde yaşanan Taylor Swift "The Eras Tour" ön satış çöküşü, sanal bekleme odası mimarisinde yapılan tek tasarım hatasının tüm küresel altyapıyı nasıl yıktığının en pahalı kanıtıdır.

Ön Satış Kodu Tükenmesi ve 3.5 Milyar İstek Anatomisi

Etkinlik öncesi 1,5 milyon doğrulanmış hayrana (Verified Fan) özel erişim kodu gönderildi. Kapasite planlaması bu 1,5 milyon kullanıcının makul davranacağı varsayımına dayandı. Ancak satış sabahı ön satış kodu olmayan 14 milyon hayran ve endüstriyel ölçekli bilet botları aynı anda giriş kapısına dayandı. Altyapıya toplam 3,5 milyar sistem isteği çarptı; bu rakam platformun tarihsel rekorunun tam dört katıydı.

Felaketin kök nedeni basitti: kimlik doğrulama ve ön satış kodu kontrolü, durumsuz uç katman yerine durum bilgili (stateful) iç mikroservislerin arkasında konumlandırılmıştı. Bekleme odasına girmeye çalışan milyonlarca kodsuz kullanıcı ve bot, uçta düşürülmek yerine iç ağdaki oturum açma ve profil servislerine ulaştı.

Kaskad Arıza Zinciri ve Mimari Dersler

İç ağdaki kimlik doğrulama önbelleği (cache) aşırı yük altında ıskalama fırtınasına (cache miss storm) yakalandı. Kuyruk yönetim servisi, her sıra güncellemesinde arka uçtaki kimlik servisine senkron HTTP çağrısı yapıyordu. Kimlik servisi yavaşlayınca kuyruk servisinin bağlantı havuzları doldu ve servis ağı (service mesh) üzerinde kaskad zaman aşımı başladı.

En yıkıcı sonuç ödeme aşamasında yaşandı. Saatlerce bekleyip koltuğunu sepete ekleyen gerçek kullanıcılar, ödeme butonuna bastıklarında aynı kimlik doğrulama servisine takılıp HTTP 500 hatası aldılar. Geçersiz oturum yanıtını gören kuyruk yazılımı, ödeme aşamasındaki kullanıcıların biletini iptal edip onları milyonlarca kişilik kuyruğun en sonuna geri attı. Çıkarılacak ders kesindir: ön satış hakkı olan kullanıcılara satıştan bir gün önce kriptografik olarak imzalanmış durumsuz geçiş jetonu verilmeli, bu jetonu taşımayan tek bir paket bile CDN uç noktasından içeri alınmamalıdır.

Sıkça Sorulan Sorular (SSS)

Sanal bekleme odasında FIFO mı yoksa piyango (lottery) algoritması mı daha adildir?

Yüksek talepli satışlarda saf FIFO algoritması adil değildir çünkü veri merkezlerinde barındırılan düşük gecikmeli (1 ms RTT) botlar gerçek kullanıcıları her zaman geçer. En adil yöntem hibrit modeldir: satış saatinden önce gelen herkes ön bekleme havuzuna alınır, satış saniyesinde kriptografik karıştırma (lottery) ile rastgele sıraya dizilir ve satış başladıktan sonra katılanlar bu grubun arkasına FIFO düzeniyle eklenir.

Kuyruk durumu güncellemelerinde HTTP Polling mi yoksa Server-Sent Events (SSE) mi kullanılmalıdır?

Milyonlarca eşzamanlı kullanıcı ölçeğinde rastgele sapmalı (jittered) HTTP Polling, SSE veya WebSocket mimarisinden çok daha güvenlidir. Kalıcı SSE bağlantıları uç ve vekil sunucularda milyonlarca açık TCP soketi ve dosya tanımlayıcısı tüketerek çekirdek belleğini zorlar. İstemcinin 10 ila 25 saniye arasında rastgele aralıklarla yaptığı kısa ömürlü HTTP yoklamaları ise CDN önbelleğinden sıfır durum maliyetiyle yanıtlanır.

Çoklu CDN (Multi-CDN) mimarisinde bekleme odası çökmesi (failover) nasıl yönetilir?

Durumsuz HMAC bilet mimarisi çoklu CDN geçişlerini doğal olarak destekler. Birincil ve ikincil CDN sağlayıcılarındaki uç çalışanlara (Edge Workers) aynı 256-bit gizli imza anahtarı ve aynı zaman dilimi (slot_ts) doğrulama kodu dağıtılır. DNS veya BGP üzerinden trafik diğer CDN sağlayıcısına kaydığında kullanıcıların tarayıcısındaki çerezler geçerliliğini korur ve hiç kimse kuyruktaki sırasını kaybetmez.

Bilet botları sanal bekleme odasını aşmak için hangi teknikleri kullanır ve nasıl engellenir?

Botlar konut IP vekilleri (residential proxies), başsız tarayıcı çiftlikleri ve çerez klonlama teknikleri kullanır. Bunları engellemek için üç katmanlı savunma uygulanır: uç katmanda TLS JA4 parmak izi ile sahte tarayıcı başlıkları yakalanır, şüpheli istemcilere istemci CPU'sunu yoran SHA-256 İş Kanıtı (Proof-of-Work) bulmacası çözdürülür ve veritabanında tek kullanımlık nonce kontrolüyle bilet kopyalama engellenir.

Koltuk kilitleme süresi (Seat Lock TTL) hangi metriklere göre belirlenmelidir?

Koltuk kilitleme süresi Little Yasası (Eşzamanlı Aktif Kullanıcı = Giriş Hızı × Ortalama İşlem Süresi) üzerinden hesaplanır. Ödeme ağ geçidi yanıt süresi ve 3D Secure SMS doğrulama adımlarının p99 toplamına makul kullanıcı karar süresi eklenerek genellikle 6 ila 8 dakika arası belirlenir. İkincil trafik patlamalarını önlemek için her kilide mutlaka 60-120 saniyelik rastgele süre sapması (jitter) eklenmelidir.

İlgili Derin Teknik Makaleler

Tüm Makaleler →