Skip to content

Ocak 15, 2011

6

PHP GLOBAL Cache Kullanarak Performans Artırmak

cache-icon

Merhaba arkadaşlar, bu yazımızda mevcut uygulamalarımızın hızını artırmak için PHP GLOBALS cache yardımıyla sayfa oluşturulma sürelerini kısaltacak bir yöntemi inceleyeceğiz.

PHP GLOBALS cache, daha çok mevcut kodlarınızda optimizasyon sağlayacak bir yöntemdir.  Şüphesiz tüm geliştiriciler yeni sistem tasarlarken veritabanı tasarımından başlayarak sunucu taraflı ve kullanıcı arayüzünde optimizasyonlar yaparak uygulama hızını artırmaya çalışırlar. Ancak madalyonun öbür yüzü bu durumdan biraz farklıdır.

Her firma yeni geliştirici alırken veya mevcut geliştiricileriyle yola devam ederken, çok esnek, yüksek performanslı ve ölçeklenebilir bir yazılım üretmeyi hedef alır. Bu tabi ki çok haklı bir nedendir. Ancak çoğu uygulama (aylık 10 milyon euro üzeri ciro seviyesinde bile) ilk yazılan veya güncel yazılımlardan biraz geride bir uygulama ile çalışır. Bunun sebebi firmaların hemen hemen hepsi ilk çıkış noktalarında bugüne geleceklerini hayal bile edemezler. Zaten daha günlük 1.000 ziyaretçiniz bile yokken 10bin adet server üzerinde çalışabilecek bir kod yazarsanız projenizin tutmaması durumunda büyük bir hayal kırıklığına uğrayabilirsiniz.

Bir diğer sebep ise gerek web sitesi üzerinde, gerekse şirket içi, backoffice vb. alanlarla hazır yazılım çözümleri kullanılmakta ve bir çoğu performans için editlenmek zorunda kalabilmekte.

Yazımızda bu ve bu gibi durumlardan dolayı bir çoğumuzun sevmediği ancak çoğu zaman müdahale etmek zorunda kaldığımız eski kodların performansını artıracak küçük bir yöntemi inceleyeceğiz.

Kullanacağımız yöntem çalışma zamanında birden fazla çağrılan fonksiyonları optimize etmeye yarar. Örneğin ürün bilgisini alan bir fonksiyonunuz var ve sayfa oluşturulana kadar aynı ürün bilgisi için 4 defa çağırılıyor olabilir.

Aşağıdaki fonksiyon verilen ürün id sine eşleşen bir kayıt varsa bu ürünün bilgilerini döndürür kayıt yoksa null döndürür. Biz burada dosyadan okuma örneği oluşturduk ancak genellikle bu bilgiler veritabanından gelir. Dosyadan , veritabanından veya dış bir kaynaktan veri çeken fonksiyonların maliyeti her zaman yüksektir.  Bu sebeple örneğimizi buna benzer fonksiyonlardan veriyoruz ve öncelikle bu alanların iyileştirilmesini öneriyoruz.

<?php

/**
 * Ürün bilgisini dosyadan çek.
 *
 * @param integer $id ürün idsi
 * @return array ürün varsa ürün bilgisi dizini yoksa null döner.
 */
function getProductInfo($id) {
    $products = json_decode(file_get_contents("products.json"), true);

    return array_key_exists($id, $products) ? $products[$id] : null;
}
?>

Aşağıdaki fonksiyon yukarıdaki fonksiyonun Global Cache eklenmiş halidir. Fonksiyonu Global Cache destekli hale getirmek için override_cache parametresi eklenir, fonksiyonun gövdesi cache kontrolü yapan if bloğu içine alınır ve return bölümü cache dizisine atanır. Son olarakta cache return edilir.

Fonsiyonun temel çalışma mantığı kendisine gelen parametre ile cache oluşturmak ve tekrar aynı parametre gelirse bunu cache den dönmektir.

<?php

/**
 * Ürün bilgisini dosyadan çek.
 *
 * @param integer $id ürün idsi
 * @param boolean $override_cache Global cache 'i override et
 * @return array ürün varsa ürün bilgisi dizini yoksa null döner.
 */
function getProductInfoNew($id, $override_cache = false) {
    if (false == isset($GLOBALS[__FUNCTION__][$id]) || $override_cache) {
        $products = json_decode(file_get_contents("products.json"), true);

        $GLOBALS[__FUNCTION__][$id] = array_key_exists($id, $products) ? $products[$id] : null;
    }
    return $GLOBALS[__FUNCTION__][$id];
}
?>

Bir diğer örnek ise yukarıdakinden farklı bir yaklaşımla meydana geliyor. Yukarıdaki fonksiyonda tüm fonksiyonların gövdelerinde değişiklik yapılıyor ancak çağırdığımız yerlerde bir değişikliğe ihtiyaç duyulmuyor. Şimdi inceleyeceğimiz yöntemde ise fonksiyon üzerinde değişiklik yapmıyor ancak çağırdığımız yerleri değiştiriyoruz.

Aşağıdaki fonksiyon kendisine gelen fonksiyon adı ve parametresini çağırır ve cache ‘e atar. Bir sonraki istekle (aynı fonksiyon ve parametre ile çağırılırsa) cache ‘den döner. İki boyuttan büyük array parametreleri için fonksiyonu değiştirmeniz gerekir.

<?php

/**
 *
 * @param string $function_name fonksiyon adı
 * @param mixed $params fonksiyona gidecek parametreler
 * @param boolean $override_cache  Global cache 'i override et
 * @return array|null ürün varsa ürün bilgisi dizini yoksa null döner.
 */
function getFunctionGlobalCache($function_name, $params, $override_cache = false) {
    $params = is_array($params) ? $params : array($params);
    $cache_key = $function_name . '_' . implode("_", $params);
    if (false == isset($GLOBALS[$cache_key]) || $override_cache) {
        $GLOBALS[$cache_key] = call_user_func_array($function_name, $params);
    }
    return $GLOBALS[$cache_key];
}
?>

Fonksiyon Testleri

Eski Fonksiyonumuzu 10bin defa çağırıyoruz ve yanıt süresini kontrol ediyoruz. Tabi ki kod çalışırken bu kadar çok çagrı olmaz ancak bazen bundan daha geç yanıt verecek fonksiyonlara kolaylıkla rastlayabilirsiniz.

<?php

// Global cache olmayan fonksiyonu çağırıyoruz
$old = microtime(true);
echo "<pre>";
for ($i = 0; $i < 10000; $i++) {
    getProductInfo("123456");
}
echo "</pre>";
echo number_format(microtime(true) - $old, 8); // 0.31639218
?>

Yukarıdaki fonksiyonun çalışma süresü 0,31 saniyedir.

Global Cache Destekli Fonksiyonun Testi

<?php

// Global cache desteklif fonksiyonun testi
$old = microtime(true);
echo "<pre>";
print_r($GLOBALS);
for ($i = 0; $i < 10000; $i++) {
    getProductInfoNew("123456");
}
print_r($GLOBALS);
echo "</pre>";
echo number_format(microtime(true) - $old, 8); // 0.02954793

?>

Fonksiyon Çıktısı :

Array
(
    [GLOBALS] => Array
 *RECURSION*
    [_POST] => Array
        (
        )

    [_GET] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

    [old] => 1294572953.1944
)
Array
(
    [GLOBALS] => Array
 *RECURSION*
    [_POST] => Array
        (
        )

    [_GET] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

    [old] => 1294572953.1944
    [i] => 10000
    [getProductInfoNew] => Array
        (
            [123456] => Array
                (
                    [_code] => 123456
                    [brand] => ASUS
                )

        )

)
0.03359199

Yukarıdaki fonksiyonun çalışma süresi 0,02 saniyedir. Fonksiyon hep aynı parametre ile çağırıldığından sadece ilk çağrıda eski fonksiyon gibi çalışır. Dİğer çağrıların hepsi cache den sonuç getirir.

Global Cache Destekli Fonksiyon Çağıran Fonksiyonun Testi

Aşağıdaki fonksiyon kendisinden istenilen fonksiyonu verdiğiniz parametreler ile çağırır ve Global Cache oluşturur. Sonraki çağrıda bu isteği cache den döndürür.

<?php 

require 'fnc.inc.php';

$old = microtime(true);
echo "<pre>";
print_r($GLOBALS);
for ($i = 0; $i < 10000; $i++) {
    getFunctionGlobalCache("getProductInfo", "123456");
}
print_r($GLOBALS);
echo "</pre>";
echo number_format(microtime(true) - $old, 8); // 0.08841419
?>

Fonksiyon Çıktısı :

Array
(
    [GLOBALS] => Array
 *RECURSION*
    [_POST] => Array
        (
        )

    [_GET] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

    [old] => 1294573555.8942
)
Array
(
    [GLOBALS] => Array
 *RECURSION*
    [_POST] => Array
        (
        )

    [_GET] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

    [old] => 1294573555.8942
    [i] => 10000
    [getProductInfo_123456] => Array
        (
            [_code] => 123456
            [brand] => ASUS
        )

)
0.08841419

Sonuç

Global Cache çoğu zaman iyi bir optimizasyon yöntemi olsa da bazı durumlarda başınızı ağtırabilir. Örneğin fonksiyonun cachelediği veriler değişmiş olabilir yada gerçektende her defasında orjinal kaynaktan getirmesi gerekebilir. Bu durumlar dışında Global Cache kullanımı performansı artıracak bir yöntemdir.

Test Dosyaları Dowload

Test dosyalarınızı buradan indirebilirsiniz.

Bir Adım Daha İlerisi

Bu yöntemin bir adım daha ilerisi belirli bir süre verilerin değişmediğinden eminseniz Memcache yardımıyla fonksiyon çıktısını cachelemek olabilir. Bunu yaptığınızda uygulamada gözle görülür bir artış olacaktır.

Toplam 6 Yorum Yorum Yaz
  1. Cüneyt
    Oca 17 2011

    Sevgili Mustafa, php cache ile ilgili çok pratik ve yararli bilgiler vermişsin. Bence de gerektiğinde kullanılması gereken bir yöntem.

    Teşekkürler…

    Cevapla
  2. Anonymous
    Nis 29 2011

    Güzel bilgiler vermişsiniz teşekkürler, ama örneği anlatırken kullandığınız fonksiyonu daha basit anlamda oluşturarak anlatsaydınız gerçekten şuanda varolandan çok daha anlaşılır bilgiler vermiş olacaktınız..

    Cevapla
  3. Nis 30 2011

    Bir bakıma haklısınız ancak konu anlatımlarında gerçekle ilişkisi olmayan senaryolar kullanmaktan kaçınıyoruz. Zira teoride yaşanabilecek hiçbir sıkıntı yoktur.

    Tüm konularda çoğunlukla denenmiş ve uygulanmış kodlar kullanmaya çalışıyoruz.

    İlginize ve geri dönüşünüze teşekkürler.

    Cevapla
  4. Tem 7 2011

    Çıktıda [_code] olan yer olacak. Syntax highlighter sıkıntı yarattığı için şimdilik böyle bir çözüm bulduk.

    Cevapla
  5. Erdal VURAN
    Kas 11 2011

    Oldukça başarılı bir makale olmuş, çok beğendim, tebrik ederim.

    Cevapla

Trackbacks & Pingbacks

  1. php global cache kullanımı? (ceviz.net)

Sizin fikriniz nedir? Lütfen aşağıdaki formu kullanarak yorum yapın.

(gerekli)
(gerekli)