AWS Bedrock ile Embedding Performansını %3000 Artırmak: Senkronizasyondan Asenkronizasyona Geçiş
RAG pipeline süreçlerinde embedding çağrılarını optimize ederek 50 saniyelik işlem süresini 1.5 saniyeye indirdik. Teknik detaylar ve performans analizleri burada.
RAG Pipeline'larında Gizli Darboğaz: I/O Bekleme Süreleri
Modern AI uygulamalarının temel taşı olan RAG (Retrieval-Augmented Generation) sistemlerinde, veriyi vektör veri tabanına aktarma (ingestion) aşaması çoğu zaman göz ardı edilen bir performans darboğazıdır. Birçok geliştirici, sistemindeki yavaşlığın CPU yetersizliğinden veya modelin yanıt süresinden kaynaklandığını düşünür. Ancak gerçek suçlu genellikle sekansiyel HTTP istekleri ve buna bağlı olarak gelişen "boşa geçen" işlemci zamanlarıdır.
Geçtiğimiz günlerde gerçekleştirdiğimiz bir benchmark çalışmasında, sadece tek bir dosyanın embedding işlemlerini gerçekleştirirken karşılaştığımız şok edici sonuçlar, basit bir kod değişikliğinin nasıl devasa bir fark yaratabileceğini kanıtladı: 49.61 saniyeden 1.56 saniyeye düşüş.
Problem Analizi: Neden Bu Kadar Yavaş?
Senaryomuzda, tek bir dokümandan elde edilen 33 farklı metin parçası (chunk) kullanıldı. Kullanılan model Amazon Titan Text Embeddings V2 ve bölge ise us-east-1 olarak belirlendi.
Senkron (Blocking) Yaklaşım
Klasik bir for döngüsü içerisinde her bir metin parçası için API çağrısı yapıldığında süreç şu şekilde işler:
- İstek gönderilir $\rightarrow$ 2. Network gecikmesi yaşanır $\rightarrow$ 3. Bedrock yanıt üretir $\rightarrow$ 4. Yanıt alınır $\rightarrow$ 5. Bir sonraki parçaya geçilir.
Bu süreçte CPU kullanımı neredeyse sıfırdır çünkü uygulama sadece ağdan gelecek cevabı beklemektedir. CPU, kapasitesinin %1'ini bile kullanmazken saatler süren ingestion işlemleriyle vakit kaybedersiniz.
Çözüm: Asenkron (Non-blocking) İş Akışları
Çözüm, blocking (engelleyici) yapıyı asyncio ve asenkron HTTP kütüphaneleriyle değiştirmektir. Asenkron yapıda, uygulama ilk isteğin cevabını beklemeden ikinci, üçüncü ve diğer tüm istekleri aynı anda (concurrently) gönderir.
Performans Karşılaştırması
| Yaklaşım | Toplam Süre | Hız Artışı | CPU Durumu |
|---|---|---|---|
| Senkron Çağrılar | 49.61 sn | 1x | Boşta (Idle) |
| Asenkron Çağrılar | 1.56 sn | ~31.8x | Aktif/Verimli |
Teknik Uygulama ve Mimari Stratejiler
Sadece uygulama kodunu değiştirmekle kalmayıp, AWS ekosistemindeki farklı optimizasyon yöntemlerini de değerlendirmek gerekir:
1. Uygulama Katmanında Optimizasyon
Python'da aiohttp veya httpx gibi kütüphaneler kullanarak Bedrock API çağrılarını paralel hale getirebilirsiniz.
import asyncio
import httpx
async def get_embedding(client, text):
# AWS Bedrock API çağrısını simüle eden asenkron fonksiyon
response = await client.post("https://bedrock-runtime.us-east-1.amazonaws.com/...", json={"text": text})
return response.json()
async def main(chunks):
async with httpx.AsyncClient() as client:
tasks = [get_embedding(client, chunk) for chunk in chunks]
embeddings = await asyncio.gather(*tasks)
return embeddings
2. Veritabanı ve Tetikleyici (Trigger) Stratejileri
Amazon Aurora PostgreSQL gibi sistemlerde embedding oluşturma işlemleri için iki ana yol vardır:
- Senkron Tetikleyiciler (
aws_mlextension): Basit kurulum sağlar ancak herINSERTişlemi embedding üretilene kadar bekler. Bu durum, yüksek hacimli işlemlerde kilitlenme (lock contention) ve performans kaybına yol açar. - Asenkron Lambda Tetikleyicileri (
aws_lambdaextension): Embedding üretimini ana işlemden ayırır (decoupling). Veri tabanı performansı artar; ancak veri ile vektörü arasında geçici bir tutarsızlık (eventual consistency) oluşabilir.
3. Bedrock Altyapı Optimizasyonları
Kod optimizasyonunun yanı sıra AWS'nin sunduğu şu özellikler de kritik öneme sahiptir:
- Latency Optimized Inference: Bedrock'un önizleme aşamasındaki bu özelliği ile standart çıkarım sürelerini optimize ederek daha düşük gecikme süreleri elde edilebilir.
- Cross-Region Inference Profiles: Tek bir bölgedeki limitlere (throttling) takılmamak için istekleri farklı bölgelere dağıtarak toplam throughput'u artırabilirsiniz.
Sonuç ve Değerlendirme
Sadece bir dosyayı (embedding modülünü) senkrondan asenkrona çevirerek elde ettiğimiz 31.8 katlık hız artışı, modern bulut mimarilerinde "bekleme sürelerinin" ne kadar maliyetli olduğunu kanıtlıyor.
Kısacası:
- Eğer CPU kullanımınız düşük ama yanıt süreleriniz yüksekse, problem işlem gücü değil I/O yönetimidir.
- RAG pipeline'larınızda toplu veri işleme yapıyorsanız
asynciokaçınılmazdır. - Ölçeklenme aşamasında Aurora'nın asenkron Lambda entegrasyonlarını ve Bedrock'un
latency-optimizedparametrelerini mutlaka değerlendirin.