Nous utilisons un thème personnalisé OpenCart 1.5.5.1 pour notre site.
Cela n’a pas été facile pour nous et nous sommes confrontés problème après problème. Jusqu'ici, l'essentiel est que nous sommes actuellement sur un hôte SSD d'entreprise (toujours partagé, je crois) pour tester les performances du site (uniqpcs.co.uk). Il s'agit d'une période d'essai permettant de tester le chargement du site. site (en utilisant l’impact de la charge). Chaque fois, lors de l’exécution du test, il semble que la limite du processus d’entrée soit atteinte, ce qui empêche le site de répondre et finit par se bloquer (la limite du processus d’entrée est fixée à 20 sur notre cPanel - même essayé 40 mais toujours le même problème).
Été en contact avec le fournisseur d’hôte (NameCheap) dans les deux sens par e-mail et chat en direct sans aucune aide réelle, malheureusement, mais ils m’ont mentionné un certain nombre de points que j’espère vous aider à préciser:
D'après ce que j'ai compris, la limite Processus de saisie est atteinte lorsqu'un processus (très probablement les scripts PHP) est suspendu beaucoup plus longtemps que prévu et retard entraîne l’accumulation de plus en plus importante de processus, le site devient alors insensible et finit par atteindre sa limite.
À partir de leur journal d'erreur MySQL, ils ont déterminé que la base de données n'était "apparemment" pas très optimisée avec 126 tables et un total de 26791 lignes. Ils ont également indiqué qu'une requête SELECT dans MySQL traitait trop longtemps en raison du nombre important de lignes:
Veuillez trouver les journaux du serveur MySQL ci-dessous:
# Time: 140501 8:37:23
# User@Host: auniqpcs_uniqpc[auniqpcs_uniqpc] @ localhost []
# Query_time: 12.059221 Lock_time: 0.004748 Rows_sent: 1 Rows_examined: 26731
SET timestamp=1398947843;
SELECT COUNT(DISTINCT p.product_id) AS total FROM category_path cp LEFT JOIN product_to_category p2c ON (cp.category_id = p2c.category_id) LEFT JOIN product p ON (p2c.product_id = p.product_id) LEFT JOIN product_description pd ON (p.product_id = pd.product_id) LEFT JOIN product_to_store p2s ON (p.product_id = p2s.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND cp.path_id = '211';
# User@Host: auniqpcs_uniqpc[auniqpcs_uniqpc] @ localhost []
# Query_time: 12.081561 Lock_time: 0.004338 Rows_sent: 1 Rows_examined: 26746
SET timestamp=1398947843;
SELECT COUNT(DISTINCT p.product_id) AS total FROM category_path cp LEFT JOIN product_to_category p2c ON (cp.category_id = p2c.category_id) LEFT JOIN product p ON (p2c.product_id = p.product_id) LEFT JOIN product_description pd ON (p.product_id = pd.product_id) LEFT JOIN product_to_store p2s ON (p.product_id = p2s.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND cp.path_id = '258';
# Time: 140501 8:37:26
# User@Host: auniqpcs_uniqpc[auniqpcs_uniqpc] @ localhost []
# Query_time: 13.821338 Lock_time: 0.005288 Rows_sent: 1 Rows_examined: 26746
SET timestamp=1398947846;
SELECT COUNT(DISTINCT p.product_id) AS total FROM category_path cp LEFT JOIN product_to_category p2c ON (cp.category_id = p2c.category_id) LEFT JOIN product p ON (p2c.product_id = p.product_id) LEFT JOIN product_description pd ON (p.product_id = pd.product_id) LEFT JOIN product_to_store p2s ON (p.product_id = p2s.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND cp.path_id = '245';
# Time: 140501 8:37:32
# User@Host: auniqpcs_uniqpc[auniqpcs_uniqpc] @ localhost []
# Query_time: 16.426658 Lock_time: 0.010242 Rows_sent: 1 Rows_examined: 26746
SET timestamp=1398947852;
SELECT COUNT(DISTINCT p.product_id) AS total FROM category_path cp LEFT JOIN product_to_category p2c ON (cp.category_id = p2c.category_id) LEFT JOIN product p ON (p2c.product_id = p.product_id) LEFT JOIN product_description pd ON (p.product_id = pd.product_id) LEFT JOIN product_to_store p2s ON (p.product_id = p2s.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND cp.path_id = '245';
Pendant le traitement, l'outil de chargement envoie une autre requête PHP qui "transmet" la requête à MySQL (tant que la première requête SQL est en cours de traitement). Il est également possible que PHP demandes renvoyées à MySQL soient mal codées.
pingdom: http://tools.pingdom.com/fpt/#!/bzzDid/uniqpcs.co.uk
J'aimerais vraiment savoir quelle est la cause exacte de ce problème, est-ce que le script PHP est mal codé, s'agit-il des requêtes sur la base de données MySQL ou de l'hôte?
Maintenant, je ne suis pas trop sûr de ce qu'il faut faire .... tout conseil est apprécié.
Selon ce:
http://docs.cloudlinux.com/entry_processes_limit.html
Les limites du processus de saisie sont conçues pour empêcher les pirates informatiques de ralentir le serveur.
Ce que vous devriez faire, c'est regarder de plus près votre temps de traitement.
Effectuez un test sur webpagetest.org et vérifiez les valeurs pour "time to first byte". S'il dépasse 1/5ème de seconde, il s'agit d'un problème de traitement et les premières choses à examiner sont les composants dont la page Web a besoin ET la partie de la base de données sur laquelle vous avez besoin de données et à quel moment.
Donc, si vous exécutez une page Web qui charge une feuille de style externe, un fichier javascript externe et un ensemble d’images externes (en particulier de grandes images de haute qualité) dont les URL pointent vers le même serveur que la page Web elle-même, des ralentissements plus importants peuvent se produire. anticipé car le nombre de requêtes par utilisateur peut se multiplier assez rapidement.
Vérifiez également la base de données. Si le code qui est toujours exécuté consiste à rechercher quelque chose de complexe avec la plus grande table, comme obtenir un nombre réel de lignes, attendez-vous à un délai d'attente supplémentaire de 200 ms par demande d'élément. Essayez de résoudre ce problème en stockant les données fréquemment demandées dans une table séparée et en les lisant.
Exemple:
Imaginez une table appelée CFG qui stocke des données de configuration aléatoires dans lesquelles les noms de champs sont "nom" et "valeur" et une table appelée ABC contenant plus de 1 000 000 enregistrements et vous ne savez pas exactement combien il y en a.
Naturellement, on pourrait exécuter:
Select count(*) as Total from ABC;
Pour obtenir le nombre d’éléments et conserver le résultat dans une nouvelle colonne temporaire nommée Total. Je viens de faire cela sur une table avec plus de 900 000 enregistrements sur un Pentium 4 et il m'a fallu environ 4 secondes pour obtenir un décompte.
Dans cet exemple, vous souhaitez plutôt ajouter une nouvelle valeur de configuration qui peut être constamment recherchée, comme suit:
Insert Into CFG(Name,Value) Values("tabletotal","0");
Update CFG set Value=(Select count(*) as Total from ABC) where CFG.Name="tabletotal";
Ensuite, pour vérifier que le numéro a bien été ajouté, recherchez l'intégralité de votre table de configuration avec cette instruction:
Select * from CFG;
Ensuite, dans votre script, si vous avez utilisé un exemple comme celui-ci, changez:
Select count(*) as Total from ABC;
À:
Select Value from CFG where Name="tabletotal";
Vous économiserez alors énormément de temps de traitement et les chances d'atteindre la limite de traitement des entrées seront considérablement réduites.
"D'après ce que j'ai compris ....."
Pas vraiment. Certes, plus de demandes signifie plus de processus et plus de demandes, plus de processus simultanés. Mais cela ne devrait pas être votre point de départ pour la gestion de la capacité sur un serveur, à moins que votre modèle commercial ne consiste à gagner de l'argent en vendant de la capacité de traitement.
Déterminer exactement le nombre de demandes simultanées que votre pile peut gérer est un problème complexe qui nécessitera un accès beaucoup plus profond à votre système que celui exposé dans cpanel. Vous n'avez fourni aucun détail sur les spécifications du matériel, mais je m'attendrais à ce que quelque chose de comparable à un poste de travail à faible spécification (2 cœurs/2 Go) puisse traiter simultanément environ 70 à 130 demandes, mais cela peut varier considérablement en fonction des applications. code.
Votre plus gros problème actuellement est votre SGBD - votre ensemble de données est minuscule, mais le temps nécessaire à l’exécution de vos requêtes est énorme. Votre base de données est si petite que vous n'obtenez probablement aucun avantage significatif à utiliser un fichier SSD. Vos données doivent toutes tenir dans la RAM. Mais ces temps de requête sont vraiment affreux. Malheureusement, il n'y a pas de solution miracle pour cela. Vous devez savoir comment analyser et modifier le schéma.
Je recommanderais certainement de configurer votre propre machine dédiée aux tests. Bien que vous ayez un accès suffisant pour identifier la cause de la plupart des problèmes de base de données sans nécessiter un accès administrateur complet, cela sera nécessaire pour certains des correctifs. Et vous aurez besoin d'un accès root pour aller au fond des problèmes du PHP et du serveur Web.
Vous avez beaucoup d'apprentissage devant vous. Il est mal vu de recommander des produits spécifiques. Je vous recommanderai donc Google pour les livres sur Linux, Apache, MySQL et PHP Optimisation des performances.
mise à jour
Je viens de regarder votre site. La page d’accueil ne présente pas les symptômes de problèmes de SGBD - les entrées de journal que vous avez mentionnées ci-dessus peuvent être des anomalies. Cependant, il existe des problèmes de rendu front-end épouvantables. Notamment le fait que la première page compte plus de 400 images.
Selon mon navigateur Web, la seule page HTML représente environ 35 Ko en HTML, soit environ 15 Ko de plus qu’elle ne devrait l’être. En outre, le nombre d'éléments chargés était de 458, ce qui nécessitait plus de 6,4 Mo de données. Une âme pauvre qui peut toujours utiliser une connexion 56K à vitesse maximale aurait besoin d'attendre au moins 19 minutes pour que la page principale soit entièrement chargée.
Une chose qui peut grandement aider est de consolider vos images et vos scripts.
Regardez dans les sprites CSS. C'est un moyen facile d'accélérer le chargement des images et offre l'avantage de rendre votre serveur moins touché, ce qui le rend globalement plus rapide.
Fusionnez tous vos styles CSS et supprimez les espaces inutiles. Pour plus de rapidité, supprimez les commentaires. Essayez d’avoir UN SEUL fichier CSS par page, et non 20+.
Faites la même chose avec les fichiers Javascript. Consolidez-les en un.
Lorsque j'ai chargé votre site, j'ai remarqué une image d'arrière-plan qui s'est chargée avant tout le reste chargé. Je ne vois pas un réel avantage, et le supprimer aiderait à rendre le site plus rapide.
J'ai aussi remarqué une mauvaise sortie d'en-tête quand je suis allé voir les en-têtes:
HTTP/1.1 200 OK
Date: Mon, 02 Feb 2015 01:39:12 GMT
Server: Apache/2.2.27 (Unix) mod_ssl/2.2.27 OpenSSL/1.0.1e-fips mod_bwlimited/1.4
X-Powered-By: PHP/5.3.28
Pragma: no-cache
Nitro-Cache: Enabled
Cache-Control: public, max-age=31536000
Expires: Wed, 04 Mar 2015 01:39:12 GMT
Set-Cookie: PHPSESSID=c37c0a5a0d115149b494fae5cf5b1d78; path=/
Last-Modified: Sun, 01 Feb 2015 23:41:06 GMT
Vary: Accept-Encoding,User-Agent
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Avec un tel en-tête, les navigateurs vont probablement redemander la page même si la copie la plus récente est stockée localement. Pour résoudre ce problème, ces lignes doivent être supprimées:
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Pragma: no-cache
J'ai utilisé l'outil de ligne de commande CURL pour vérifier les en-têtes.