Merhaba canlarım bu yazı başlıkta bahsedilen şey ve bazı nüansları hakkında olacak.

Memcached” orjinal adıyla bir “key-value storage” dir ve servis olarak çalışır. Çok hızlı bir şekilde erişmek istediğiniz verilerinizi bu servise bi sefer kaydedersiniz, sonra ihtiyacınız olduğunda da servisten okursunuz. İnternette bu konuda bolca kaynak bulmak mümkün.

Php dili ile geliştirme yapanlar bilirler bu servisi kullanabildiğiniz bir kütüphane mevcuttur. Bir süre önce bu kütüphanenin getAllKeys() methodunun çalışmadığını farkettim. Her ne kadar farklı opsiyonlar ile çalıştığı iddia edilse de; farklı versiyonlarla ve ayarlarla denememe rağmen sonuç alamadım. Sonra uğraşmayı bırakmıştım. Ama o beni bırakmadı. Geçen hafta bir uygulamamızdaki Cache servisimiz için, memcached ‘de tutulan tüm anahtarları alma ihtiyacı hasıl oldu.

İlk başta bu yazının başlığı, google ‘da sorunu çözümünü bulmak için -daha doğrusu bulduğunu düşünmek için- yeterli oldu. Stackowerflow ‘da bir abimiz çalışma mantığını kavrama açısından güzel bi özet yazmış. Sonra kısa bi araştırma sonucunda PHP dili ile yazılmış bir kaç fonksiyon buldum (1, 2) ve kullanmaya başladık.

1 Hafta sonunda farkettim ki; memcached ‘in cevap verdiği bazı anahtarlar, fonksiyonun bize döndürmüş olduğu anahtarlar listesinde yok. Tabi bunu fark edene kadar kibana ile bayağı içli dışlı olduk. Neyse efendim bu yazının ana amacı yazılmış bütün kütüphanelerde, atlanmış olduğunu düşündüğüm bu ince noktayı göstermektir.

En baştan alalım. Memcached bir yetki kontrolü yapmaz. Yani siz telnet ‘le bile bağlanıp bana şu anahtarın cevabını ver diyebilirsiniz. Bu yöntemle servise “stats items” sorgusunu iletirseniz aşağıdakine benzer bir cevap alırsınız:

STAT items:2:number 9
STAT items:2:number_hot 1
STAT items:2:number_warm 2
STAT items:2:number_cold 6
STAT items:2:age_hot 0
STAT items:2:age_warm 3825

...

STAT items:16:number 1
STAT items:16:number_hot 0
STAT items:16:number_warm 0
STAT items:16:number_cold 1
STAT items:16:age_hot 0
STAT items:16:age_warm 0

...

END

Yani diyor ki ben sizin verileri bir kaç levhaya yazdım. O levhalardaki kayıt sayıları, özellikleri falanda bunlar bunlar. Sonra internetteki örneklere de bakarsak, yine her levhadaki anahatları çekebileceğimiz bir kod var.

“stats cachedump 2 100”

Bu size 2 numaralı levhadaki ilk 100 anahtarı getirir. Yada 100 yerine 0 yazarsanız tüm anahtarları veriyor.

ITEM angaryos_cache:tableName:log_levels|castsColumns [6 b; 0 s]
ITEM angaryos_cache:tableName:settings|castsColumns [6 b; 0 s]
ITEM angaryos_cache:tableName:subscribers|castsColumns [6 b; 0 s]
ITEM angaryos_cache:tableName:departments|castsColumns [6 b; 0 s]
ITEM angaryos_cache:tableName:validations|castsColumns [6 b; 0 s]
ITEM angaryos_cache:tableName:color_classes|castsColumns [6 b; 0 s]
END

Aslında yanıldığımız yer de burası. Hepimiz burada anahtarları görünce atladık. Tamam bazı anahtarlar geldi ama ilk sorgumda bana 2 numaralı levhada 9 anahtar var demişti (STAT items:2:number 9) şuan 6 tane geldi. Yine ilk sorgumuncevabına döndüğümde görüyorum ki; toplamda 9 anahtar farklı seviyelerde işaretlenmiş:

STAT items:2:number_hot 1
STAT items:2:number_warm 2
STAT items:2:number_cold 6

Sonra her türk gibi aklımdaki bütün yöntemleri uygulamama rağmen bir çözüm elde edemeyince kullanım kılavuzunu okumaya karar verdim. Biraz bloglarını okudum. Biraz github repolarına baktım. Biraz kaynak kod karıştırdım falan derken en son kendimi Arif ‘in Manchester’a attığı golü izlerken buldum. Dedim ben daha devam etmiyim de Metin Yüncü abi kızmasın.

Neyse; bu sabah sakin kafa ile araştırınca vuslata erdim. Aradığımız komut “lru_crawler metadump 2”. Bu, öznitelik ayırmaksızın tüm anahtarları getiriyor:

key=angaryos_cache:b39efed6f405d9a00d43b2e6f311148aa7403250 exp=1586378101 la=1586378046 cas=106160 fetch=yes cls=2 size=119
key=angaryos_cache:tableName:join_tables|castsColumns exp=-1 la=1586374055 cas=67472 fetch=yes cls=2 size=118
key=angaryos_cache:tableName:color_classes|castsColumns exp=-1 la=1586374052 cas=67419 fetch=yes cls=2 size=120
key=angaryos_cache:sumAllTablesCounts exp=1586460585 la=1586374186 cas=71380 fetch=yes cls=2 size=99
key=angaryos_cache:tableName:validations|castsColumns exp=-1 la=1586374052 cas=67428 fetch=yes cls=2 size=118
key=angaryos_cache:tableName:departments|castsColumns exp=-1 la=1586374055 cas=67523 fetch=no cls=2 size=118
key=angaryos_cache:tableName:subscribers|castsColumns exp=-1 la=1586374053 cas=67440 fetch=yes cls=2 size=118
key=angaryos_cache:tableName:settings|castsColumns exp=-1 la=1586374055 cas=67521 fetch=yes cls=2 size=115
key=angaryos_cache:tableName:log_levels|castsColumns exp=-1 la=1586374055 cas=67527 fetch=yes cls=2 size=117
END

Aşağıda PHP dili için yazılmış fonksiyona gözatabilirsiniz. Ayrıca “Mini Araçlar” reposuna da ekliyorum. Sağlıcakla, evde kalın.

function getMemcachedKeys($host = '127.0.0.1', $port = 11211)
{
    $mem = @fsockopen($host, $port);
    if ($mem === FALSE) return -1;

    $r = @fwrite($mem, 'stats items' . chr(10));
    if ($r === FALSE) return -2;

    $slabs = [];
    while (($l = @fgets($mem, 1024)) !== FALSE) 
    {
        $l = trim($l);
        if ($l == 'END') break;

        $m = array();
        $r = preg_match('/^STAT\sitems\:(\d+)\:/', $l, $m);
        if ($r != 1) return -3;
        
        if(!in_array($m[1], $slabs)) array_push ($slabs, $m[1]);
    }

    $keys = [];
    foreach($slabs as $slab)
    {
        $r = @fwrite($mem, 'lru_crawler metadump '.$slab . chr(10));
        while (($l = @fgets($mem, 1024)) !== FALSE) 
        {
            $l = trim($l);
            if ($l == 'END') break;
            
            $key = explode(' ', $l);
            $key = $key[0];
            $key = substr($key, 4);
            $key = urldecode($key);
            array_push($keys, $key);
        }
     
    }
    
    @fclose($mem);
    unset($mem);

    return $keys;
}