Categorie
PHP

PHP – Velocizzare le pagine con APC

In questo articolo voglio parlarvi di APC, un sistema di caching PHP in grado, in taluni casi, di rendere significativamente più veloci le nostre applicazioni.

APC (Alternative PHP Cache) è un’estensione per il caching e l’ottimizzazione del codice intermedio PHP.

Premessa

La cache è una memoria temporanea (secondaria) nella quale possiamo memorizzare le informazioni per un più veloce accesso futuro. La cache è sicuramente meno capiente della memoria principale (qualunque essa sia), ma è molto più performante. Wikipedia dice:

Una cache è associata ad una memoria “principale”, in cui risiedono i dati. Essa è tipicamente di capienza inferiore rispetto alla memoria principale, ma il suo utilizzo è più conveniente in termini di tempo di accesso e/o carico sul sistema.
Quando è necessario l’accesso ad un dato, questo dato viene prima cercato nella cache. Se è presente e valido, viene utilizzata la copia presente. Viceversa, viene recuperato dalla memoria principale, e memorizzato nella cache, nel caso possa servire successivamente.

Quindi l’obiettivo della cache è memorizzare informazioni il cui reperimento è particolarmente dispendioso, come l’esecuzione di queries complesse da un database.
In pratica se l’informazione non è stata modificata nel corso del tempo converrà recuperarla dalla cache piuttosto che rieseguire nuovamente la query tutte le volte che ne abbiamo bisogno.
Naturalmente dovremo escogitare un sistema che garantisca che le informazioni memorizzate nella cache siano aggiornate, altrimenti rischiamo di combinare un “bel pasticcio”.
Di solito quando si memorizza un dato nella cache si specifica anche un tempo di vita (lifetime). Passato questo tempo l’informazione non sarà valida.
Tuttavia, anche settando lifetime particolarmente bassi, potrebbe sempre verificarsi l’ipotisi di un aggiornamento del dato prima della sua scadenza. In questo caso la regola più semplice da seguire è quella di eliminarlo dalla cache oppure, ancora più semplice, svuotare completamente la cache ad ogni aggiornamento.
Riassumendo, un sistema di cache in PHP dovrebbe lavorare, grosso modo, in questo modo:

  1. Ho bisogno di un certo dato.
  2. Controllo se il dato è memorizzato nella cache (e non è scaduto).
  3. Se il dato non c’è (o è scaduto) lo recupero della memoria principale (per esempio dal DB) e lo salvo nella cache.
  4. Prelevo il dato dalla cache.

Naturalmente si presuppone che il punto 3 sia per la maggior parte delle volte saltato, rendendo quindi efficace il meccanismo.

Installazione

APC è disponibile tramite PECL (PHP Extension Community Library), cioè un archivio di moduli che estendono l’interprete PHP.
Per l’installazione vedere: www.php.net/manual/en/apc.installation.php
Mentre su macchine Windows bisogna scaricare l’estensione (.dll) ed aggiungerla al php.ini, vedere:
docs.moodle.org/20/en/Installing_APC_in_Windows

APC come acceleratore

Oltre a fornire un sistema di caching (di cui parleremo dopo), APC fa parte anche degli acceleratori di bytecode, cioè del codice intermedio di PHP.
Essendo PHP un linguaggio interpretato, ad ogni esecuzione, prima il codice sorgente viene tradotto in un codice intermedio (bytecode o codice oggetto) e poi viene eseguito.
In pratica, PHP usa un’architettura di esecuzione a due tempi. Fase uno, compilazione del codice sorgente in codice intermedio. Fase due esecuzione del codice intermedio. Ma cosa succede una volta che il codice intermedio viene eseguito? Il codice viene deallocato e distrutto. Questo significa che alla successiva esecuzione dello script lo Zend Engine (l’interprete PHP) dovrà ritradurre il codice sorgente in codice intermedio e rieseguire il codice intermedio.
Questo approccio, che da un lato può offrire anche diversi vantaggi (es. perfetto isolamento tra diverse richieste) dall’altro, soprattutto per siti con milioni di visitatori giornalieri, può rappresentare un collo di bottiglia, difatti il processo di interpretazione è sicuramente oneroso in termini di tempo.
Gli acceleratori (come APC) servono appunto per memorizzare il codice intermedio in una cache temporanea per riutilizzarlo alla successiva richiesta di interpretazione. Questa funzionalità è svolta in maniera del tutto trasparente e senza nessun intervento sul codice sorgente.
I vantaggi ottenuti dall’utilizzo di un acceleratore dipendono fortemente dalla natura dell’applicazione. Applicazioni in cui la maggior parte dell’overhead è sull’attesa di una risposta del database, beneficeranno in maniera minore dell’annullamento dell’overhead di compilazione. D’altra parte, applicazioni che utilizzeranno molti files, con sovraccarichi di esecuzione relativamente bassi potranno ottenere un notevole aumento delle prestazioni.

Nota: Il codice intermedio è un codice composto da operazioni molto semplici, piuttosto simile all’Assembly.

APC come sistema di caching

Vediamo ora come , noi sviluppatori, possiamo utilizzare APC per memorizzare e leggere informazioni dalla cache. L’estensione è infatti provvista di una seri di funzioni che ci rendono semplice il lavoro.

Salvare dati nella cache

Possiamo farlo con due comode funzioni: apc_add ed apc_store:
bool apc_add ( string $key [, mixed $var [, int $ttl = 0 ]] )
bool apc_store ( string $key , mixed $var [, int $ttl = 0 ] )

$key: è la chiave del dato da memorizzare.
$var: è il valore da memorizzare.
$ttl: è il tempo per il quale il dato è valido.

Le due funzioni accettano anche questa sintassi:
array apc_add ( array $values [, mixed $unused [, int $ttl = 0 ]] )
array apc_store ( array $values [, mixed $unused [, int $ttl = 0 ]] )

$values è un array in cui le chiavi sono le chiavi del dato da memorizzare.

Entrambe le funzioni restituiscono true o false a seconda se il dato viene memorizzato o meno. In caso della variante con array sarà restituito un array con le chiavi che generano errore (che non vengono memorizzate).
Se il tempo di vita (ttl) non viene indicato il valore di default è 0 (zero), cioè nessuna scadenza. Possiamo memorizzare qualsiasi tipo di dato, numeri, stringhe, array oggetti etc..
La differenza tra apc_add ed apc_store consiste nel fatto che la prima non sovrascriverà mai una chiave esistente, mentre la seconda si.

<?php
$a = array('BAR', 'BAZ');
apc_store('foo', $a);
var_dump(apc_fetch('foo'));
echo "\n";
$bar = 'BAR';
apc_add('foo', $bar);
var_dump(apc_fetch('foo'));


/**
Restituisce:
array (size=2)
  0 => string 'BAR' (length=3)
  1 => string 'BAZ' (length=3)
array (size=2)
  0 => string 'BAR' (length=3)
  1 => string 'BAZ' (length=3)
**/
?>

Leggere dalla cache

Per leggere un dato dalla cache possiamo utilizzare la funzione apc_fetch():

<?php
$bar = 'BAR';
apc_store('foo', $bar);
var_dump(apc_fetch('foo'));

/**
Restituisce:
string(3) "BAR"
**/
?>

Rimuovere un dato dalla cache

Per cancellare un dato dalla cache usiamo la funzione apc_delete():
mixed apc_delete ( string $key )

$key è la chiave che vogliamo rimuovere.
Ritorna true o false in caso di successo o fallimento.

<?php
$bar = 'BAR';
apc_store('foo', $bar);
apc_delete('foo');
?>

Svuotare la cache

Possiamo anche decidere di svuotare completamente la cache. In questo caso usiamo la funzione apc_clear_cache(). Visto che APC potrà anche essere usato come acceleratore, dobbiamo specificare quale cache eliminare:
bool apc_clear_cache ([ string $cache_type ] )

cache_type: se è “user“, allora sarà svuotata la cache utente; altrimenti sarà pulita la cache di sistema (APC come acceleratore).
Ritorna true o false in caso di successo o fallimento.

Modificare valori numerici

In caso volessimo memorizzare valori numerici abbiamo due comode funzione per aumentarli o decrementarli: apc_inc ed apc_dec.
int apc_inc ( string $key [, int $step = 1 [, bool &$success ]] )
int apc_dec ( string $key [, int $step = 1 [, bool &$success ]] )

$key: è la chiave che vogliamo modificare
$step: è il valore da incrementare o decremenentare

<?php
apc_add('num', 10);
apc_inc('num', 2);
apc_dec('num', 1);
echo apc_fetch('num') . "\n";

/**
Ogni volta che carichiamo la pagina il numero sarà aumentato di una unità
11,12,13,14...
**/
?>

Restituisce il valore corrente della chiave in caso di successo o false in caso di errore.

Verificare se una chiave esiste

Per farlo possiamo usare la funzione apc_exists.
La funzione accetta come unico parametro la chiave da verificare. La chiave può essere sia una stringa che un array, contenete chiavi.
Ritorna true o false a seconda se la chiave esiste o meno. Nel caso fosse passato un array ritorna un array contenente le chiavi esistenti o un array vuoto nel caso non ne esista nessuna.

<?php
$fruit  = 'apple';
$veggie = 'carrot';

apc_store('foo', $fruit);
apc_store('bar', $veggie);

if (apc_exists('foo')) {
    echo "Foo exists: ";
    echo apc_fetch('foo');
} else {
    echo "Foo does not exist";
}

echo PHP_EOL;
if (apc_exists('baz')) {
    echo "Baz exists.";
} else {
    echo "Baz does not exist";
}

echo PHP_EOL;

$ret = apc_exists(array('foo', 'donotexist', 'bar'));
var_dump($ret);

/**
Ritorna:
Foo exists: apple
Baz does not exist
array(2) {
  ["foo"]=>
  bool(true)
  ["bar"]=>
  bool(true)
}
**/
?>

Conclusioni

Alternative PHP Cache è una cache opcode in grado di accelerare significativamente le applicazioni PHP, mettendo in cache sia il codice intermedio PHP che le variabili utente.
Aggiungere APC ad un’applicazione in genere si traduce in un sensibile miglioramento dei suoi tempi di risposta, il carico del server viene ridotto e gli utenti (nonchè gli sviluppatori) sono più felici 🙂

Risorse

www.php.net/manual/en/book.apc.php

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.