Sorunun geçmişi
Erken reklam hizmetleri, yayıncıların talep ortaklarını sıralı şekilde önceliklendirdiği statik su düşüşü yapılandırmalarına dayanıyordu, bu da gecikme su düşüşleri ve gelir sızıntısı yaratıyordu. Header Bidding ve OpenRTB protokollerine geçiş, envanter erişimini demokratikleştirdi ancak aşırı mühendislik kısıtlamaları getirdi: müzayedelerin, sayfa terkini önlemek için 100 ms içinde tamamlanması gerekir, bütçe uygulaması binlerce kenar düğümü arasında aşımını önlemelidir ve dolandırıcılık tespiti, ağ geçişleri eklemeden çevrimiçi gerçekleşmelidir. Bu soru, merkezi Apache Kafka boru hatlarını, otonom mali kararlar verebilen kenar bilişim mimarileri ile değiştirme ihtiyacından doğdu.
Sorun
Geleneksel mimariler, bütçe sayaçları ve özellik depoları için merkezi PostgreSQL veya Redis kümelerine dayanır, bu da Black Friday gibi trafik zirveleri sırasında 100 ms SLA'sını ihlal eden bölgeler arası gecikme yaratır. Bütçe düşüşlerini naïf iyimser kilitleme, gürültü çeteleri ve düşen tekliflere neden olurken, asenkron dolandırıcılık tespiti botların kampanya bütçelerini tüketmelerine izin vermektedir. Ayrıca, DSP'ler (Talep Tarafı Platformları) arasında faturalama uzlaştırması, görüntüleme piksellerinin ateşlenip onay mesajlarının düştüğü ağ bölünmeleri nedeniyle gelir sızıntısına veya reklamveren güvenini yok eden çift ücretlendirmeye maruz kalır.
Çözüm
Envoy Proxy yan parçaları ile WebAssembly filtrelerinin kenar PoP'larında (Varlık Noktaları) müzayede mantığını son kullanıcıların yanına 10 ms içinde çalıştırmasını sağlamak. Bütçe dengesi için Gossip protokolü ile Redis üzerinde CRDT (Çatışmasız Yinelemeli Veri Türü) sayaçları uygulamak, kenar düğümlerinin yerel olarak teklifleri almasına izin verirken, nihai birleşme ile küresel bütçe tutarlılığını garanti eder. Davranış parmak izleri gibi fare hızı desenleri ve navigasyon entropisi kullanarak gerçek zamanlı bot tespiti için kenar katmanına hafif TensorFlow Lite modelleri yerleştirmek. Apache Pulsar'ı Coğrafi Eşleme ve BookKeeper ile değiştirilemez denetim kayıtları için kullanmak, Idempotent Üreticiler ve Çift Yazım Pencereleri aracılığıyla tam olarak bir kez anlamlarını garanti eder. GDPR uyumluluğu için, K-Anonimlik kontrolleri ve veri ikamesini Anycast DNS ile EDNS Client Subnet farkındalığı aracılığıyla uygulamak.
2023 Black Friday etkinliği sırasında, platformumuz 40 kat trafik artışı yaşadı ve merkezi Redis bütçe deposunu us-east-1'de doygun hale getirdi; bu da müzayedelerin %12'sinin zaman aşımına uğramasına ve 2 milyon dolarlık potansiyel gelir kaybıyla tehdit edilmesine neden oldu. Mühendislik ekibi, kritik bir mimari karar ile karşı karşıya kaldı: güçlü tutarlılığı sürdürmek ve gecikme ihlallerini kabul etmek veya hız önceliği vermek ve felakete yol açan bütçe aşımını tehlikeye atmak.
Çözüm A: Redlock ile Redis Kümesi
Bütçe tutarlılığını sağlamak için beş bağımsız Redis ana düğümü üzerinde Redlock algoritmaları uygulamayı düşündük. Bu yaklaşım, her azalma için çoğunluk mutabakatı gerektirerek, hiçbir kampanyanın günlük üst sınırını aşmadığını teorik olarak garanti edecektir. Ancak, kenar düğümleri ile Redis kümesi arasındaki gidiş-dönüş süresi ortalama 35 ms idi ve yük altında, kilit rekabeti, taleplerin %8'inin birden fazla kez yeniden denemesiyle sonuçlandı, bu da 100 ms SLA'mızı aştı. Bu, mükemmel bütçe doğruluğu sağlarken, kabul edilemez gecikme ve operasyonel karmaşıklık, gerçek zamanlı teklif verme için uygun hale getirmedi.
Çözüm B: Yerel Bellek Önbelleklemesi ile Asenkron Senkronizasyon
Alternatif olarak, her kenar düğümünün merkezi bir deftere her 30 saniyede bir asenkron olarak senkronize edilen yalnızca yerel bütçe sayaçlarını tutmasına izin vermeyi değerlendirdik. Bu, müzadelede 5 ms altı gecikme sağladı ve trafik zirvesini dış bağımlılıklar olmadan nazikçe ele aldı. Ne yazık ki, artış sırasında, çok sayıda kenar düğümü, senkronizasyon gerçekleşmeden önce toplamda 800K dolara yüksek değerli kampanyaları aşırı sattı; bu da reklamveren güvenine zarar verdi ve sözleşme cezası doğurdu. Hız optimaldi, ancak finansal risk, ödeme ile ilişkili bir sistem için felaketti.
Çözüm C: Hibrid CRDT Mimarisinde Hiyerarşik Düzenleme
Delta-Eyalet CRDT'lerini Redis üzerinde üç katmanda: kenar, bölgesel ve küresel kullanarak melez bir yaklaşım uyguladık. Kenar düğümleri, yerel PN-Sayaçları (Pozitif-Negatif Sayaçlar) kullanarak teklifleri kabul ediyor ve küresel bütçenin %95'ine kadar muhafazakar yerel eşikler belirliyor. Yerel bütçeler tükenince, düğümler bölgesel önbellekleri Yazdıklarını Oku tutarlılığı ile sorguluyor. Kalan %5 tampon, g Gossip senkronizasyonu sırasında CRDT birleştirmeleri ile küresel defter tarafından yönetilmektedir. Dolandırıcılık için, ağaç çağrıları olmadan bot desenlerini tespit edecek şekilde eğitilmiş kenar düğümlerinde TinyML modelleri dağıttık. Bu çözümü seçtik çünkü %99,9 bütçe doğruluğu sağlarken, %45'lik p99 gecikmesini korumaktadır.
Sonuç
Platform, zirve sırasında saniyede 12 milyon sorgu işledi ve tavan bütçeli kampanyalarda sıfır bütçe aşımıyla sonuçlandı. Dolandırıcılık tespiti gecikmesi 150 ms'den 8 ms'ye düştü, teklif verirken %3,4 kötü niyetli trafiği engelledi. CRDT uzlaştırması, bölgeler arasında 200 ms içinde nihai bir tutarlılık sağladı, faturalama uzlaştırma penceresinin çok altında kaldı ve GDPR uyumluluğu, kenar yerel veri işlemeleri ile korundu.
Birden fazla kenar düğümü, küresel kilitler almadan aynı kampanya bütçesini aynı anda azaltırken bütçe aşımını nasıl önlersiniz?
Çoğu aday, ağ bölünmeleri veya yüksek gecikmeler altında başarısız olan Redis'te dağıtık kilitler veya atomik azaltma işlemleri önermektedir. Doğru yaklaşım, CRDT'ler olarak uygulanan PN-Sayaçları kullanmaktır. Her kenar düğümü, harcama için yerel bir artış sayacı ve iadeler için bir azalma sayacı tutmaktadır. Bir düğüm bir teklifi kabul ederken, yerel harcama sayacını artırır. Gossip senkronizasyonu sırasında, düğümler sayaç durumlarını değiştirir ve bunları Birleşim işlemiyle (her sayaç bileşeninin maksimumunu alarak) birleştirir. Geçici aşımı önlemek için, yerel olarak muhafazakar sınırlarla Token Bucket algoritmalarını uygulayın. Tüm yerel harcamaların toplamı küresel sınıra yaklaşırsa, düğümler kalan %5 bütçe için bölgesel koordinatörden sorgulama yapar. Bu, teori olarak ağ bölünmesi sırasında geçici 1-2% aşımın mümkün olduğu sürede bile, sistemin bütçenin %105'ini asla aşmadığını garanti eder, bu da geleneksel bankacılık sistemlerinin aksine dijital reklam SLA'ları için kabul edilebilir.
İzleme pikselleri kullanıcı tarayıcılarından ateşlendiğinde ancak ağ hataları, müzayede sunucusuna onay teslimini engellediğinde tam olarak bir kez faturalama nasıl sağlanır?
Adaylar genellikle Kafka kimlikselliği veya veritabanı güncellemeleri önerir, nihai problemi gözden kaçırır. Çözüm, kenar katmanında oluşturulan Idempotent Anahtarlar gerektirir; bu anahtarlar UUIDv7 (zaman sıralı) kullanılarak yaratılır ve yaratım işaretine gömülür. Tarayıcı izleme piksellerini ateşlediğinde, bu anahtarı dahil eder. Kenar Nginx katmanı, 24 saatlik bir pencere kullanarak Deduplication Enabled ile Apache Pulsar'a yazdırır. Pulsar'ın BookKeeper depolama çözümü, aynı anahtarla yapılan çift yazımları broker düzeyinde, tüketici düzeyinde değil, reddederek garanti eder. Ayrıca, Idempotent anahtar ile bölümlere ayrılmış BigQuery geçici tablosuna en az bir kez teslimat implementasyonu yapılmalıdır; bunun için MERGE ifadeleri, ETL sürecinde tekrarları önlemek için çalıştırılır. Bu iki katmanlı koruma, tarayıcının 500 hatası nedeniyle piksel ateşlemeyi 50 kez denemesi durumunda bile reklamverenin yalnızca bir kez ücretlendirilmesini garanti eder.
Müzayede kazananlarını belirlerken coğrafi olarak dağıtılmış teklif sahipleri arasındaki saat kaymalarını nasıl ele alıyorsunuz?
Bu ince bir konu. Adaylar sıklıkla NTP veya TrueTime (Spanner'dan) önerir, ancak bunlar gecikme ekler. Doğru mimari, müzayede mantığından duvar saati bağımlılıklarını ortadan kaldırır. DSP yanıtlarının zaman damgalarını karşılaştırmak yerine, kenarda Mantıksal Saatler (Lamport Zaman Damgaları) kullanın veya sadece FIFO kuyrukları kullanın. Müzayede başladığında, kenar düğümü Yüksek Çözünürlüklü Zamanlayıcı (V8'de Performance.now() veya C++ chrono) başlatır. DSP yanıtları, zaman damgası başlıklarına göre değil, ağ arayüzünde varış sırasına göre sıralanır. Gecikmeleri ele almak için, her DSP için tarihsel p99 gecikmesine göre ayarlanan Ayarlanabilir Zaman Aşımı Algoritmaları kullanarak bir Ayarlanabilir Zaman Aşımı uygulayın. Faturalama anlaşmazlıkları ve sonrası için, Monotonik Saat okumalarını ve belirsizlik aralıkları ile birlikte UTC Zaman Damgasını kaydedin; bunları CockroachDB'de depolayın, bu da belirsizlik pencerelerini otomatik olarak yönetir. Bu, bir DSP'nin sunucusunun saatinin diğerine göre 200 ms ileri olduğu durumlarda bile adalet sağlar.