memcached'e Övgü
(jchri.st)- Ö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 daNonedö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
- Kesinti yönetimi kolaydır: istemci kütüphaneleri çoğu zaman bağlantı istisnalarını yok sayar ve basit bir
- 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
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
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
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
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
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
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
Geliştiriciler bunun hiç farkında değilmiş gibi görünüyor
Bence bunun nedeni, Memcached’i Redis ile değiştirirken aynı davranışı beklemeleri
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
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
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
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/Ç
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