1 puan yazan GN⁺ 4 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • Önbellek, veritabanı yükünü azaltmak için devreye alınır; ancak Redis gibi kullanımı kolay araçlara zamanla kalıcı bir depoymuş gibi bağımlı hale gelmek kolaydır
  • Sorun Redis'in kalıcılık özelliği değil, başlangıçta geçici bir önbellek olarak eklenen bir bileşenin uygulamanın çekirdek durumu ile iç içe geçmesidir
  • memcached, resmi tanımında zaten dağıtık bellek içi nesne önbellekleme sistemidir ve diske yazmayı temel almadığı için durumsuz önbellek iş yükü olarak ele almak daha kolaydır
  • Birden fazla memcached instance'ı sunucu tarafından değil, istemci tarafından URL listesi ve anahtar hash'i ile bölüştürülür; arızalı düğüm hash mekanizmasından çıkarılır ve daha sonra yeniden bağlanmayı dener
  • “Veritabanı yavaş” diye önce önbellek eklemek yerine, önce yavaş sorgulara ve eksik indekslere bakmak gerekir

Redis'in önbellekten depoya dönüştüğü an

  • Altyapı işletirken “önbelleğe ihtiyacımız var” talebi sık gelir ve tanıdık, özellik açısından zengin Redis'in akla önce gelmesi kolaydır
  • Redis ana sayfası, yapay zeka uygulamaları için gerçek zamanlı bağlam motoru olan Redis Iris'i öne çıkarıyor; ancak Redis'in gelir üretmek zorunda olan bir şirket olduğu düşünülürse bu yön anlaşılabilir
  • Redis'i dağıtıp bağlantı dizesini verdiğinizde, başta güvenilir bir önbellek gibi çalışır

Birkaç ay sonra ortaya çıkan sorunlar

  • Zaman geçince cache.set("key", "value"), INSERT INTO table VALUES ('key', 'value') komutundan çok daha basit kaldığı için insanlar Redis'i şu şekilde görmeye başlar
    • Her zaman var olan bir bileşen, verinin korunduğu yer; fiilen bir veritabanı
    • REmote DIctionary Server artık geçici bir önbellek değil, kalıcı bir depo gibi algılanır
  • Siz de, operasyon ekibindeki çalışma arkadaşlarınız da bunun farkında olmazsınız; herkes önbelleğin geçici olduğu varsayımıyla hareket ettiği için uyarı (alerting) sistemi de bunu yakalayamaz
    • Ancak Redis üzerinde bir şey yaptığınızda, örneğin yükseltme, düğüm taşıma ya da RAID0 sunucu HDD tepsisinin çıkması gibi bir olay olduğunda sorun görünür hale gelir
  • Temel sorun Redis'te kalıcılık özelliği bulunmaması değil, önbellek olarak devreye alınan Redis'in insanlar tarafından önbellek gibi ele alınmamasıdır
  • Bu bağımlılığı geç fark ettiğinizde Redis uygulamaya fazla derinden bağlanmış olur, çıkarması zorlaşır ve sonunda bir “evcil hayvan” gibi bakımını yapıp izlemek zorunda kalırsınız

memcached'in önbellek rolüne daha doğrudan uymasının nedeni

  • memcached, “ücretsiz açık kaynaklı, yüksek performanslı, dağıtık bellek içi nesne önbellekleme sistemi”dir; veritabanı yükünü azaltarak dinamik web uygulamalarını hızlandırmak için kullanılan genel amaçlı bir önbellektir
  • Django gibi takılabilir önbellekleme destekleyen framework'lerde önbellek backend'i değiştirilebilir
  • Redis'ten daha az özelliğe sahip olsa da memcached'i seçmek için neden, operasyonel davranışının daha basit olmasıdır
    • Kesinti yönetimi kolaydır: istemci kütüphaneleri çoğu zaman bağlantı istisnalarını yok sayar ve basit bir get, sunucu kapalı olsa bile varsayılan değer ya da None döndürebilir
    • memcached'te gömülü clustering özelliği olmaması, ironik biçimde clustering işini kolaylaştırır
      • İstemci kütüphanesine birden fazla URL verildiğinde, hedef instance anahtar hash'ine göre seçilir
      • İstemci çağrısı instance'ın kapandığını algılarsa düğümü hash mekanizmasından çıkarır ve belirli bir süre sonra otomatik olarak yeniden bağlanmayı dener
    • Kalıcılık yükü yapısal olarak daha düşüktür: memcached diske yazmaz, bu yüzden durumsuz iş yükü olarak istenen yere zamanlamak kolaydır
  • Redis ile de benzer bir işletim biçimi kurulabilir; ancak memcached'in mimarisi bu yöne daha yakındır ve onu önbellek olarak ele almayı daha sezgisel hale getirir
  • memcached nispeten basit bir uygulamadır ve yaklaşık 64MB önbellek boyutuna sahip onlarca instance çalıştırıldığında bile ek yük neredeyse yoktur; bu da onu tercih etme nedenlerinden biridir
  • Birçok “veritabanı yavaş” sorunu aslında yavaş sorgular veya eksik indekslerle başlar; bu yüzden önbellek eklerken sorgu optimizasyonuna da bakmak gerekir
  • memcached'in tasarım kararlarını merak ediyorsanız memcached blog'unda çok sayıda ilginç yazı var; bunlardan biri de mayısta yayımlanan “Bir Yanıtın Gelmesi Gerçekte Ne Kadar Sürüyor? (How Long Does That Response Take… For Real?)” yazısıdır

1 yorum

 
GN⁺ 4 시간 전
Hacker News görüşleri
  • Redis harika bir teknoloji, ancak kalıcı veri yapıları ile geçici cache gibi iki farklı rolü aynı anda iyi yapmaya çalışırken zorlandığını düşünüyorum
    Redis’in kendisinde bile bu ikisi iyi karışmıyor; kalıcılık global olarak açılıp kapatılıyor
    Saf cache için memcached veya dengi bir şeyi kullanır, skor tablosu gibi veri yapıları gerektiğinde ise yalnızca kalıcılığı açık Redis kullanırdım
    $WORK içinde ikisini de devreye almadık; yavaş işler için cache katmanı olarak veriyi hem dosya sisteminde hem de anahtar-değer deposu gibi kullandığımız DB tablolarında tutuyoruz
    DB, thundering herd durumunu koordine etmeye yardımcı oluyor; aynı sunucudaki okumalar yalnızca dosya sistemine gidiyor, diğer sunuculardaki okumalar ise DB’ye bir kez baktıktan sonra dosya sisteminde tutuluyor
    Dosya sistemi katmanını memcached ile değiştirebilirdik ama şimdiye kadar gayet iyi çalışıyor

    • 2000’lerin sonlarında Memcachedb (memcache + kalıcılık için bdb) ile uğraştıktan sonra neredeyse aynı sonuca vardım
      Redis’in kesinlikle daha fazla özelliği vardı ve antirez de hem çekici hem de şaşırtıcı derecede mütevazı biriydi; bu yüzden Redis’in neden daha popüler hale geldiğini anlıyorum
      Yine de benim için memcached her zaman sıkıcı teknolojiyi seç yaklaşımının zirvesiydi
      Platform mühendisi olarak ikisini de destekleyebilirim, ama geliştiriciler Redis’in kalıcılık, replikasyon, clustering gibi gelişmiş özelliklerini kullanmaya başladığında, bu kararın dezavantajlarını gerçekten anlayıp anlamadıklarını kontrol etmeye çalışırım
    • DB tablolarını anahtar-değer deposu gibi kullanıp yanına dosya sistemini ekleyerek bile, özel bir cache deposu kurmanın maliyetine katlanmadan önce yapılabilecek gerçekten çok şey var
      Böyle çözümler önerdiğim her seferinde, cache’in mutlaka özel bir depoda olması gerektiğini düşünen tecrübesiz insanlarla ve mühendislik ortamlarında sayısız kez tartıştım
  • Buna memcache demek bu sorunlardan kaçınabileceğiniz anlamına hiç gelmiyor
    2000’lerin ortasında memcache kullanan ölçekli bir sistemi yönetiyordum; geliştiriciler yazıda Redis örneği için verilen sorunlarla tamamen aynı tuzaklara düştü
    Memcache ile dağıtık sistemlerin kurallarını aşmaya çalıştılar ve cache bağımlılığı nedeniyle sunucu kümesinin boyutunu memcache’in çalışıyor olacağı varsayımıyla belirlediler; arıza olduğunda ise bir anda DDoS gibi patlıyordu
    Bazı host’lar TPS’si yüksek anahtarları düşürdüğünde, diğer tüm host’ların bu anahtarları yeniden doldurmak için bağımlı servise yüklenmesine yol açan write amplification vardı; hot key’ler hot host’lar yarattı ve memcached’i servis daemon’uyla birlikte çalıştırmak açıklanamayan CPU sıçramalarına neden oldu
    Eski DNS kayıtlarının inatçı şekilde kalması yüzünden memcache çağrıları bazen kara deliğe gidiyordu
    Bunların hepsi memcache daha iyi kullanılsa önlenebilirdi, ama kötüye kullanma cazibesi çok güçlüydü

  • Yazarın bahsettiği Redis/Valkey sorunlarının neredeyse hepsini prodüksiyonda gördüm sanırım
    Valkey’de bellek politikası olmadığı için tüm belleği tüketip append-only file yazma hatası üreten bir kesinti yaşadık; diskin tamamen dolduğu için AOF yazımının başarısız olduğu durumlar da oldu
    Redis’in canlı, çalışır durumda ve tüm kullanıcı verileriyle dolu olacağına tamamen güvenildiği, ama yavaş yola geri dönecek hiçbir mekanizma bulunmadığı için 500 hatalarının çıktığı durumlar da gördüm
    Sıralı kümeler ve başka veri yapılarını yaratıcı biçimde kullanıp o kümelerin asla tahliye edilmeyeceğine güvenen örnekler de vardı
    Sahadaki bu gözlemlere rağmen, Redis yerine önce memcache önermenin hâlâ zor olduğunu düşünüyorum
    Uygulamayı memcache dostu bir cache yerleşimiyle tasarlamak zor olabilir ve yeterince büyük bir ekip memcache kullanırsa eninde sonunda Redis’e ihtiyaç duyacak bir yol bulma ihtimalleri çok yüksek
    O zaman da 2 cache teknolojisini birden sürdürmek gerekiyor

    • Biri Redis’i cache dışı amaçla kullanmaya karar verirse, pratikte zaten 2 cache teknolojiniz var demektir
      Cache için yapılandırılmış bir Redis instance’ı başka amaçla kullanılamaz; cache instance’ında tahliye olmalı, cache dışı instance’ta ise tahliye olmamalıdır
      Sonuçta farklı ayarlı ikinci bir Redis gerekir
      Dürüst olmak gerekirse, uygulamayı memcache dostu bir cache yerleşimiyle tasarlamak, Redis dostu bir cache yerleşimiyle tasarlamaktan farklı değil
      Bu tür uygulama cache kalıpları aynıdır: getir, yoksa hesapla ve ayarla
    • Zaten yoksa bir soyutlama arayüzü oluşturup, anahtarı isterken cache miss durumunda kaynaktan değeri alacak asenkron bir fonksiyon ya da lambda geçmeyi tercih ederim
      var value = cache.lookup( keyname, () => db.query(...), TimeSpan.FromMinutes(5) // or CacheOptions );
      Böylece cache miss olduğunda hemen yedek yola gidebilir veya ekleme yapabilirsiniz
    • 2 cache teknolojisini sürdürmemek her zaman kazanan argümandır
  • Memcache hakkında çok konuşulmayan başka bir özellik de tüm işlemlerinin tasarım gereği O(1) olmasıdır
    Yazarların bilinçli olarak seçtiği bu tasarımın kısıtları var, ama basit işlemlerde rastgele duraksamalar yaşanmamasını garanti ediyor
    Buna karşılık Redis’in tek iş parçacıklı çekirdek tasarımı, keyfi karmaşıklıkta işlemler çalıştırabilmesine izin veriyor; geliştirici açısından bunu kullanmak akıllıca hissettirebilir ama o işlem bitene kadar geri kalan her şey beklemek zorunda kalır

  • Açık kaynak projelerinde veya uzun süre bakımı sürdürülen programlarda bu tür şeyler sık olur
    Kod tabanı büyüdükçe, başlangıçta planda olmayan şeyleri sonunda desteklemeye başlarsınız
    Özellikler arttıkça kullanıcılar da artar; kimileri eski özellikleri kullanmaya devam eder, kimileri yenilerini benimser ve sonunda belirli bir değer fiilî varsayılan haline gelir, artık bir seçenek gibi görünmez
    Redis’i örnek alırsak, AOF kapatılırsa uçucu bir bellek içi önbellek gibi çalışır ama çoğu kişi onu böyle düşünmez bile
    Bu yüzden az özellikli ve basit olmanın daha iyi olduğuna dair bir mantık ortaya çıkar; bu bağlamda Memcached, böyle bir kısıtlayıcı yaklaşımın örneğidir
    Büyük ekipler için bu tamamen mantıklıdır, ancak açık kaynak projelerinin fon veya katkı almaya devam edebilmesi için düzenli güncellemeler gerekir; dolayısıyla yapısal bir gerilim vardır
    Bazen bu, belirli bir niş alana uzmanlaşmış fork’lara veya türev projelere yol açar
    Bana göre tek bir doğru cevap yok; bağlama bağlı
    Çünkü iletişimin kendisi de bedava değildir

    • İletişimin bedava olmaması, mikroservisler konusunda benim temel sorunum
      Geliştiriciler bunun hiç farkında değilmiş gibi görünüyor
    • En açık örnek, insanların Redis’in çökme veya kapanma durumunda veri kaybeden bir önbellek olarak çalıştığını düşünmesi
      Bence bunun nedeni, Memcached’i Redis ile değiştirirken aynı davranışı beklemeleri
    • Büyük ölçekte AOF arızalara yol açtığı için kapatılıyor
      Yine de harika bir önbellek
  • Son birkaç yılda epey Flask işi yaptım; tam zamanlı değil ama küçük bir e-ticaret işletmesinin teknoloji yığınının bir parçası olarak kullandım
    MongoEngine, SQLAlchemy, Celery ve Google/eBay/Shopify için Python yığınında türlü türlü mayınlar ve tuhaflıklarla karşılaştım ama Redis’te hiç böyle bir şey yaşamadım
    Belki de bunun sebebi, Redis’i kalıcı veri deposu sanan herkese yönetici yetkisi vermememdir; ama dürüst olmak gerekirse Redis’i son derece sağlam ve iyi tasarlanmış bir teknoloji olarak tanımlamak isterim
    API’si aşırı derecede basit ve biraz sıra dışı bir şey yapmanız gerektiğinde her zaman makul, iyi düşünülmüş bir yol sunuyor

    • Şu anda Flask, SQLAlchemy ve Celery ile bir projeye başlıyorum; neden Celery’den kaçınmak gerektiği ve onun yerine ne kullanılabileceği hakkında daha fazlasını duymak isterim
    • Benim dünyamda memcached ve Redis gibi önbellek sistemleri sadece koyup aldığınız önbelleklerdir
      Etiketleme gibi bir geçersiz kılma sistemi kullanılabilir elbette
      Bir önbellek sistemiyle yapılabilecek sıra dışı şeylerin neler olduğunu, insanların yalnızca veri önbelleklemenin ötesinde önbelleği ne için kullandığını gerçekten merak ediyorum
  • Memcached’i seviyorum ama Redis’i uçucu bir önbellek olarak yapılandırıp insanların ona kalıcı veri deposu gibi davranması Redis’in suçu değil
    Memcached’in de kalıcı olmaması açısından bu karşılaştırma özellikle tuhaf

    • Birçok şirkette, muhtemelen çoğunda, Redis istendiği an kaybolabilecek bir önbellek olarak değil gerçek bir dayanıklı üretim veritabanı olarak görülüyor ve öyle işletiliyor
      Bunu ayrıca belirtmezseniz, yeni bir geliştiricinin de böyle varsayması pek de yersiz değil
  • Memcached, çıktığı dönemde önbelleklemenin kurtarıcısıydı
    2003’te Brad Fitzpatrick tarafından LiveJournal için yapılmış olması da hoş
    Kullanıcı akışındaki her gönderi için erişim kısıtları farklı olabiliyordu ve bu sayede gönderiler ya da tüm sayfalar önbelleğe alınabiliyordu
    Ruby on Rails ile birlikte yıllarca kullandım; sayfaları hızlandırdı ve gayet iyi çalıştı
    Hem dezavantajı hem de hız açısından avantajı, önbelleğin diskte değil bellekte tutulmasıydı
    Önbelleklenecek veri genişse ve siteniz büyük ölçekliyse, barındırma maliyeti yüksek olabilir
    Böyle durumlarda Solid Cache benim için kurtarıcı oldu
    Şu anda üzerinde çalıştığım projede önbellek 100GB’tan büyük; PostgreSQL diskinde tutuluyor, indekslerle hızlıca sorgulanıyor ve Rails süre dolunca ilgili satırları otomatik olarak siliyor
    Önbellek daha küçük ölçekliyse ve zaten Redis kullanıyorsanız muhtemelen ben de doğrudan Redis kullanırdım
    Ama hız birinci öncelikse Memcached ile Redis’i kıyaslamak için benchmark yapardım

  • Memcached’in geçici olması ve insanların onu kalıcıymış gibi kullanıp kullanmaması iki ayrı mesele
    Önbellek isabet oranı %99,9 gibi görünüyorsa ve hep oradaysa, er ya da geç biri bu davranışa bağımlı kod yazacaktır
    Geliştirme modunda istemci kütüphanesinin yaklaşık %10 oranında null döndürmesine yardımcı olmak mümkün olmaz mı diye düşünüyorum

  • memcached, basit anahtar-değer önbelleği işlerinde Redis’ten inanılmaz derecede daha hızlı
    Thread’leri var ve tek bir işi çok iyi yapacak şekilde son derece optimize edilmiş
    Redis ise tüm veri yapıları ve tek thread yapısı vb. ile daha çok rastgele paylaşılan bir Python heap’ine benziyor
    Notion’da Redis’i pek çok amaç için kullanıyoruz ama gerçek önbellekleme işini memcached’e bırakıyoruz

    • Anahtar-değer kullanımında o kadar da hızlı olmadığını doğrulayabilirim
      Okuma başına ortalama 300 mikrosaniye ile 350 mikrosaniye civarında
      Tek thread olması da çok önemli değil; çünkü darboğaz CPU değil, reaktif G/Ç
    • Thread’ler bedava değil
      Daha fazla CPU çekirdeği kullanmanızı sağlarlar ama yük çok yüksek değilse tek thread’li memcached, çok thread’li olandan daha az CPU kullanır