Memcache Danga.com tarafından livejournal için üretilmiş ama ciddi bir soruna çözüm olduğu için çok hızlı şekilde yayılmış bir program ve library’dir. Yapısındaki hız farkı genel olarak libevent aracılığı ile linux altında epoll kullanımından ve memory’i pahalı olan malloc ve free’lerden uzak şekilde slab allocation mantığında kullanmasından gelmektedir. Network üstünden çalışabiliyor olduğu için bir çok serverın aynı cache sistemini kullanabiliyor hale gelmesini sağlamış ve facebook gibi büyük projelerin düşük server maliyetleri ile ayakta kalmasını sağlar hale gelmiştir.Eğer okumadıysanız bu yazıdan önce Cache sistemleri ile ilgili yazdığım yazıyı okumanızı öneririm. Neden gerek olduğu, nasıl kullanılması gerektiği gibi konuları bulabilirsiniz. Bu yazıda ise biraz daha memcache’in kendisine sorunlarına avantajlarına özgü anlatım yapacağım.Memcache kullanımıyla ilgili akılda tutulması gereken en önemli noktalardan birisi memcache’in bir cache sistemi olduğu ve cache’in silinebileceğini akılda tutup veritabanıymış gibi işlem yapmamaktır. Üstüne attığınız veriler her zaman veritabanı gibi başka bir kaynaktan alınabilecek durumda olmalıdır.Memcache nasıl çalışır kısaca gözden geçirelim. Network üstünden 11211 portundan dinleyerek gelen komutlara göre işlem yapar. Herhangi bir güvenlik protokolu yoktur. Memcache yapı olarak malloc ve free lerden uzak kalmak için belirlediğiniz bir memory alanını kendi kullanımı için 1 mblık slab parçalarına böler ve bu şekilde malloc yapar. Böylece kücük veriler için devamlı malloc free yapmak yerine kendi memory management’ını gerçekleştirir. Buda ciddi ölçüde memcache deamon’a hız kazandırır. Kendi Anahtar yapısına özgü Index yapısı vardır, böylece bir anahtarı istediğinizde anahtar ardından verinin tutulduğu memory geldiğinden direk erişim yaparak çok hızlı şekilde verebilmektedir. Asıl olarak memcache’de iteration olmama sebebide budur. Network üzerinden işlem yaparken çok ciddi connection yükü altında ezilmeyip hızlı response verebilmeyi ise libevent yapısını kullanmasına, daha önceki yazılarda @xeptor nickli arkadaşımızın anlattığı yapı olan linux altında epoll kullanımı sayesindedir. Threaded çalışabilmesi ile thread desteği henüz yeni olmasına rağmen multi cpu lu sistemlerde daha iyi response zamanları verdiğini söylemeliyim.Memcache in bildiğim kısıtlamaları dikkat edilmesi gereken noktalar;* Memcache bir cache sistemidir. Verilerinizin kaybolmaması gibi bir durum söz konusu değildir.* Memcache’de herhangi bir güvenlik algoritması yoktur. Network üstünde başkalarının erişememesini firewall yada başka bir şekilde kendinizin sağlaması gerekmektedir.* Memcache’de herhangi bir hata durumunda kendini düzeltme yapısı yoktur. Memcache serverlar birbirleri arasında haberleşmezler bu yüzden hata olduğunda uygulamanız kendisi başka bir memcache serverı kullanmak için yazılması gerekmektedir.* Memcache’de maximum tutabileceğiniz anahtar büyüklüğü kodunu değiştirmediğiniz suretçe 250 bytedır.* TCP/IP latency si uzun olan serverlar arasında memcache kullanmak doğru bir yol değildir. Sisteminizi daha çok yavaşlatır.* Memcache’de kodunu değiştirmediğiniz sürece kaydedebileceğiniz en büyük veri uzunluğu 1 mbdır. 1 mb’ dan büyük veri atarsanız fazla gelen kısım alınmaz. Dikkat etmezseniz bulmanız çok zor problemlere yol açabilirsiniz.* Tek bir memcache serverı bir çok server için kullanmak genelde kötü bir yoldur. Memcache’in sorun yaşayıp programın kapanabileceğini göz önüne alarak birden çok memcache server’a hash algoritması ile yük dağıtımı yapmanız. Hata durumunda geride kalan memcache serverlara veri yazıp alabilmeniz gerekmektedir.* Memcache malloc gibi fragmantasyonlara dikkat etmez bu yüzden kullanırken slablar içindeki chunk sizeların grow oranlarını veri büyüklüğünüze göre ayarlamanız performans getirecektir.* Memcache’e anlık çok fazla connection geldiğinde yapısındaki connection cache e göre sorun çekebilmektedir.Yukarıda yazdıklarımı biraz daha açarak sorunları ve nasıl çözebileceğimize değineyim.Öncelikle memcache memory i nasıl kullanır ona bir bakalım.Fragmantasyon Sorunu:
Memcache’in 1 mb lık slablar halinde memory allocate ettiğini söylemiştim ve tabiki tek bir anahtarı ve değerini tek bir slab’a yazmamaktadır. Slablar içinde eşit boyuttaki chunk(parça) lara ayırır. Bir veri koymak istediğinizde slab lar içerisinde veri boyutunuza eşit boş parçayı bulursa direk o slab içerisine yazar. Eğer tüm slablarda bulamazsa yeni bir slab allocate edilir ve içeriği sizin gonderdiğiniz veri büyüklüğüne göre parçalara ayrılır ve içerisine veri yerleştirilir. Eğer uyan bir slab yok ise ve memory limitine gelmişse olan bir chunk boyutu chunk size faktöre göre büyütülür ve veri içerisine yazılır. Chunk size faktor memory nin faktöre göre bölündüğünde anahtar başlarına erişebilmesini sağladığı için önemli bir konudur ve bu şekilde memory fragmantasyonunu düşük tutmayı hedefler. Ancak eğer devamlı çok düşük boyutta veriler atıyorsanız olası chunksize dan kücük olduğu icin bir sürü memory fragmantasyonu olacaktır yada chunk büyüme faktörüne göre daha orta derecede değişen veri boyutları atarsanız. Bu durumu engellemek amacıyla chunk ların büyüme faktörünü memcached in –f parametresi ile değiştirebilirsiniz. Ancak dikkatli kullanılması gereken bir yoldur. Eğer işletim sisteminiz destekliyor ise –L ile memory i lock ederek cpu gücünden kazanabilirsiniz. Önemli olan nokta max memory’i sahip olduğunuz ram miktarından daha yüksek vermemektir. Swap kullanımı her zaman çok yavaş bir konudur.Memcache de eski dataların silinmesi:
Memcache de dataları invalidate etmek için iki yöntem vardır. İlki set fonksiyonu içinde zaman verebilirsiniz, bu durumda istediğiniz süreç sonrasında memcache otomatik değeri invalidate edecektir. (Aslında çağrıldığında ve ya memory gerektiğinde bu işi yapmaktadır bu yüzden extra bir thread bu iş için uğraşmamaktadır.) Bir diğer yol ise LRU denilen yöntemdir. Eğer yeni veri ekliyorsanız ve yer yok ise data boyutunuza uygun en eski değeri bulacak ve üzerine yazacaktır. Burada data boyutunuza uygunun altını çizmek gerekiyor daha eski cache değerleri varken niye daha yenisini siliyor sorusu sorarsanız sanırım buda cevap olabilir. Eğer uygun boyut bulamazsa birden fazla data yı silerek kendisine uygun chunk oluşturmaya çalışacaktır.Güvenlik:
Memcache üzerinde herhangi bir extra güvenlik hız nedeni ile söz konusu değildir. Bu yüzden kendinizin firewall yada benzeri bir şekilde güvenliği sağlamanız gerekmektedir.x86 ve x86_64 farkı:
Memcache in başka bir limitide x86 memory erişiminde PAE(Physical Address Extension) kullansada application bazında flat memory modeli kullandığı için 4 GB üzerine erişememesidir. x86_64 de ise flat memory model 16.8 milyon terabytes a kadar desteklemektedir. Bu yüzden eğer işletim sisteminiz 64 bit değilse ve 4 GB üzeri memory kullanmak istiyorsanız farklı portlardan tek bir makine üzerinde birden çok memcache çalıştırabilirsiniz.1 MB Limiti:
Memcache de binary yada değil herşeyi depolayabileceğimizi söylemiştim. Fakat Memcache 1 MB üzerindeki depoladığınız verileri trim edicektir. Bu konuyu geçebilmek için iki tane yolunuz var, eğer genel olarak 1 MB üzeri veri kullanıyorsanız memcache in codelarından POWER_BLOCK constant ını değiştireceksiniz. Yada verilerinizi memcache e atarken eğer 1 mb dan büyük se sonuna bir tag koyarak o tag da belirttiginiz anahtara geri kalanını yazıcaksınız. Okurkende verinin sonunda TAG varmı diye bakarak varsa o anahtarı daki veriyi de alıp toplayarak verinize kavuşabilirsiniz. Tabi bu durumda datalardan birisi yok olduğunda tüm veriyi invalidate etmeniz gerektiğini ve belirli şekilde boşa cpu gücü kaybedeceğinizi unutmamak gerekiyor. Bu yüzden bu yöntemi cidden 1 mb dan fazla veriniz az ise uygulamanızı tavsiye ederim.Memcache server üzerine anlık çok fazla connection gelmesi:
Memcache malloc işlemini tuttuğu veriler bakımından cok düşük seviyeye indirsede anlık connectionların hepsine malloc yapma gereksinimi duymaktadır. Buda birden çok fazla connection geldiğinde connectionlara memory ayırması gerektiğinden belirli bir yavaşlamaya sebep olmaktadır. Bir serverda memcache e açacağınız anlık connection sayısı 30’u yada 40’ı zaten geçmemesi gerekmektedir, geçiyorsa codelarınızı kontrol etmenizi öneririm ama 30 web serverınız var ve hepsi aynı memcache serverı kullanıyorsa bu sayı artacaktır. Bu durumda kolları sıvayıp code üzerinden default allocated connection memory’sini artırmanız gerekmektedir.Memcache de kullanılabilecek anahtarın max 250 karakter uzunluğunda olması:
Eğer yazmanız gereken anahtar kelime 250 karakterden fazla ise bu durumda crc32 veya md5 tarzı checksum alıp anahtar olarak kullanmanız anahtar kelimenizin boyunu kücültmeye yeticektir.Memcache server olarak birden çok serverın kulllanılması ve yük dağılımı:
Bilindiği gibi memcache sorun yaşamamak üzerine kurulan bir sistem değildir ve sorun yaşayabilir. Kimi süreçtede o kadar çok yükünüz olurki tek memcache server bu yükü kaldıramıyacak duruma gelir. Bu durumda birkaç hashing algoritmasından birini kullanıyoruz. En çok kullanılan anahtar kelimenizin crc32 sini almak ve server sayınıza bölmektir. Bu şekilde aynı anahtar kelime hep aynı servera karşılık gelecek ve memcache serverlarınıza yük dağıtabileceksinizdir. Memcache serverlarınızdan tekine bağlanamadığınızda da bu serveri geçici olarak listeden çıkarıp server sayınızı düşürerek hash hesaplamanız sorun çıktığı durumlarda diğer serverlara yükü dağıtmak için kullanılabilecek bir yoldur. Sorun çıkabileceğini göz önünde tutarak memcache serverlarınızı yoğunluk bakımından limitlerde gezdirmemeniz doğru bir seçim olacaktır.Peki doğru memcache kullanımı nasıl?:
Memcache i database deki sorgu başına cache mantığında kullanmanız anlamsız ve gereksizdir. Query Cache de ciddi ölçüde bu işi yapmaktadır. Memcache birden çok SQL sorgusunun sonucunda oluşan yapıyı tutmak için daha uygundur. Bu şekilde yükü azaltabilirsiniz. Örnek vermek gerekirse bir sayfayı oluşturmak için 20 tane sorgu gönderiliyorsa 20 ayrı memcache anahtarında bunu tutmak yerine tek bir anahtarda atılması gereken tüm sorguların olması doğru yoldur.Bir konuda MySQL içerisinden udf kullanılarak memcache in yönetilmesidir. @umutbesler nickli arkadaşımız değinmişti bu konuya, biraz daha detayına girecek olursak. MySQL deki stored procedureleri kullanarak MySQL den sayfayı oluşturacak tüm nesneleri çekmek ve bunları memcache de Query olarak değil sayfada olması gereken tüm verileri tutacak şekilde ayarlamak, MySQL den sırayla gerekli tüm sorguları gönderip sayfayı oluşturmaktan her zaman daha hızlı olacaktır. Bu durumda MySQL’den isterseniz sorguyla memcache sonucunu alabilirsiniz ancak tavsiyem MySQL e yazdırıp hiç MySQL e sormadan direk memcache connection ile bu sonuçlar varmı diye bakıp kullanmaktır.Bunun harici MySQL üzerinde kullanılabilecek önemli noktalardan biriside cache de bulunan bir yapı değiştiğinde trigger lar ile yada veriyi stored procedure aracılığı ile değiştirerek MySQL in otomatik bunu memcache de invalidate etmesini sağlamak olabilir. Eğer sadece uygulamanız aracılığıyla veri değiştirmiyorsanız bu yöntem olmazsa olmaz bir yöntemdir.Dahada basit bir kullanım örneği MySQL in Innodb de count işleminde yavaş olduğunu biliyoruz. Row eklendiğinde silindiğinde memcache de atomic olan inc dec gibi fonksiyonları kullanarak MySQL in table daki count’ları tutması da ciddi ölçüde veri tabanı yükünüzü hafifletecektir.PHP ile memcache kullanımın basit bir örneği ve nereden yardım alınabileceği:
Amacım advance şekilde nasıl kullanılır göstermek değil doğrusu bunu sizin projenize özgü oluşturmanız gerekmektedir ve yapıyı anlamak adına hazır codelardan kaçınmanızı kendinizin yapmanızı öneririm. Örneği memcache in kendi codelarından paste ediyorum.set(“str_key”, “String to store in memcached”);$memcache->set(“num_key”, 123);$object = new StdClass;$object->attribute = ‘test’;$memcache->set(“obj_key”, $object);$array = Array(‘assoc’=>123, 345, 567);$memcache->set(“arr_key”, $array);var_dump($memcache->get(‘str_key’));var_dump($memcache->get(‘num_key’));var_dump($memcache->get(‘obj_key’));}else {echo “Connection to memcached failed”;}?> Bunun harici olarak http://tr2.php.net/memcache adresinden memcache ile ilgili dökümanlara ve gerekli örneklere ulaşabilirsiniz.