OPcache

Comprendre et optimiser

Forum PHP - 2014

Par Frédéric Bouchery / Xavier Leune

Frédéric Bouchery

@FredBouchery

Xavier Leune

@Beoneself


60 millions de visiteurs uniques par mois ...

Qu'est qu'un cache d'opcode ?

Script PHP

<?php
$end = time() + 60 * 60 * 24 * 365;
echo strftime("Expire le %m/%d/%Y\n", $end);

Analyse

Noeuds

0T_OPEN_TAG
1T_VARIABLE$end
2T_WHITESPACE
3=
4T_WHITESPACE
5T_STRINGtime
6(
7)
8T_WHITESPACE
9+
10T_WHITESPACE
11(
12T_LNUMBER60
13T_WHITESPACE
14*
15T_WHITESPACE
16T_LNUMBER60
17T_WHITESPACE
18*
19T_WHITESPACE
20T_LNUMBER24
21T_WHITESPACE
22*
23T_WHITESPACE
24T_LNUMBER365
25)
26;
27T_WHITESPACE
28T_ECHOecho
29T_WHITESPACE
30T_STRINGstrftime
31(
32T_CONSTANT_ENCAPSED_STRING"Expire le %m/%d/%Y\n"
33,
34T_WHITESPACE
35T_VARIABLE$end
36)
37;
38T_WHITESPACE

Interprétation

Opcodes

0 EXT_STMT
1 ASSIGN        !0, 1
2 EXT_STMT
3 BOOL_NOT  ~1  !0
4 JMPZ          ~1, ->7
5 EXIT
6 JMP           ->7
7 RETURN        1

Exécution

Cacher l'opcode !

Script PHP


Analyse

Noeuds


Interprétation

Opcodes


Mise en cache


Exécution

Script PHP


Reprise en cache

Opcodes


Exécution

Les caches d'opcode

Avant 2007, règne de Turck MMCache et d'eAccelerator

Zend en observateur des premiers jours

A partir de 2007 : APC monte sur le trône

Début 2013, Zend libère Optimizer+

En mars 2013, RFC pour intégrer Optimizer+ dans PHP 5.5

Depuis, désaffection pour APC

Mais quid des autres solutions ?

NuSphere et ionCube ?

Bonne question !

XCache fait de la résistance

Raison du règne d'APC ?

apc_store()

Naissance d'APCu

Opcache est donc un simple cache d'opcodes ?

Script PHP


Analyse

Noeuds


Interprétation

Opcodes


Optimisation

Opcodes


Mise en cache


Exécution

<?php
echo 60 * 60 * 24 * 365;
?>
         line     # *  op         ext  return  operands
         ------------------------------------------------
            2     0  >   EXT_STMT
                  1      MUL             ~0      60, 60
                  2      MUL             ~1      ~0, 24
                  3      MUL             ~2      ~1, 365
                  4      ECHO                    ~2
            4     5    > RETURN                  1


         line     # *  op         ext  return  operands
         ------------------------------------------------
            2     0  >   EXT_STMT
                  1      ECHO                    31536000
            4     2    > RETURN                  1
<?php
$x = 1;
if (!$x) exit;
?>
line     # *  op         ext  return  operands
------------------------------------------------
   2     0  >   EXT_STMT
         1      ASSIGN                  !0, 1
   3     2      EXT_STMT
         3      BOOL_NOT        ~1      !0
         4    > JMPZ                    ~1, ->7
         5  > > EXIT
         6*     JMP                     ->7
         7  > > RETURN                  1


line     # *  op         ext  return  operands
------------------------------------------------
   2     0  >   EXT_STMT
         1      ASSIGN                  !0, 1
   3     2      EXT_STMT
         3    > JMPNZ                   !0, ->5
         4  > > EXIT
         5  > > RETURN                  1
<?php
if (true) echo 'ok';
?>
---- Pas optim ------
0 EXT_STMT
1 JMPZ     true, ->4
2 ECHO     'ok'
3 JMP      ->4
4 RETURN   1

-- Optim bit 1 ------
0 EXT_STMT
1 NOP
2 ECHO     'ok'
3 JMP      ->4
4 RETURN   1

-- Optim bit 2 ------
0 EXT_STMT
1 JMPZ     true, ->4
2 ECHO     'ok'
3 NOP
4 RETURN   1

----- Optim ---------
0 EXT_STMT
1 ECHO     'ok'
2 RETURN   1

Optimisation mémoire : interned strings

<?php
function test()
{
    return 'test';
}

$test = test();
echo $test;
?>

Cinq chaînes

Un seul emplacement mémoire

cache d'opcode + optimisation
=
gros gain de performance ?

Pas tout à fait !

cache : temps de réponse -50%

optimisation : temps de réponse -10%

OPCache : un outil magique ?

Pas tout à fait !

Un besoin de configuration important

26 paramètres de configuration

Dont 15 impactant la performance ou la mise en cache

Les stratégies d'invalidation

revalidate_freq 2

validate_timestamps 1

revalidate_path 0

Répertoire courant Chemin d'inclusion Fichier inclus
/var/www/app/current/classes/
../monFichier.php
monFichier.php
/var/www/app/current/
monFichier.php
/var/www/app/current/batches
/var/www/app/current/monFichier.php

1 fichier en cache mais 3 clés pour y accéder.

Attention !
APC et OPCache ne se comportent pas de la même manière

Structure de répertoire avec capistrano :

droite
        |-current -> releases / 1
        |
        |-releases
        |--1/
        |---index.php (inode: 80)
                    
        |-current -> releases / 2
        |
        |-releases
        |--1/
        |---index.php (inode: 80)
        |--2/
        |---index.php (inode: 250)
            

max_wasted_percentage 5

Les stratégies de stockage

memory_consumption 64Mo

max_accelerated_files 2000

interned_strings_buffer 4Mo

save_comments 1

load_comments 1

Les filtres sur les fichiers

file_update_protection 2

max_file_size 0

blacklist_filename ""

Les stratégies d'optimisation

fast_shutdown 0

enable_file_override 0

optimization_level 0xffffffff

enable_cli 0

Quelle configuration pour quel environnement ?

Dév

  • validate_timestamps=1
  • enable_file_override=1
  • revalidate_freq = 0

Test

  • validate_timestamps=1
  • enable_file_override=1
  • revalidate_freq = 60

Prod

Activer :

  • fast_shutdown
  • enable_file_override

Désactiver :

  • validate_timestamps
  • revalidate_path

Flush obligatoire

Surveiller OPCache

opcache_get_status();

Suivre la consommation mémoire n'est pas suffisante !

Suivre les clefs de cache

Exemple, pour opcache.max_accelerated_files = 7 963

num_cached_scripts : 1 946
num_cached_keys    : 7 963

opcache.log_verbosity_level = 4 (max)

Fri Oct 10 15:07:44 2014 (14926): Debug No more entries in hash table!

Suivre les interned strings

interned_strings_usage.free_memory : 0

Et mes données utilisateurs ?

Il n'y a pas qu'APC dans la vie !

Pensez à shmop ou aux ramdisks !

Sinon, il y a toujours APCu ...

Pour stocker quoi d'ailleurs ?

$content = '<?php return ' . var_export($configuration, true) . ';';
file_put_contents('/tmp/cache/configuration.php', $configuration);
if (file_exists('/tmp/cache/config.php')) {
    $configuration = include('/tmp/cache/config.php');
} else {
    // ... génération
}

Attention à file_update_protection

OPCache ...

... ce n'est pas une révolution

Attention à la configuration par défaut

Merci !

joind.in : https://joind.in/11960
Slides : http://tech.ccmbg.com/forumphp-2014/

@FredBouchery - @Beoneself

Bonus !

Dév : dev/opcache.ini
Test : test/opcache.ini
Prod : prod/opcache.ini