Jump to content

Problèmes avec le cache (memcache, apc) et les requêtes SQL


Recommended Posts

Bonjour, 
 
pour optimiser les performances de notre Prestashop 1.6.1.4 il nous est conseillé d'utiliser le cache memcache (ou autre) par contre lorsqu'on l'active les résultats sont inutilisables en production.
 
Après analyse du code, il s'avère que les requêtes sql sont cachées par la classe DB, donc la fonction executeS est utilisée principalement avec le paramètre par défaut $use_cache = true.
 
Un exemple concret serait celui de la création d'une adresse par un client :
 
La fonction getAddresses() dans Customer.php enregistre le résultat de la requête dans une clé de cache du type 'Customer::getAddresses1234-2-0'
 

public function getAddresses($id_lang)
    {
        $share_order = (bool)Context::getContext()->shop->getGroup()->share_order;
        $cache_id = 'Customer::getAddresses'.(int)$this->id.'-'.(int)$id_lang.'-'.$share_order;
        if (!Cache::isStored($cache_id)) {
            $sql = 'SELECT DISTINCT a.*, cl.`name` AS country, s.name AS state, s.iso_code AS state_iso
					FROM `'._DB_PREFIX_.'address` a
					LEFT JOIN `'._DB_PREFIX_.'country` c ON (a.`id_country` = c.`id_country`)
					LEFT JOIN `'._DB_PREFIX_.'country_lang` cl ON (c.`id_country` = cl.`id_country`)
					LEFT JOIN `'._DB_PREFIX_.'state` s ON (s.`id_state` = a.`id_state`)
					'.($share_order ? '' : Shop::addSqlAssociation('country', 'c')).'
					WHERE `id_lang` = '.(int)$id_lang.' AND `id_customer` = '.(int)$this->id.' AND a.`deleted` = 0';

            $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
            Cache::store($cache_id, $result);
            return $result;
        }
        return Cache::retrieve($cache_id);
    }

par contre cette clé ne me semble pas invalidée lorsque le client ajoute ou supprime une adresse...
 
ensuite, la requête $sql ci dessus en elle même est cachée par la fonction executeS($sql) dans Db.php
 

 public function executeS($sql, $array = true, $use_cache = true)
    {
        if ($use_cache && $this->is_cache_enabled && $array) {
            $this->last_query_hash = Tools::encryptIV($sql);
            if (($result = Cache::getInstance()->get($this->last_query_hash)) !== false) {
                $this->last_cached = true;
                return $result;
            }
        }

       ...

        $this->last_cached = false;
        if ($use_cache && $this->is_cache_enabled && $array) {
            Cache::getInstance()->setQuery($sql, $result);
        }

        return $result;
    }

la clé de cache étant l'encryptage de la requête qu'il voit passer, une requête du type :
 

SELECT DISTINCT a.*, cl.`name` AS country, s.name AS state, s.iso_code AS state_iso
FROM `ps_address` a
LEFT JOIN `ps_country` c ON (a.`id_country` = c.`id_country`)
LEFT JOIN `ps_country_lang` cl ON (c.`id_country` = cl.`id_country`)
LEFT JOIN `ps_state` s ON (s.`id_state` = a.`id_state`)
INNER JOIN ps_country_shop country_shop
ON (country_shop.id_country = c.id_country AND country_shop.id_shop = 1)
WHERE `id_lang` = 1 AND `id_customer` = 1 AND a.`deleted` = 0

tant que cette clé précise n'est pas invalidée ou que tant que la requête est identique (ce qui est la cas), le résultat retourné est le résultat qui a été mis en cache précédemment...
 
Soit, lorsqu'un client ajoute une adresse il ne peut pas la voir apparaître dans la liste de ses adresses... 
 
et ce comportement peut se constater sur une grande partie de ces requêtes dont le cache n'est pas invalidé correctement (la requête dans Product.php getImages() par exemple etc.)
 
Est-ce que quelqu'un utilise le cache sans rencontrer ces problèmes ?
 
Est-ce que vous avez une astuce pour les régler autre que simplement s'asseoir sur cette fonctionnalité pourtant prometteuse ?

 
Je vous remercie d'avance :)

Link to comment
Share on other sites

Bonjour, 

 

merci pour vos réponses, pourtant ils vantaient cette gestion de cache améliorée sur la 1.6.1 (lors du prestashop day et sur http://build.prestashop.com/news/prestashop-1-6-1-0-performances/ )

 

J'ai donc espéré pourvoir l'utiliser quitte à débugger un petit peu la feature, mais ce problème d'invalidation des requêtes sql que j'ai évoqué me semble encore bien énorme... (notre 1.6.1.4 est blindée d'overrides pour corriger d'autres fonctions inachevées ou buggées...)

 

En espérant que la team nous écoute et propose un peu plus de corrections / optimisations qui seront valables sur des boutiques en production :)

(car même si la 1.7 semble prometteuse sur certains points il faudra attendre encore pas mal de versions voir la 1.8 avant d'envisager une upgrade en prod)

Link to comment
Share on other sites

Désolé de vous décevoir mais Prestashop ne fonctionne pas en production avec les caches serveur (MemCache, APCcache, etc...)

Oubliez cette option, c'est une feature inachevée :(

 

Ca fait depuis 1.3 que je suis Prestashop, et à force je m'étais dit que ca devait bien fonctionner, que c'est moi qui suis trop bête pour configurer correctement, mais visiblement non. C'est comme les fameux media servers, j'ai jamais réussi à avoir une vraie réponse si ca fonctionne ou non ou comment configurer ca.

 

Heureusement que 1.6.14 tourne assez rapide même sans APC ou memcache, mais dommage quand même, 1-2 secondes de gain n'auraient pas fait de tord! :-(

Link to comment
Share on other sites

  • 2 months later...
  • 2 years later...

Aucun cache serveur.

Prestashop étant dynamique votre serveur va passer plus de temps à lire/effacer/ré-écrire le cache  plutôt que de renvoyer le résultat.

Si votre shop rame, il faut regarder si les requetes sql sont optimisées (index manquants, LEFT JOIN à la place de INNER JOIN), si un module ou plusieurs ne vient pas tout ralentir et si l'hébergement tient la route.

Edited by Eolia (see edit history)
Link to comment
Share on other sites

Non, car je refuse de travailler sur les 1.7 pour des raisons que j'ai déjà largement évoquées.

Il faut lancer le debug sql et voir le temps que prennent chaque requête et le nombre de rows renvoyés.

Il faut également regarder les temps pris par chaque module hooké.

Un Prestashop en bonne santé et même avec 100 000 produits doit avoir un TTFB (Time To Fist Byte, le temps que met le serveur à renvoyer le squelette de la page après l'avoir calculé) entre 250 et 700 millisecondes max.

Link to comment
Share on other sites

je viens de faire le test mais ça varie entre les différentes pages

quand je me met sur le tableau de bord j'obtient :

 

Temps de chargement

530 ms - Serveur web sous Licorne!
Temps d'interrogation 41 ms
Des requêtes 50
Utilisation maximale de la mémoire 12,0 Mo
Fichiers inclus 907 fichiers - 10,27 Mo
PrestaShop Cache 0.42 Mo
Global chaque 0,93 Mo
PrestaShop Version 1.7.4.2
PHP Version 7.0.33-0 + deb9u1 (envisager une mise à niveau)
Version MySQL 10.1.26-MariaDB-0 + deb9u1 (OK)
Limite de mémoire -1
Temps d'exécution maximum 259200s
Smarty Cache activée
Smarty Compilation auto
  Temps Temps cumulé Memory Usage Utilisation maximale de la mémoire
config 149ms 149 ms 7,10 Mo 7,12 Mo
__construction 0 ms 149 ms - Mo 7,12 Mo
init 129ms 278 ms 1,89 Mo 9,27 Mo
vérifier l'accès 0 ms 278 ms - Mo 9,27 Mo
ensembles setMedia en 20 ms 298 ms 0.46 Mo 9,57 Mo
post-traitement 0 ms 298 ms - Mo 9,57 Mo
initHeader 13 ms 312 ms 0,70 Mo 10,13 Mo
initContent 201ms 513 ms 1,39 Mo 11,58 Mo
initFooter 1 ms 513 ms 0,01 Mo 11,58 Mo
afficher 16 ms 530 ms 0,27 Mo 12.03 Mo

 

quand je me met dans la page des modules du back office : 

 

Load Time 1356 ms - OK... for a shared hosting
Querying Time 231 ms
Queries 457
Memory Peak Usage 28.3 Mb
Included Files 1385 files - 15.01 Mb
PrestaShop Cache 0.42 Mb
Global vars 1.88 Mb
PrestaShop Version 1.7.4.2
PHP Version 7.0.33-0+deb9u1 (Consider upgrading)
MySQL Version 10.1.26-MariaDB-0+deb9u1 (OK)
Memory Limit -1
Max Execution Time 259200s
Smarty Cache enabled
Smarty Compilation auto
  Time Cumulated Time Memory Usage Memory Peak Usage
config 1222 ms 1222 ms 27.21 Mb 27.21 Mb
__construct 0 ms 1222 ms - Mb 27.21 Mb
init 103 ms 1325 ms 0.50 Mb 28.18 Mb
checkAccess 0 ms 1325 ms - Mb 28.18 Mb
setMedia 3 ms 1328 ms - Mb 28.18 Mb
postProcess 0 ms 1328 ms - Mb 28.18 Mb
initHeader 13 ms 1341 ms 0.31 Mb 28.18 Mb
initContent 0 ms 1341 ms - Mb 28.18 Mb
initFooter 1 ms 1341 ms 0.01 Mb 28.18 Mb
display 15 ms 1356 ms 0.13 Mb 28.30 Mb

 

il faut vérifier toutes les pages du back office ? 

à priori le ps configuration à 17secondes :( 

Query Time (ms) Rows Filesort Group By Location
UPDATE `ps_configuration` SET `value` = '64275edd8762982e33b5e523bcf936c0',`date_upd` = '2019-01-07 15:37:55' WHERE `name` = 'CRONJOBS_ADMIN_DIR' AND (id_shop_group IS NULL OR id_shop_group = 0) AND (id_shop IS NULL OR id_shop = 0) LIMIT 1
17.5 1     /classes/Configuration.php:461
SELECT SQL_NO_CACHE c.`name`, cl.`id_lang`, IF(cl.`id_lang` IS NULL, c.`value`, cl.`value`) AS value, c.id_shop_group, c.id_shop
FROM `ps_configuration` c
LEFT JOIN `ps_configuration_lang` cl ON (c.`id_configuration` = cl.`id_configuration`)
10.1 1040     /classes/Configuration.php:157
Edited by mikka66 (see edit history)
Link to comment
Share on other sites

Test en front office

 

 

Load Time 849 ms - OK... for a shared hosting
Querying Time 520 ms
Queries 111
Memory Peak Usage 15.9 Mb
Included Files 594 files - 11.63 Mb
PrestaShop Cache 0.68 Mb
Global vars 1.66 Mb
PrestaShop Version 1.7.4.2
PHP Version 7.0.33-0+deb9u1 (Consider upgrading)
MySQL Version 10.1.26-MariaDB-0+deb9u1 (OK)
Memory Limit -1
Max Execution Time 259200s
Smarty Cache enabled
Smarty Compilation auto
  Time Cumulated Time Memory Usage Memory Peak Usage
config 59 ms 59 ms 3.55 Mb 3.58 Mb
__construct 0 ms 59 ms - Mb 3.58 Mb
init 59 ms 118 ms 1.28 Mb 4.88 Mb
checkAccess 0 ms 118 ms - Mb 4.88 Mb
setMedia 4 ms 122 ms 0.42 Mb 5.28 Mb
postProcess 0 ms 122 ms - Mb 5.28 Mb
initHeader 0 ms 122 ms - Mb 5.28 Mb
initContent 148 ms 270 ms 4.28 Mb 9.59 Mb
initFooter 0 ms 270 ms - Mb 9.59 Mb
display 579 ms 849 ms 3.84 Mb 15.92 Mb
Hook Time Memory Usage
0 hooks - ms - Mb
Module Time Memory Usage
0 modules - ms - Mb

Stopwatch SQL - 111 queries

Query Time (ms) Rows Filesort Group By Location
INSERT INTO `ps_connections` (`id_guest`, `id_page`, `ip_address`, `http_referer`, `id_shop`, `id_shop_group`, `date_add`) VALUES ('98633', '1', '631632018', '', '1', '1', '2019-01-07 17:01:20')
349.1 1     /classes/ObjectModel.php:529
SELECT SQL_NO_CACHE DISTINCT a.*, cl.`name` AS country, s.name AS state, s.iso_code AS state_iso
FROM `ps_address` a
LEFT JOIN `ps_country` c ON (a.`id_country` = c.`id_country`)
LEFT JOIN `ps_country_lang` cl ON (c.`id_country` = cl.`id_country`)
LEFT JOIN `ps_state` s ON (s.`id_state` = a.`id_state`)
INNER JOIN ps_country_shop country_shop
ON (country_shop.id_country = c.id_country AND country_shop.id_shop = 1)
WHERE `id_lang` = 1 AND `id_customer` = 61 AND a.`deleted` = 0
82.9 2     /classes/Customer.php:577
Link to comment
Share on other sites

La première requête indique un serveur sql pas mal surchargé (349 ms pour insérer une ligne) donc un mutu qui attend que le disque soit libre pour écrire.

La seconde est l'exemple type des requêtes Prestahop mal écrites.

une adresse a forcément un id_country et un pays a forcément une langue donc ces jointures devraient être des INNER mais bon...

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...