CobbleDB: Daha Düşük Gecikme ve Maliyet için AI Arama Depolamasını Yeniden İnşa Etmek
Kalıcı durumu, toplu güncellemeleri ve sorgu anı getirmeyi ayıran ayrıştırılmış mimari.
AI-native arama, web içeriğinin işlenmesi, depolanması ve sunulması konusunda farklı gereksinimler dayatır. Bu talepleri ölçekte karşılamak için performansı artırmak ve maliyeti düşürmek amacıyla tüm yığını sıfırdan yeniden inşa ediyoruz.
Verimli işlemeyi ve hızlı sunumu desteklemek için kendi tarama, dizine ekleme ve sıralama altyapımızı, gömme modellerimizi ve çıkarım motorlarımızı geliştirdik. Şimdi bu yaklaşımı, işlemenin yazdığı ve sunumun okuduğu bağlantı dokusu olan depolamaya da genişletiyoruz.
DynamoDB gibi yönetilen veritabanları güvenilir depolama sağladı, ancak verilerin nasıl depolandığı ve okumalara nasıl hizmet edildiği üzerinde sınırlı kontrolümüz vardı ve kullanıma dayalı fiyatlandırma, dizin boyutumuz ve sorgu hacmimizle birlikte arttı. Buna ek olarak, önceki boru hattımız belge işlemesini doğrudan sunucu veritabanına bağlayarak canlı okumalardan bağımsız olarak güncellemeleri yönetmeyi zorlaştırdı.
Yeni bir dahili kodlama ajanı sürüsünün yardımıyla; kalıcı belge durumu ve yayımlama için Pillar, toplu güncellemeler için Lorry tarafından desteklenen ve anahtar-değer sıcak deposu olan CobbleDB etrafında bu katmanı yeniden inşa ettik. Yeniden tasarımla belge işlemesi sıcak depo veri alımından ayrılır ve sunumu iş yükümüze göre ayarlamamıza olanak tanır. Üretim öncesi ve sonrası ölçümleri yaklaşık 5× daha düşük toplu okuma gecikmesi gösterirken, dahili maliyet modelimiz DynamoDB'ye kıyasla en az %20 tasarruf öngörmektedir.
AI-native arama için depolama altyapısı
Klasik bir arama yığını, dil modeli için değil insan okuyucu için tasarlanmıştır. Bu fark, sistemin web içeriğini hazırlaması, depolaması ve sunması gereken ayrıntı düzeyini (granularity) değiştirir.
Ham HTML'yi modellemeye hazır içeriğe dönüştürmek için işleme boru hattımız her sayfayı temizler, anlamsal olarak tutarlı pasajlara böler, bunların gömmelerini hesaplar ve pasajlar ile gömmeleri veritabanında birlikte depolar. Sorgu anında sunum boru hattı, sorguyla en ilgili metni seçer ve modele iletir.
İki farklı iş akışı
Bu nedenle depolama katmanı, farklı talepleri olan iki iş akışını desteklemelidir: işleme boru hattından gelen güncellemeleri almak ve düşük gecikmeli okumalara hizmet etmek.
Yazma tarafında, sürekli olarak yeni sayfalar gelir, mevcut sayfalar değişir ve parselleme yöntemlerindeki veya gömme modellerindeki değişiklikler derlemenin büyük bölümlerinin yeniden işlenmesini gerektirebilir. Depolama katmanı bu güncellemeleri kalıcı belge durumuna dahil etmeli, mevcut sürümleri izlemeli, doğru temsilleri alt akış sistemlerine yayımlamalı ve ham taramadan tam boru hattını tekrarlamadan büyük veri dolgularını (backfills) desteklemelidir.
Buna karşılık, sorgu anındaki okumalar sayfa anahtarlarının toplu hallerini talep eder ve sıralama (ranking) ile pasaj seçimi için ilgili pasaj metnini ve gömmeleri (embeddings) getirir. Bu okumalar nihai cevaba giden yolda yer alır, bu nedenle hızlı bir şekilde tamamlanmaları gerekir.
Bu iş yükleri farklı tasarımlar gerektirir. İşleme; kalıcı kuyruklardan, güncellemeleri verimli bir şekilde iletme, hataları yeniden deneme ve mevcut kayıtları büyük ölçekte güncel tutma yeteneğinden faydalanır. Sunum ise önceden hesaplanmış kayıtlar, sıcak önbellekler ve minimum sorgu anı çalışmasıyla hızlı toplu okumalardan faydalanır. ikisi arasındaki sıkı bağ (tight coupling), kurtarma çalışmalarının ve büyük güncellemelerin gecikmeye duyarlı okumalarla rekabet etmesine neden olabilir.
Yönetilen veritabanının yetersiz kaldığı durumlar
DynamoDB, dağıtık bir veritabanı işletmenin yükü olmaksızın bize yüksek düzeyde erişilebilir bir depolama alanı sundu. Sorgu anında okumalar için pasajları ve gömmeleri (embeddings) özel olarak hazırlanmış sayfa tablosu tutarken, tam sayfa içeriği ve meta veriler ayrı ayrı depolandı. Ancak iş yükümüz büyüdükçe üç kısıtlama önemli hale geldi.
İkincisi, kullanıma dayalı fiyatlandırma okunan veya yazılan her bayt için ücret alır. Tek bir Arama API'si isteği, getirmemiz gereken sayfalara karşılık gelen 100-120 anahtar içerir. Veri alma işlemi, ortalama öğe boyutu yaklaşık 50 KB olan 10-20 sayfa anahtarından oluşan daha küçük toplu işlere isteği böler. Bu kayıtların tekrar tekrar okunması büyük bir kapasite tüketirken, sürekli taramalar ve parselleme ya da gömme modellerindeki değişiklikler daha fazla yazma işlemi üretti. Ekonomik model yalnızca API çağrısı sayısına değil, aynı zamanda kayıtların boyutuna ve sıklığına da bağlıydı.
İkincisi, yönetilen servis performans ayarlaması için ihtiyaç duyduğumuz esneklikten yoksundur. İhtiyacımız olan işlem dar kapsamlıydı: bir sayfa tanımlayıcıları toplu işi verildiğinde, hazırlanan içeriklerini hızlı bir şekilde döndürmek. Hangi makinenin bir bölümü barındırdığı, önbelleğine ne kadar bellek ayrıldığı ve hangi çoğaltmanın bir isteği ele aldığı konusunda kontrol sahibi olmak istedik. Bu kontroller önemlidir çünkü önbelleğe alınmamış bir okuma, bölgeler arası bir atlama veya yavaş bir çoğaltma tüm toplu işi geciktirebilir. DynamoDB, API'nin arkasında kendi depolama ve çoğaltma davranışını yönetir. Servisi yapılandırabilirdik, ancak iş yükümüz etrafındaki dahili yerleşimini, depolama motoru önbelleklerini veya çoğaltma seçim politikasını ayarlayamıyorduk.
Üçüncüsü, işleme doğrudan sıcak depo yazımlarına bağlanmıştı. Önceki işleme boru hattımız hazırlanan her sayfayı doğrudan DynamoDB'ye yazıyordu. Bu nedenle büyük bir yeniden işleme görevi bir dizi bireysel sıcak depo güncellemesine dönüşüyor ve işleme, sıcak deponun aktarım hızı (throughput) sınırlarına ve yeniden deneme (retry) davranışına uyum sağlamak zorunda kalıyordu. Yeni bir parçaçalama (chunking) yöntemini denemek, gömme modelimizi değiştirmek veya yeni bir alan eklemek için tüm veritabanı üzerinde 1-2 gün içinde MapReduce çalıştıramazdık. Ayrı bir servisin kendi hızında toplu hale getirip sıcak depoya iletebileceği bağımsız bir kaydedilmiş sayfa güncellemeleri akışı yoktu.
Bu kısıtlamaların ele alınması, veritabanını değiştirmekten fazlasını gerektiriyordu. Kalıcı belge durumunu ve güncelleme iletimini sorgu anı depolamasından ayırmamız ve ardından sıcak depoyu özellikle hızlı toplu okumalar için optimize etmemiz gerekiyordu.
Belge durumunu, güncelleme iletimini ve sunumu ayırın
Yeni mimari her sorumluluğu farklı bir bileşene atar. Pillar kalıcı bir belge durumu korur ve neyin yayımlanacağına karar verir. Lorry bu dışa aktarımları bölümlenmiş toplu işlere dönüştürür. CobbleDB toplu işleri alır ve sayfa anahtarına göre hazırlanan kayıtları sunar.
CobbleDB: Ayarlanabilir okuma yolu
CobbleDB, sorgu anında hazırlanan kayıtları sunmak için optimize edilmiş sıcak depomuzdur. Dağıtık bir anahtar-değer deposudur: anahtarlar sayfa tanımlayıcılarıdır (hash'lenmiş URL'ler) ve değerler sayfanın işlenmiş temsilidir (önceden parselere ayrılmış pasajları ve parsel başına vektör gömmeleri).
Önemli değişiklik, depolama yapılandırması üzerindeki kontrolümüzdür.
Veriler bölümlere ayrılır ve veri düğümleri arasında paylaştırılır. Bu dağıtık biçim, veritabanının işlenmiş devasa bir sayfa derlemesini (corpus) barındıracak şekilde yatay olarak ölçeklenebilmesini sağlar. Her bölümün üç farklı düğüm üzerinde üç çoğaltması (replica) vardır; bir kopya kullanılamaz hale gelirse diğerleri okumalara hizmet etmeye devam edebilir.
Her bir veri düğümüne bölümlerin (partitions) bir alt kümesi atanır. Düğüm, verilerini toplu alımlarla beslenen ve yoğun okuma iş yüklerine son derece uygun, açık kaynaklı gömülü bir anahtar-değer (key-value) depolama motoru olan RocksDB kullanarak depolar.
Önbelleğe alınmış veriler bellekten sunulabilirken, önbelleğe alınmamış okumalar yerel NVMe depolama alanı kullanır. Bu bize, yönetilen bir servisin dahili önbellek politikasını kabul etmek yerine, gözlemlenen iş yükü için bellek-disk dengesini optimize etme konusunda doğrudan bir yol sunar.
Durumsuz (stateless) bir sorgu yönlendiricisi, anahtarları bölümlere hash'ler ve istekleri paralel olarak düğümlere yönlendirir. Mimari ayrıca PostgreSQL tabanlı bir meta veri servisi ve kalıcı nesne depolama (object storage) içerir.
Bu tasarım, iş yükümüzün talep ettiği okuma kalıplarını destekler. Bir sorgu, ilgili sayfaların aday kümesini elde etmek için alma (retrieval) ve sıralamadan (ranking) geçtikten sonra, bu sayfaların içerikleri için sıcak veritabanı toplu olarak sorgulanır. Bu okuma istekleri yönlendiriciye (router) ulaşır ve ilgili bir veri düğümüne yönlendirilir. Yönlendirici, mümkünse bölgeler arası (cross-zone) gecikmeyi en aza indirmek için istekleri aynı erişilebilirlik bölgesindeki bir düğüme göndermeye öncelik verir. Her veri düğümü, birden fazla anahtarı düşük gecikmeyle aynı anda getirmek için tasarlanmış bir RocksDB toplu okuma API'si olan MultiGet'i kullanarak sayfa içeriklerini alabilir. Bir düğümün yanıt vermesi yavaşsa sistem, farklı bir düğümdeki başka bir bölüm çoğaltmasını da sorgulayarak kuyruk gecikmesini (tail latency) iyileştirebilir.
İş akışımızın gerektirmediği yaygın özellikleri uygulamaktan da kaçınabiliriz. Örneğin, çoğu veritabanı tutarlılık garantileri ve işlem desteği sunar, ancak sıcak depolarımız işlem veya senkronize edilmiş çoğaltma gerektirmez. Bir belgenin yazıldığı an ile okumaya hazır hale geldiği an arasında kısa bir gecikme olması ve bir çoğaltmanın verileri diğerinden daha hızlı alması kabul edilebilirdir. İhtiyacımız olmayan özellikleri dışarıda bırakmak, sistemimizin genel giderlerini ve maliyetini azaltır.
Pillar ve Lorry: Kalıcı yazma yolu
Taradığımız ve işlediğimiz her şeyi ayrı bir depolama katmanı takip eder; güncellemeleri sürümlendirilmiş belge durumuyla birleştirir ve gerekli temsilleri CobbleDB ile arama dizinine yayımlar. Bu amaçla belge durumu ve yayımlama katmanımız olan Pillar'ı geliştirdik.
Pillar, YTsaurus tarafından desteklenmektedir. Sayfa bileşenlerini (meta veriler, parçalar ve gömmeler gibi) ayrı YTsaurus tablo ailelerinde saklar. Ayrıca parçaların ve gömmelerin sürümlerini takip ederek, altta yatan modellerin değişebilmesi için birden fazla temsilin birbirinin üzerine yazılmadan bir arada var olmasını sağlar. Pillar ve YTsaurus ucuz HDD depolama kullandığından, DynamoDB'de sakladığımızdan çok daha fazla belgeyi saklayabiliriz.
Pillar; alt kümeleri (subsets) veya taze sayfalar ya da yüksek değerli sayfalar gibi ilke tanımlı sayfa gruplarını izler. Alt küme üyeliği, hangi güncellemelerin CobbleDB gibi alt akış bileşenlerine aktarılması gerektiğini belirler. CobbleDB daha pahalı NVMe depolama kullanır, bu nedenle yalnızca arama sonuçlarında gerçekten kullanmak istediğimiz belgeleri dışarı aktarırız. Bir sayfanın içeriği güncellendiğinde veya bir alt kümeden eklendiğinde ya da kaldırıldığında, Pillar ilgili dışa aktarım işini kuyruğa almaktan sorumludur.
Atomik YTsaurus işlem güvencesini sağlamak amacıyla durumu, dışa aktarım niyetlerini ve tüketilen girdileri kapsar. Bir işlemin başarıyla tamamlanabilmesi için sistemin kalıcı durumu güncellemesi, girdiyi işleme alınmış olarak işaretlemesi ve gerekli tüm dışa aktarımları kuyruğa eklemesi gerekir; eğer işlem iptal edilirse hiçbir katmanda herhangi bir değişiklik yapılmaz.
CobbleDB, güncellemelerin bölüme göre toplu hale getirilmesini bekler. Pillar dışa aktarımları, Lorry adını verdiğimiz durumsuz (stateless) bir servis tarafından bu biçime dönüştürülür. Tek görevi kalıcı, bölüme hizalanmış bir kuyruktan dışa aktarım kayıtlarını okumak, bunları bölüme özel toplu dosyalarda birleştirmek ve CobbleDB'ye teslim etmektir.
Lorry ile Cobble arasında ek bir protokol, veri düzlemini (S3) kontrol düzleminden ayırır. Lorry, toplu işi benzersiz bir tanımlayıcı altında S3'e yazar ve toplu işi Cobble içinde kaydeder. Cobble bölümü çoğaltmaları, alınacak bir sonraki S3 toplu işi için veri düzlemi veya kontrol düzlemi API'sini bağımsız olarak sorgular ve toplu güncelleştirmeleri kronolojik sırada eşzamansız (asynchronously) olarak uygular. Bu, yavaş veya iyileşmekte olan bir düğümün sistemin geri kalanını yavaşlatmak yerine kendi hızında yetişebileceği anlamına gelir.
Yeni yol, anlık işleme işlemini sıcak depoya veri alımından ayırır ve artımlı güncellemeler ile toplu yeniden oluşturmalar için yeniden oynatılabilir (replayable) bir yol sağlar. Bu iş bölümü, kalıcı belge durumundaki güncellemelerin okuma yolu gecikmesine müdahale etmemesini sağlar.
Doğrulama
5x daha hızlı
Sıcak depo (hot store) taşındıktan sonra ortalama toplu okuma gecikmesi 31,4 ms'den 5,60 ms'ye düştü. p90 değeri 56,7 ms'den 9,77 ms'e, p99 değeri ise 123 ms'den 24,2 ms'e geriledi. Oranlar 5,08× ile 5,80× arasında değişiyor ve hem tipik isteklerde hem de kuyrukta (tail) iyileşmeler görüldü.
Bu rakamlar, her sorgunun yaklaşık 10-15 anahtar talep ettiği toplu okumalardan elde edilmiştir. Ortalama yük öğesi boyutu 50 KB'dır. Her iki sistem de yaklaşık 200 bin rps hızında sorgulanmıştır; bununla birlikte herhangi bir düşüş yaşanmadan 500 bin rps'ye kadar yük testleri de gerçekleştirdik.
CobbleDB'nin katkısını yalıtmak için kurulumun diğer tüm yönleri sabit tutuldu. Ancak bu, gözlemsel bir öncesi ve sonrası karşılaştırması olmaya devam ediyor; sistemler kontrollü koşullar altında aynı istekleri işlemek yerine canlı üretim trafiğine farklı zamanlarda hizmet verdi. Bu nedenle her iki sistemin performansını sentetik bir kıyaslama (benchmark) üzerinde de ölçtük. Üretimde görülen istekleri taklit etmek amacıyla, 10-100 KiB arasında değişen değerlere ve 10-15 anahtardan oluşan toplu verilere sahip isteklerle her iki sistemi de sorguladık.
DynamoDB bu bağlamda zorlanır çünkü yönetilen okuma yolu bu boyuttaki toplu okumalar için ayarlanamaz. Buna karşılık CobbleDB; yerleşimi, önbelleğe almayı (caching) ve çoğaltma kontrollerini bizim yönetmemiz nedeniyle tam da bu ortam için optimize edilmiştir. Anahtarları bölüme göre gruplandırır, okumaları bölüm çoğaltmalarına karşı paralel olarak yürütür ve yavaş okumaları diğer çoğaltmalara karşı sınırlayabilir. Sonuçlarımız, bu tasarım seçimlerinin üretim ortamında daha hızlı okumalara dönüştüğünü göstermektedir.
%20 daha ucuz
CobbleDB ayrıca DynamoDB'den önemli ölçüde daha ucuzdur. Depolamaya ek olarak DynamoDB, okunan veya yazılan her bayt için de ücret alır. Derleme (corpus) ölçeğimiz ve sunum trafiğimiz düzeyinde, kullanıma dayalı bu ücretler toplam maliyetin önemli bir parçasını oluşturur. Sürekli güncellemeler yazma kapasitesi tüketirken, bir sorgu için getirilen hazırlanan sayfaların her toplu işi okuma kapasitesi tüketir.
Maliyet tasarruflarını depolama boyutu, yazma kapasitesi birimleri ve okuma kapasitesi birimlerine ilişkin dahili tahminlere dayanarak hesapladık. Her taahhüt kademesinde CobbleDB, DynamoDB'den en az %20 daha ucuzdur. Gerçek tasarruflar muhtemelen çok daha yüksektir, çünkü bu sonuçlar sıkıştırmadan kaynaklanacak olası yedekleme tasarruflarını hesaba katmamaktadır.
Bir AI ajanı sürüsü bunu inşa etmemize nasıl yardımcı oluyor?
CobbleDB'yi ve çevreleyen altyapıyı inşa etmek hiç de kolay değildi. Yalnızca CobbleDB'nin çekirdek veritabanı yaklaşık 40.000 satır Rust kodundan oluşuyor ve geçiş; üretim ölçeğinde doğruluğu ve hata davranışını doğrulamak, CobbleDB'yi hem işleme hem de sunum yollarıyla entegre etmek ve canlı trafiği güvenli bir şekilde geçirmek için kapsamlı çalışmalar gerektirdi.
Bir kodlama ajanı sürüsü çalıştıran dahili bir sistemi kullanarak bu çabayı hızlandırdık. Sistem, son derece kalıcı olacak şekilde tasarlanmıştır; oturumlar boyunca projenin hedeflerini, aktif riskleri, depo (repository) geçmişini ve önceki kararları muhafaza eder.
CobbleDB projesine bu tür proaktif, her zaman çalışır durumda olan ajanlardan oluşan bir topluluk atadık. İlk görevleri, halihazırda devam etmekte olan çalışmanın doğru bir modelini oluşturmaktı. Proje kanalını ve aktif konuları denetlediler, bekleyen öğeleri pull request'leri ve sahipleriyle ilişkilendirdiler; sistem sağlığı ve sonraki eylemler hakkında güncel bir özet raporu ürettiler. Buradan hareketle mühendislik döngüsünün çeşitli kısımlarında faaliyet gösterdiler:
- Kod ve altyapı değişiklikleri incelendi.
- Güvenli olmayan geri yükleme varsayımları, eski derleme referansları ve çalışma zamanında başarısız olacak yapılandırmalar dahil olmak üzere gözden kaçması kolay engeller ortaya çıkarıldı.
- Odaklanmış düzeltmeler, testler, izleme değişiklikleri ve operasyonel belgeler hazırlandı.
- Üretim eylemlerinin açıkça insanlar tarafından sahiplenilmesini sağlarken CI, inceleme (review) ve altyapı geçitlerini (gates) takip etti.
- İzlenen dağıtımlar (rollouts) ile yedekleme veya geri yükleme alıştırmaları yapıldı ve ardından gözlemlenen sistem durumu dağıtımın başarı ölçütleriyle karşılaştırıldı.
- Mühendislerin neyin sevk edildiğini, neyin engelli kaldığını ve nerede hala insan muhakemesine ihtiyaç duyulduğunu görebilmesi için proje özetleri sürdürüldü.
Mühendisler mimariyi belirlemeye, önemli değişiklikleri incelemeye ve üretim operasyonlarını yetkilendirmeye devam etti. Ajanlar, bu kararlar arasındaki sürekli denetim ve takibin büyük kısmını ele aldı. Bu, küçük bir ekibin projeyi verimli bir şekilde yürütmesini sağladı; temel CobbleDB altyapısı iki insan mühendis ve yüzlerce yapay zeka ajanı tarafından iki ayda inşa edildi.
Sonuç
CobbleDB genel amaçlı bir veritabanı değildir; eşzamansız (asynchronous) bir işleme boru hattı (pipeline) tarafından beslenen, hazırlanan sayfa kayıtlarının tekrar eden toplu okumalarından oluşan özel iş yükümüz için amaca yönelik olarak tasarlanmıştır. Kalıcı durumu, güncelleme iletimini ve sorgu anında sunumu birbirinden ayırarak; tek bir veritabanı arayüzünün tüm bunları barındırmaya zorlanmasını veya bakım işlerinin canlı sorgu yoluna yıkılmasını engellemeden, her bir sorumluluğu bağımsız olarak optimize edebiliriz. CobbleDB'ye geçiş, altyapı maliyetlerini düşürürken hem ortalama hem de kuyruk (tail) gecikmesini önemli ölçüde iyileştirdi.
Kurum içinde AI-native altyapı geliştirmeye devam ettikçe, üçüncü taraf uygulamalara ve fiyatlandırma modellerine bağlı olduğumuzda mümkün olmayan şekillerde performans ve maliyet optimizasyonu sağlayabiliriz. Güçlü AI ajanları, dengeyi satın almak yerine inşa etmek lehine daha da fazla değiştirmektedir.
CobbleDB'yi yakında açık kaynaklı hale getirmeyi planlıyoruz; böylece AI-native arama sistemleri geliştiren diğer ekipler, arama işlemlerini ürünlerimizin içinde daha hızlı ve daha ucuz hale getiren aynı depolama katmanından yararlanabilir.
Alıntı
@online{perplexity2026Cobbledb,
author = {{Perplexity} and Alexandr Yarats and Marco Montagna and Aleksei Bykov and Alexey Gusev and Ali Abdullaev and Amir Mokhammed-Ali and Andrey Zosimov and Denis Kremko and Gleb Vishnevsky and Micah Zirn and Phi Hoang and Claire Beamer and Jeremy Yang and Jerry Ma and Denis Yarats},
title = {{CobbleDB: Rebuilding AI search storage for lower latency and cost}},
date = {2026-09-14},
url = {https://perplexity.coolkeypoint.com/hub/blog/cobbledb}
}