Metasearch'te Cache ve Price Freshness
Travel metasearch için cache ve price-freshness stratejisini gerçek search load, adaptive TTL, live recheck, stale-price risk, observability ve production trade-off'larıyla tasarlayın.
Bir travel metasearch sistemi için cache problemi “fiyatı kaç dakika saklayalım?” kadar basit değildir. Asıl tasarım problemi latency, supplier maliyeti, coverage ve kullanıcı güveni arasında denge kurmaktır. Çok agresif live query yapmak pahalı ve yavaş olabilir; çok uzun cache ise click sonrası price mismatch ve sold-out riskini artırır.
Gerçek bir senaryo düşünelim: 150.000 hotel, 6 supplier ve saniyede yüzlerce search. Her search'te tüm provider'ları live çağırırsanız p95 latency birkaç saniyeye çıkabilir ve upstream rate limit'lere çarpabilirsiniz. Her offer'ı 30 dakika cache'lerseniz performans iyileşir ama check-in'e yakın ve volatile property'lerde stale-rate oranı hızla yükselir. Çözüm tek bir TTL değil, context-aware freshness policy tasarlamaktır.
Price freshness neden ürün problemi olarak ele alınmalı?
Freshness doğrudan trust ve conversion ile ilişkilidir. Kullanıcı sonuç ekranında 4.800 TL görüp provider landing'de 5.450 TL ile karşılaşırsa teknik olarak “cache hit” başarılı olabilir; ürün açısından ise sistem yanlış beklenti yaratmıştır.
Freshness bu nedenle en az üç boyutta izlenmelidir:
- technical freshness: data kaç dakikalık?
- commercial freshness: price hâlâ geçerli mi?
- transactional freshness: kullanıcı click/booking anında aynı offer'ı bulabiliyor mu?
Sadece cache age ölçmek yeterli değildir. Aynı yaşta iki price farklı volatility'ye sahip olabilir.
Indicative ve live price nasıl ayrılmalı?
Indicative price exploration ve discovery için uygundur; live price ise transaction'a yaklaşan context'te daha güçlü doğruluk beklentisi taşır. Skyscanner indicative ürünlerinde cached/estimated price yaklaşımını açıkça ayırırken, Google Hotels de cache ve live pricing query modellerini farklı kullanım senaryolarında kullanır.
Internal modelde source açık olmalıdır:
type PriceSource = "indicative" | "cached-live" | "live";
interface PriceObservation {
providerId: string;
propertyId: string;
itineraryKey: string;
amount: number;
currency: string;
observedAt: string;
expiresAt: string;
source: PriceSource;
roomId?: string;
ratePlanId?: string;
availabilityCheckedAt?: string;
confidence: number;
}UI ve ranking aynı numeric price'ı görse bile backend bu source farkını kaybetmemelidir.
Cache key nasıl tasarlanmalı?
Yanlış cache key, uzun TTL'den daha tehlikeli olabilir. Hotel price için yalnız property ID kullanmak ciddi collision yaratır. Minimum context çoğu zaman şunları içerir:
provider
+ property
+ check-in
+ nights
+ occupancy
+ room count
+ market
+ currency
+ eligibility/rate-rule contextChildren age, member rate veya country-specific price gibi koşullar varsa key'e dahil edilmelidir.
Aksi halde teknik olarak “hit” aldığınız cache başka bir user's context'ine ait olabilir.
Tek global TTL neden yetersizdir?
Price volatility her offer'da aynı değildir. Yarın check-in yapılacak 4-room-remaining bir property ile altı ay sonraki yüksek inventory'li resort aynı freshness threshold'u kullanmamalıdır.
Adaptive TTL şu sinyalleri kullanabilir:
- check-in proximity,
- historical mismatch rate,
- historical price-change frequency,
- supplier,
- property popularity,
- search/click volume,
- remaining inventory signal,
- event/holiday period,
- booking window,
- campaign/promotion flag.
Örnek policy:
check-in <= 2 gün => base TTL 2 dk
check-in <= 7 gün => base TTL 5 dk
check-in <= 30 gün => base TTL 15 dk
check-in > 30 gün => base TTL 60 dk
provider mismatch > %5 => TTL x 0.50
high click volume => refresh priority +2
sold-out risk high => TTL x 0.50
stable supplier/property => TTL x 1.50Bu değerler universal değildir; first-party mismatch ve latency data ile kalibre edilmelidir.
Refresh priority nasıl tasarlanmalı?
Tüm cache key'leri aynı anda refresh etmek mümkün olmayabilir. Bu yüzden freshness yalnız TTL değil, scheduler problemidir.
Basit bir priority score:
priority =
search_volume_weight
+ click_volume_weight
+ checkin_proximity_weight
+ mismatch_history_weight
+ revenue_weight
- recent_refresh_penaltyQueue consumer en yüksek score'lu offer/context kombinasyonlarını önce refresh edebilir.
Bu model özellikle large hotel catalog'larında “her şeyi sık refresh et” yaklaşımından daha ekonomiktir.
Stale-while-revalidate nerede mantıklıdır?
Browse ve inspiration use case'lerinde yakın zamanda gözlemlenmiş cached data hemen gösterilip arkada refresh edilebilir. Kullanıcı karar anına yaklaştıkça policy sıkılaşmalıdır.
Örnek:
Destination page -> indicative/cached acceptable
Search result -> fresh cached preferred
Offer detail -> stricter freshness
Provider click -> optional live recheck
Booking ownership -> transaction-time validationAynı cache policy'nin bütün funnel'da kullanılması kullanıcı intent'ini görmezden gelir.
Click-time live recheck ne zaman gerekli?
Her click'te live validation latency ve supplier cost yaratabilir. Ancak şu durumlarda daha anlamlı olabilir:
- check-in çok yakınsa,
- supplier'ın mismatch geçmişi yüksekse,
- cached price age threshold'u geçmişse,
- high-value booking ise,
- low inventory sinyali varsa,
- promotion/conditional rate söz konusuysa.
Live recheck sonucunda price değişirse product'ın davranışı önceden tanımlı olmalıdır:
- yeni price göster,
- offer'ı tekrar rank et,
- alternatif provider sun,
- büyük farkta handoff'u durdur.
“Price değişti, yine de redirect et” de bir ürün kararıdır; sessizce olmamalıdır.
Failure mode'lar nelerdir?
Cache stampede
Popular key expire olduğunda yüzlerce request aynı supplier'ı çağırır. Single-flight, lock veya background refresh gerekir.
Poisoned cache
Yanlış occupancy veya tax semantics ile gelen offer cache'e yazılır ve yüksek hit rate ile hata yayılır.
Provider outage sırasında stale veri
Supplier down olduğunda stale cache kullanmak coverage sağlar ama freshness riskini artırır. Stale-if-error policy açık olmalıdır.
Clock/timestamp problemi
Provider timestamp, server time veya timezone yanlış yorumlanırsa offer gerçekte olduğundan fresh görünebilir.
Silent fallback
Live query timeout olur ve cached data döner, fakat response'ta fallback bilgisi kaybolur. Operasyon ekibi “live coverage”ı fazla iyi zanneder.
Hot-key starvation
Scheduler yalnız popüler property'leri refresh eder; long-tail sürekli stale kalır. Minimum coverage quota gerekebilir.
Cache ve price accuracy nasıl birbirine bağlanmalı?
Mismatch yalnız raporlanmamalı, refresh policy'ye feedback vermelidir.
Örnek loop:
Displayed cached price
|
v
Provider landing check
|
+--> matched
| |
| +--> confidence ↑
|
+--> mismatch
|
+--> reason taxonomy
+--> provider/property volatility ↑
+--> effective TTL ↓
+--> refresh priority ↑Google'ın price-accuracy verilerinde tax mismatch, room unavailable, delayed feed ve wrong itinerary gibi mismatch reason'lar bulunması, root-cause taxonomy'nin neden önemli olduğunu gösterir.
Hangi metrikler izlenmeli?
Cache sağlığı
- cache hit ratio,
- miss ratio,
- stale-while-revalidate usage,
- refresh queue depth,
- refresh age p50/p95,
- hot-key rate.
Freshness
- offer age p50/p95,
- live/cached/indicative ratio,
- threshold-overrun rate,
- provider/property freshness distribution.
Business quality
- price mismatch rate,
- unavailable-after-click,
- mismatch by cache-age bucket,
- conversion by freshness bucket,
- revenue by freshness bucket,
- click abandonment after reprice.
Supplier cost
- live requests per search,
- API quota usage,
- provider timeout rate,
- refresh cost per successful booking.
Cache hit ratio tek başına optimize edilmemelidir. %95 hit ratio, %12 mismatch ile kötü sonuç olabilir.
Trade-off nasıl değerlendirilir?
Üç policy düşünelim:
| Policy | Latency | Supplier cost | Freshness risk |
|---|---|---|---|
| Her zaman live | Yüksek | Yüksek | Düşük |
| Uzun fixed TTL | Düşük | Düşük | Yüksek |
| Adaptive cache + selective live | Orta/Düşük | Orta | Kontrollü |
Çoğu production metasearch için üçüncü yaklaşım daha esnektir, ancak complexity getirir. Adaptive policy ancak observability varsa anlamlıdır; ölçemediğiniz volatility'ye göre TTL ayarlayamazsınız.
Ne zaman cache kullanmamak gerekir?
Cache her durumda doğru çözüm değildir. Şu durumlarda live-first model değerlendirilebilir:
- supplier response çok hızlı ve ucuzsa,
- inventory son derece kıtsa,
- offer token çok kısa ömürlüyse,
- booking ownership sizdeyse,
- regulation/contract live validation gerektiriyorsa.
Buna karşılık inspiration, trend ve broad-date exploration use case'lerinde full-live architecture gereksiz pahalı olabilir.
Production checklist
- Cache key search context'i tam temsil ediyor mu?
- Her price'ın observedAt/source alanı var mı?
- Live ve indicative data ayrılıyor mu?
- TTL provider ve check-in proximity'ye göre adapte olabiliyor mu?
- Cache stampede koruması var mı?
- Stale-if-error policy tanımlı mı?
- Live timeout sonrası fallback görünür mü?
- Click-time validation trigger'ları net mi?
- Mismatch reason policy'yi etkiliyor mu?
- Freshness bucket bazında conversion izleniyor mu?
- Long-tail starvation kontrol ediliyor mu?
- Supplier cost ile user trust aynı dashboard'da görülebiliyor mu?
Meta Search yorumu
İyi cache tasarımı “en yüksek hit ratio”yu hedeflemez. Amaç doğru context'te yeterince fresh offer'ı, kabul edilebilir latency ve supplier cost ile sunmaktır. Freshness metadata, adaptive TTL, priority refresh ve mismatch feedback birlikte çalıştığında cache infrastructure optimizasyonundan çıkıp doğrudan product-quality mekanizmasına dönüşür.
Bu problemi production’da mı yaşıyorsunuz?
Semptomu, veri akışını ve entegrasyon davranışını birlikte teknik olarak inceleyebiliriz.