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:
- Ho bisogno di un certo dato.
- Controllo se il dato è memorizzato nella cache (e non è scaduto).
- Se il dato non c’è (o è scaduto) lo recupero della memoria principale (per esempio dal DB) e lo salvo nella cache.
- 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.
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 🙂