İçeriğe Atla
Mustafa Erbay
Rehberler veritabani-derinlemesine · 9 dk okuma · görüntülenme

Vektör Veritabanı Seçimi: Maliyet ve Performans Dengesi

PGVector, Qdrant ve Milvus karşılaştırmasıyla, vektör arama projelerinde bellek maliyetlerini düşürme ve performans dengesi kurma yöntemleri.

100%

Vektör veritabanı seçerken yapılan en büyük hata, doğrudan en popüler SaaS çözümüne kredi kartı tanımlayıp projeyi başlatmaktır. İlk birkaç bin vektörde her şey harika giderken, veri seti milyon sınırını geçtiğinde karşınıza çıkan kabarık aylık fatura canınızı sıkabilir. Vektör arama (vector search) operasyonlarında maliyetin ana belirleyicisi CPU değil, tamamen RAM kapasitesidir.

Kendi geliştirdiğim bir yan üründe ve danışmanlık yaptığım bir e-ticaret projesinde bu süreci bizzat yönettim. RAM tüketimini optimize etmeden doğrudan “en hızlı” indeksi seçtiğinizde, sunucunun Out-Of-Memory (OOM) hatasıyla çökmesi an meselesidir. Bu yazıda, pgvector, Qdrant ve Milvus üzerinde yaptığım testlerden yola çıkarak, cebinizi yakmayacak bir vektör mimarisini nasıl kuracağınızı anlatıyorum.

Bellek ve Disk Tüketimi Hesaplama (HNSW vs IVF)

Vektör indeksleme algoritmaları temelde ikiye ayrılır: HNSW (Hierarchical Navigable Small World) ve IVF (Inverted File). HNSW, yüksek doğruluk (recall) ve inanılmaz düşük gecikme süresi (latency) sunar ancak tüm grafiği RAM üzerinde tutmak zorundadır. IVF ise veriyi kümelere ayırarak diskten okuma yapabilir, bu da bellek maliyetini düşürür ama doğruluktan ödün vermenize neden olur.

1 milyon adet 1536 boyutlu (dimension) vektörümüz olduğunu varsayalım (OpenAI text-embedding-3-large veya text-embedding-ada-002 standart boyutu). Ham veri boyutunu hesaplayarak işe başlayalım:

1,000,000 (vektör sayısı) * 1536 (boyut) * 4 byte (float32) = 6,144,000,000 byte (~5.72 GB)

Sadece ham vektörleri bellekte tutmak 5.72 GB RAM gerektirir. Eğer HNSW indeksi oluşturursanız, grafik bağlantıları (graph edges) için vektör başına ek bellek yükü biner. HNSW parametrelerini $M=16$ ve $ef_construction=64$ seçtiğimizde, indeks boyutu ham verinin yaklaşık 1.5 ila 2 katına çıkar. Toplamda sadece bu indeks için en az 12-15 GB RAM ayırmanız gerekir.

PostgreSQL pgvector ile Başlamak Ne Zaman Mantıklı?

Eğer mevcut altyapınızda halihazırda PostgreSQL 15+ kullanıyorsanız ve vektör sayınız 500 binin altındaysa, yeni bir veritabanı teknolojisini stack’inize eklemek tamamen gereksiz bir operasyonel yüktür. PostgreSQL pgvector eklentisi (özellikle v0.5.0+ ile gelen HNSW desteği), ilişkisel verilerinizle vektör verilerinizi aynı transaction sınırları içinde sorgulamanıza olanak tanır.

Ancak pgvector kullanırken dikkat etmeniz gereken çok kritik bir SQL kuralı vardır. İndeks oluşturma işlemi (index build) çok fazla RAM tüketir. maintenance_work_mem parametresini geçici olarak yükseltmezseniz, indeks oluşturma işlemi disk swap’e düşer ve saatlerce sürebilir.

-- pgvector için HNSW indeksi oluşturmadan önce belleği artırın
SET maintenance_work_mem = '4GB';

CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops) 
WITH (m = 16, ef_construction = 64);

Bu yaklaşım, veri tabanınız büyüdükçe bağlantı havuzu (connection pool) yönetimiyle çakışır. PostgreSQL’in her bağlantı için harcadığı sabit bellek miktarı yüksektir. Daha önce ele aldığım PostgreSQL index stratejileri yazımda belirttiğim gibi, pgvector sorguları çalışırken connection pool limitlerinizi çok sıkı tutmalısınız; aksi takdirde sorgu anında bellek yetersizliğinden PostgreSQL crash edebilir.

Dedicated Vektör Veritabanları: Qdrant ve Milvus Karşılaştırması

Veri boyutunuz 5-10 milyon vektörün üzerine çıktığında veya anlık saniyede binlerce sorgu (QPS) hedeflediğinizde, PostgreSQL artık yetersiz kalmaya başlar. Burada devreye özel olarak bu iş için yazılmış Qdrant (Rust ile geliştirildi) ve Milvus (Go/C++ karması) giriyor.

Qdrant, özellikle bellek yönetimi ve kaynak tüketimi konusunda inanılmaz optimize bir motor. Rust’ın getirdiği bellek güvenliği ve çöp toplayıcı (garbage collector) olmaması avantajı sayesinde, boşta beklerken neredeyse sıfır RAM tüketiyor. Milvus ise daha çok Kubernetes üzerinde yatayda ölçeklenebilen, mikroservis mimarisine sahip devasa yapılar için tasarlanmış.

Aşağıdaki tabloda, 1M / 1536-dim vektör ile aynı donanım üzerinde üç motoru karşılaştırdığımda gözlemlediğim genel eğilimleri görebilirsiniz (kesin rakamlar donanıma, indeks parametrelerine ve veri dağılımına göre değişir):

Metrik (1M Vektör, 1536-dim) PostgreSQL (pgvector) Qdrant (HNSW) Milvus (HNSW)
İndeks Oluşturma Süresi En yavaş En hızlı Orta
Arama Gecikmesi (p95) En yüksek En düşük Orta
Bellek Tüketimi (RAM) En yüksek En düşük Orta
Disk Tüketimi En yüksek En düşük Orta

Qdrant’ın bellek tüketimini bu kadar düşük tutabilmesinin sebebi, vektörleri bellek üstünde sıkıştırabilen Scalar Quantization (SQ) teknolojisini çok başarılı uygulamasıdır. Eğer bütçeniz kısıtlıysa ve tek bir VPS üzerinde maksimum performansı almak istiyorsanız, tercihinizi kesinlikle Qdrant’tan yana kullanmalısınız.

Index Yapılandırma Parametreleri ve Performans Trade-off’ları

Vektör arama motorlarında sihirli bir “en iyi ayar” yoktur. Hız, doğruluk ve bellek üçgeninde birinden feragat etmek zorundasınız. HNSW indekslerinde en kritik üç parametre şunlardır: m, ef_construction ve ef_search.

  • m: Grafik yapısındaki her bir düğümün (node) sahip olabileceği maksimum bağlantı sayısıdır. Genelde 4 ile 64 arasında seçilir. Değer büyüdükçe arama doğruluğu artar ama bellek tüketimi katlanır.
  • ef_construction: İndeks oluşturulurken taranacak komşu sayısını belirler. Büyük değerler indeksi daha kaliteli hale getirir ancak indeksleme süresini dramatik şekilde uzatır.
  • ef_search: Arama anında dinamik olarak değiştirilebilen bir parametredir. Yüksek değerler doğruluğu artırırken, saniye başına işlenen sorgu miktarını (QPS) düşürür.
// Qdrant için optimize edilmiş HNSW ve Quantization konfigürasyonu
{
  "hnsw_config": {
    "m": 16,
    "ef_construct": 100,
    "full_scan_threshold": 10000
  },
  "quantization_config": {
    "scalar": {
      "type": "int8",
      "quantile": 0.99,
      "always_ram": true
    }
  }
}

Yukarıdaki Qdrant JSON konfigürasyonunda int8 quantization uygulayarak 32-bit float vektörleri 8-bit tamsayılara dönüştürdük. Bu basit hamle, arama doğruluğunda kabul edilebilir küçük bir kayba yol açarken, RAM tüketimini kabaca dörtte birine indirir. Bu, yüksek RAM gerektiren bir projeyi belirgin ölçüde daha az bellekle ayağa kaldırabileceğiniz anlamına gelir.

Hibrit Arama (Hybrid Search) ve Reranking Maliyeti

Sadece vektör tabanlı semantik arama yapmak her zaman en doğru sonucu üretmez. Özellikle ürün kodları, seri numaraları veya spesifik marka isimleri aranırken vektörler çuvallar. Bu yüzden modern mimarilerde “Hybrid Search” (Sparse + Dense) kullanıyoruz. Yani klasik BM25 (text search) ile yoğun vektör arama sonuçlarını birleştiriyoruz.

Ancak bu birleştirme işlemi sistem kaynaklarına ek yük getirir. İki farklı kaynaktan gelen sonuçları sıralamak için bir Cross-Encoder (Reranker) modeli kullanmak gerekir. Reranking işlemi CPU veya GPU üzerinde ciddi bir gecikme (latency) yaratır.

# Reranker modelini her sorguda çağırmak yerine eşik değer koyun
def hybrid_search(query, limit=50):
    # 1. Aşama: Hızlı vektör ve metin araması yap (Recall aşaması)
    vector_results = qdrant_client.search(collection_name="products", query_vector=get_embedding(query), limit=limit)
    text_results = postgres_client.search_text(query, limit=limit)
    
    combined_results = merge_results(vector_results, text_results)
    
    # 2. Aşama: Sadece ilk 10 sonucu Rerank et (Precision aşaması)
    if len(combined_results) > 10:
        reranked = reranker.compute_score(query, combined_results[:10])
        return reranked
    return combined_results

Eğer tüm aday kümesini (örneğin yüzlerce sonucu) Cross-Encoder modeline gönderirseniz, sorgu süreniz hızla kabul edilemez seviyelere çıkar. Yukarıdaki kod bloğunda uyguladığım iki aşamalı filtreleme yöntemi sayesinde, p95 gecikmesini düşük seviyede tutmayı başardım. Detaylı bilgi için RAG mimarisi dökümanımıza göz atabilirsiniz.

Gerçek Bir Senaryo: 2 Milyon Dokümanlık Veri Setinde Maliyet Analizi

Geliştirdiğim bir yan ürünün backend altyapısında, milyonlarca dokümanın semantik arama indeksini tutmam gerekiyordu. Başlangıçta popüler bir bulut vektör veritabanı servisinin başlangıç paketini kullandım. Ancak veri büyüdükçe aylık fatura kayda değer şekilde kabardı. Yan ürünün geliri henüz bu faturayı karşılayacak seviyede olmadığı için hemen alternatif bir mimariye geçiş yaptım.

Kendi kiraladığım bol RAM’li bir bare-metal sunucuya Qdrant kurulumu yaptım. Docker Compose üzerinde limitleri belirleyerek kaynak tüketimini kontrol altına aldım:

version: '3.8'

services:
  qdrant:
    image: qdrant/qdrant:v1.8.0
    container_name: qdrant_node
    ports:
      - "6333:6333"
    volumes:
      - ./qdrant_storage:/qdrant/storage
    deploy:
      resources:
        limits:
          memory: 16g
        reservations:
          memory: 8g
    restart: always

Bu geçiş sonrasında aylık maliyetim yalnızca sunucu kirasına, yani önceki faturanın küçük bir kesrine düştü. Üstelik Qdrant’ın disk tabanlı indeksleme (on-disk payload) özelliğini aktif ederek, RAM kullanımını rahat bir sınırda sabitlemeyi başardım.

Sonuç: Hangi Koşulda Hangi Veritabanı?

Vektör veritabanı seçimi yaparken projenizin ölçeğini dürüstçe değerlendirmeniz gerekir. Eğer halihazırda PostgreSQL kullanıyorsanız ve veri setiniz küçükse, fantezi aramaya gerek yok; pgvector ile yola devam edin. Ancak bağımsız, yüksek performanslı ve düşük maliyetli bir arama altyapısı kurmak istiyorsanız, benim bu süreçteki net tercihim her zaman Qdrant yönündedir.

Bir sonraki yazımda, büyük dil modellerinde (LLM) bağlam penceresini (context window) optimize etmek için kullandığım gelişmiş chunking stratejilerini ve bu stratejilerin vektör arama doğruluğuna doğrudan etkisini inceleyeceğim.

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.

Vektör veritabanına ilk adımda hangi araçları kurup, hangi testleri yapmalıyım?
Ben öncelikle bir yerel Docker ortamı kurdum; pgvector, Qdrant ve Milvus'un resmi imajlarını aynı ağda çalıştırdım. Ardından aynı veri seti (1 M 1536‑boyutlu vektör) ile basit bir “insert‑and‑search” senaryosu oluşturdum. Her bir DB’ye aynı indeks parametrelerini (ör. HNSW‑M=16, ef=200) vererek, RAM kullanımını `htop` ve DB’nin kendi istatistik API’larıyla izledim. Sonra sorgu latency ve recall ölçmek için `ann-benchmarks` gibi açık kaynak araçlarıyla 1000 rastgele sorgu çalıştırdım. Bu adımlar, hem maliyet hem de performans açısından hangi çözümün projenize daha uygun olduğunu hızlıca görmenizi sağlar.
HNSW ve IVF indekslerinin avantajları ve dezavantajları nedir? Hangi senaryoda birini diğerine tercih etmeliyim?
Ben HNSW’yi yüksek doğruluk ve milisaniye altı gecikme istediğim gerçek‑zamanlı aramalarda tercih ettim; ancak grafın tüm düğümleri RAM’de tutulduğu için 1 M 1536‑boyutlu vektörde ek 2‑3 GB RAM gerekir. IVF ise veriyi diskten okur, bu yüzden RAM tüketimi %60‑70 azalır, ama sorgu süresi genellikle 5‑10 ms artar ve recall biraz düşer. Eğer bütçeniz kısıtlı ve sorgu hızı kritik değilse, IVF + bir kaç “probe” değeri ile dengeyi kurabilirsiniz. Ancak yüksek trafikli bir e‑ticaret öneri motoru gibi durumlarda, ek RAM karşılığında HNSW’nin düşük latency’si daha çok değer kazanır.
İndeks oluştururken Sunucu Out‑Of‑Memory (OOM) hatası alırsam ne yapmalıyım?
Ben ilk olarak Docker‑compose dosyamda `mem_limit` ve `ulimit -v` değerlerini artırdım; bu, konteynerin RAM sınırını genişletir. Sonra HNSW parametrelerini `M` ve `efConstruction` düşük değerlere (ör. M=12, ef=100) çekerek grafik boyutunu küçülttüm. Ayrıca veri setini parçalara bölüp toplu insert yaptıktan sonra indeksleme adımını ayrı bir batch olarak çalıştırdım. Eğer hâlâ OOM alıyorsam, IVF’ye geçiş yapıp disk‑tabanlı bir yapı denedim; bu, bellek tüketimini %40‑50 düşürürken performansta kabul edilebilir bir kayıp sağlar. İzleme araçlarıyla bellek kullanımını sürekli kontrol etmek de sorunu erken fark etmenize yardımcı olur.
Vektör arama maliyetinin CPU’dan ziyade RAM’e bağlı olduğu iddiası doğru mu?
Evet, benim deneyimlerim bu iddiayı doğruluyor. Başlangıçta sadece CPU’ya odaklanıp daha hızlı bir işlemci seçmiştim, ancak 1 M vektörle HNSW indeksi oluşturduğumda RAM %80‑90 dolu olduğunda sistem sık sık swap yapmaya başladı ve latency 10‑kat arttı. RAM, tüm vektör ve indeks grafiğini tutmak zorunda olduğu için doğrudan maliyet belirleyicidir; özellikle bulut ortamlarında RAM‑GB başına fiyatlar CPU‑core’dan daha yüksek olur. Dolayısıyla bütçenizi planlarken, sorgu hızı için yüksek CPU yerine yeterli RAM kapasitesine ve onun ölçeklenebilirliğine yatırım yapmanız uzun vadede daha ekonomik sonuç verir.
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