JeuWeb - Crée ton jeu par navigateur
Problèmatique charge SQL - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Problèmatique charge SQL (/showthread.php?tid=6497)

Pages : 1 2 3


Problèmatique charge SQL - Racktor - 10-11-2012




RE: Problèmatique charge SQL - Sephi-Chan - 10-11-2012




RE: Problèmatique charge SQL - Xenos - 10-11-2012

Pour ma part, j'avais le même genre de défaut de surcharge sur ECLERD. Une des solution au problème était effectivement de diminuer le nombre de requètes. Donc, une requète à 7 jointure était plus rapide que 7 requètes "simples", car le temps de connexion et de "mise en route" de SQL était non-négligeable face au temps de requète (imagine une requète lourde de 7ms+1ms le temps que SQL se mette en route, face à 7 requètes de 1ms de temps de requète +1ms le temps que SQL se mette en route, la requète lourde est plus rapide).

Egalement, tout ce que SQL sait faire doit être fait. S'il y a des calculs sur les colonnes à faire (somme, produits, max etc), des ordonnancement (groupes, ordres des résultats etc) alors il vaut mieux laisser SQL les faire plutôt que PHP (en tous cas, c'était bien plus rapide dans mon cas, un mutualisé perso chez OVH).

Pour le stockage quasi-statique, n'ayant pas les méthodes proposées par sephi, je me rabattais sur la génération d'une fichier PHP de constantes: la page d'admin PHP lit les données "semi-statiques" dans la BDD, puis enregistre ces données dans un fichier au format PHP, de la forme
<?php
define(<varname>, <var value>);
?>
Ce fichier PHP est ensuite utilisé par les pages web du jeu. Il est certainement possible de modifier légèrement ce système pour ne plus passer par la page d'admin et faire la regénération manuellement (par exemple, tu pourrai envisager d'enregistrer, dans le .php généré, la date de prochaine re-génération de ce fichier, et quand le fichier php du jeu récupère le php des semi-constantes, il vérifie la date de prochaine génération, et si elle est dépassé, il regénère le fichier tout comme le faisait la page d'amin). Cette méthode est assez redoutable, je trouve, pour tout ce qui est semi-constantes nombreuses (c'est vrai qu'une requète sur une table SQL de constantes, qui ferait moins de 20 lignes, ca dépote aussi tout à fait bien, mais si on a des requètes complexes, un système de fichier php pour les semi-constantes est un gain de temps).

Dernier élément: j'avais tendance à surmultiplier les requètes, ce qui est à éviter. Dans une première version, j'avais une boucle de 2000 tours, qui générait une requète pour récupérer toutes les informations d'une région du jeu... 2.000 requètes qui flinguent le serveur. Il vaut mieux, dans un tel cas, se prendre la tête pour ne plus faire "2.000 similations d'une région", mais "1 simulation d'un lot de 2.000 régions". Travailler par lots m'a permis de multiplier x100 la vitesse de simulation du jeu. Après, ceci n'est pas appliquable partout.

Elément-bonus: pour ma part, les données peu sensibles (en lecture-seule) mais récurrentes (nom du joueur par exemple), je les stocke dans des cookies chez le client: cela évite de faire des requètes serveur pour les lire, et si ces données sont peut sensibles, le fait que le client modifie les cookies n'influencera pas les autres joueurs. De même, certains traitements peuvent être fait chez le client via javascript, plutôt que chez le serveur (exemple: ordonnancement d'éléments, système de masquage/affichage des éléments d'une liste suivant, par exemple, des mots-clefs: s'il n'y a pas des tonnes d'éléments, je préfère tous les envoyer au client, et laisser le javascript faire les masquages/affichages hors-ligne, ce qui évite de recharger la page et de faire des requètes simplement parce que le client à décoché ou coché un tag).


Et je veux mon carambar.


RE: Problèmatique charge SQL - Damocorp - 10-11-2012

La doc vers apc pour php http://php.net/manual/fr/book.apc.php

Mais il est sur un hébergeur gratos je crois, et apc faut l'installer ( voir le configurer si tu as besoin).
Je le test actuellement en local, c'est super pratique.

Par contre on m'as conseillé d'utiliser APC pour la gestion automatique des fichiers php.
Et memcache pour les variables stocké en mémoire, ceci dans le but de le délocaliser sur un serveur mémoire en cas de besoin. Mais j'ai pas encore tester memcache.


Et pour la BDD, le seul moment ou j'ai pu voir des soucis de latence s'installer, c'est à l'époque ou je n'avais pas une bonne structure de clé pour les liaison.


RE: Problèmatique charge SQL - Sephi-Chan - 10-11-2012

D'ailleurs, ce qui est amusant à voir, c'est que ce sont vraiment des problèmes que seules les personnes qui développent from scratch avec EasyPHP (ou assimilé) rencontrent. Les frameworks permettent de s'occuper de ces problèmes de manière simple.

C'est un sujet à mettre dans un meta topic "Pourquoi devrais-je utiliser un framework ?".

Ce n'est pas une critique à l'égard des personnes concernées, c'est seulement un constat amusant. L'utilisation d'une technologie et d'un package prévu pour être simple complique les choses tant ça ferme les portes de solutions techniques qui existent et qui sont largement utilisées.


RE: Problèmatique charge SQL - Racktor - 10-11-2012




RE: Problèmatique charge SQL - Sephi-Chan - 10-11-2012

(10-11-2012, 02:12 PM)Racktor a écrit :
(10-11-2012, 11:06 AM)Sephi-Chan a écrit : Il faudrait voir la structure de ta base pour se prononcer sur les façons d'optimiser la structure.
Je peux fournir le dictionnaires des données que je peux avoir avec phpmyadmin. Mais laisser à la vue de tous la structure de mes bdd, je sais pas si c'est bon niveau sécurité si quelqu'un de mal intentionné tombe dessus ...

Je ne vois pas trop ce qu'un utilisateur malveillant pourrait en faire. Il n'y a pas accès. À toi de voir mais tu peux aussi décrire ton modèle sur les points où tu as besoin de conseils. Smile


(10-11-2012, 02:12 PM)Racktor a écrit :
(10-11-2012, 11:06 AM)Sephi-Chan a écrit : Après, le grand principe quand tu développes une application, c'est la surveillance. En production, ce qui n'est pas surveillé n'existe pas. Tu devrais avoir des outils qui t'indiquent (grâce à des graphes) la charge de ta machine, l'utilisation de RAM, le nombre de requêtes au serveur Web, au serveur SQL, etc. Un exemple d'outil de ce type : Munin. Partant de là tu sauras comment se comporte ton système normalement, et tu seras de fait capable d'identifier un comportement anormal.
Oui ca c'est vrai que ce que tu me décris est vraiment intéressant.
Juste une question sur l'utilisation :
je peux l'installer sur le serveur que j'ai chez power-heberg ou je dois faire ca en local ?

Tout au long de mon message, je considère que tu as accès à un serveur dédié. On ne peut pas héberger sainement une application sérieuse comme un jeu sur un serveur mutualisé.

C'est l'environnement de production qui est intéressant à monitorer, et ça implique que les outils de monitoring soient installés sur le serveur.

Ton hébergeur fait sans doute tourner les siens, mais je doute que tu y ai accès, et puis ça n'aurait aucun sens puisque la charge imposée n'est pas de ton ressort, mais également de celui de tous tes colocataires.


(10-11-2012, 02:12 PM)Racktor a écrit : je parle vraiment de données qui ne bougerais pas et donc pas fonction du joueur mais vraiment de ce qui est extrait de la Bdd

Dans ce cas, générer un fichier de constantes ou de variable peut être approprié. Tu peux utiliser la fonction var_export pour générer ce code.


(10-11-2012, 02:12 PM)Racktor a écrit : Ca c'est pas mal, je ne savais pas que PHP pouvait stocker des données de cette façon.
Quand on parle de cache on parle de quoi exactement dans ce cas ?
On peut stocker beaucoup de données ?
C'est quoi les limites de ce système ?

Pour faire ça avec PHP, ça implique d'avoir APC (ou Memcache, ou Redis). À nouveau, ça nécessite généralement un serveur dédié.

Tout dépend de ce que tu appelles beaucoup. Les plus petits serveurs dédiés à 12€ TTC par mois (Dedibox SC et Kimsufi mKS 2G) disposent de 2 Go de RAM, autant dire qu'une bonne partie de ta base de données pourrait tenir dedans (surtout si tu as peu de texte, qui pèse lourd en comparaison de nombres).

Regarde le poids (en octets) de tes variables grâce à cette petite fonction, et tu verras que pas mal de choses peuvent tenir dans 1 Mo est déjà pas mal.


function variable_size($var) {
$start_memory = memory_get_usage();
$tmp = unserialize(serialize($var));
return memory_get_usage() - $start_memory;
}

Un cache, c'est un outil qui va te permettre de servir de tampon pour éviter d'aller interoger une autre source de données dont l'accès serait plus coûteux. Ainsi, on peut stoker des données comme des nombres, des tableaux, des objets, etc. Ça inclut des bouts de HTML complets !

Je t'en ai montré un échantillon avec la fonction que je t'ai montrée dans mon message précédent : si la fonction (imaginaire) build_tech_tree implique des tas de requêtes SQL et des calculs coûteux.

On pourrait aussi imaginer les calculs d'une page pour afficher le classement : en créant une clé et en lui donnant un délai d'expiration (disons 10 minutes), on peut alléger considérablement les traitements d'une page coûteuse à générer.

La limite des caches sont généralement la présence de contenu spécifique à un utilisateur, puisqu'ils empêchent un élément d'être réutilisé pour tout le monde. Dans certains cas, utiliser un cache par utilisateur reste intéressant. C'est un calcul à faire. Smile

Dans la même veine, on n'est pas obligé d'utiliser une expiration en temps, on peut expirer les caches manuellement.

Reprenons l'exemple de l'arbre technologique.

Tu souhaites afficher l'arbre d'un joueur spécifique (qui reprend l'arbre générique que j'ai mis en cache dans mon précédent exemple) dans lequel on met en évidence les choix fait par le joueurs (les technologies qu'il a développé, et jusqu'à quel niveau, par exemple).

Il suffit de lister les choix qu'à fait le joueur puis de stocker ça dans APC avec une clé propre aux joueurs (disons players/1/tech_tree) grâce à une fonction telle que je te l'ai montrée (qui retourne la valeur stockée en cache ou la calcul puis la stocke et la retourne si elle n'y est pas).

Ensuite, tu pourras avoir une fonction qui accepte en argument l'arbre générique puis les choix d'un joueur et qui te produit le HTML pour afficher un bel arbre (ou une nouvelle structure que tu utiliseras pour générer le HTML).

Ensuite, lorsqu'un joueur développe une technologie, il suffit de supprimer la clé players/1/tech_tree du cache et il sera ainsi régénéré automatiquement au prochain affichage ! N'hésite pas à dire si tu ne comprends pas bien mes exemples ou ce que ça implique concrètement.

Après, on n'est pas obligé d'utiliser la mémoire pour ça, on peut aussi utiliser des fichiers.

Même sans utiliser de framework complet, tu peux toujours utiliser le composant Zend Cache de Zend Framework. Ça permet d'avoir une API commune et robuste, avec différents back-ends (mémoire, fichiers, etc.).


(10-11-2012, 02:12 PM)Racktor a écrit : A la rigueur si ca peut m'encourager à utiliser un Framework, tant mieux.
Par contre comment le Framework résout ce genre de pb (on parle bien de la surcharge SQL) ?

Pas forcément la surcharge SQL directement, mais tout le nécessaire pour avoir des données statiques chargée une seule fois, pour garder certaines ressources en cache, pour produire des requêtes SQL efficaces, etc.

Les bons ORM (des librairies pour manipuler la base de données au travers d'objets), savent produire des requêtes avec jointures pour charger les données liées d'une traite.

Imagine un système de commentaires avec auteur. J'ai un modèle Comment (qui utilise la table comments) qui dispose d'une colonne author_id pour faire le lien avec un modèle User (et sa table users). Mon ORM me permet très facilement de récupérer des messages en y joignant l'auteur. D'ailleurs, dans la plupart des cas, l'ORM ne va pas faire une jointure mais va va charger d'abord les messages, puis récupérer toutes les valeurs author_id, puis chercher tous les utilisateurs portant ces IDs et rattacher les objets User aux commentaire appropriés.


RE: Problèmatique charge SQL - Damocorp - 10-11-2012

Cool l'explication sur les ORM, j'avais cherché sur le net, et c'était pas clair Smile

Citation :Merci pour la documentation j'avoue que Sephi-Chan m'avais un peu perdu sur ce point mais la je comprends mieux.
Par contre tu veux dire quoi par "gestion automatique des fichiers php" ?

Va me falloir de l'aide car j'ai pas encore tout compris.
Mais en gros :
Citation :Par défaut, APC vérifie le script à chaque demande pour voir s'il a été modifié ou non.
S'il a été modifié, il sera compilé à nouveau et la nouvelle version sera mise en cache.
En désactivant cette option, aucune vérification n'aura lieu. Cela signifie que si vous voulez activer les modifications, vous devez redémarrer le serveur web.
Sur un serveur de production où vous modifiez rarement le code, le fait de désactiver cette option permet de gagner en performances de manière significative.

source siteduzero
APC va aussi mettre des fichiers en cache pour éviter d'aller les chercher sur le disque dur. Et il garde la version compilé d'après ce qu'il est marquer. ( moi c'est l'histoire de la compilation que je pige pas encore )

Donc mémoire > HD en vitesse d'accès => Gain de vitesse.
Pas de recompilation => gain de vitesse.

Lit le tuto du site du zéro, c'est clair, et ensuite la doc php Big Grin


Dans chacune des pages que tu demande sur mon jeu, il existe une page php invisible qui est intégré. Celle-ci contient ma gestion d'APC. Exemple :

[pastebin]Fh1zk4Z0[/pastebin]

En gros, quelque soit le joueur, le N° de partie, la date de début, et la date de fin sont identique. Je stock donc ca dans APC pour éviter les requêtes à la BDD.
Donc lorsqu'on demande un page, pour éviter une requête, j'affiche tout via apc_fetch.

Mais pour éviter les vérifications dans mon code, j'ai ce fichier php qui s’occuper d'APC. Et vérifie si les données existe. Si elle n'existe pas il les crée et stock dans APC.

Maintenant niveau calcul cela donne :
1 requête par page et par visiteur gagné tant que la donnée existe.

Imagine que j'ai 50 joueurs qui demande chaque jours 100 pages du site et ce 3 fois par jours.
On obtiens 50*100*3= 15.000 requêtes en moins pour le serveur par jours.

J'ai trouvé ca ahurissant Big Grin
En extrapolant sur tout un site, ca peut faire gagner pas mal de requête inutile Smile


RE: Problèmatique charge SQL - Sephi-Chan - 11-11-2012

APC contient 2 composants : un système de stockage et un cache d'opcode (le code intermédiaire de PHP, habituellement généré à chaque exécution d'un fichier). Ce cache d'opcode améliore la vitesse d'exécution des scripts sans rien avoir à faire. Le cache d'opcode permet de stocker des structure parfois complexes de manière globale.

Par ailleurs, vous devriez vraiment arrêter avec vos histoires de requêtes inutiles. Une requête n'est pas inutile, sinon vous ne la feriez pas. Que vous interrogiez MySQL, APC, Memcache, MongoDB, etc. vous récupérez des données dans une base de données et c'est utile et ça prend du temps : ce n'est pas parce que vous tapez dans autre chose que MySQL que c'est gratuit.

Le code que tu présentes n'a pas vraiment de sens : ta requête doit retourner plusieurs lignes, donc il faudrait stocker des clés APC portant un identifiant, pour ne pas écraser la même sens cesse (en les nommant parties/1, par exemple). De plus, plutôt que d'avoir 3 clés scalaires, tu peux stocker un hash ou un objet dans une unique clé.


RE: Problèmatique charge SQL - Akira777 - 11-11-2012

Plutôt d'accord avec Sephi.

Quand j'étais jeune développeur PHP, je me posais tous le temps la question, est-ce que cette requête est utile, dès que je dépassais 5 requêtes par page, je me privais de mettre en place des fonctionnalités pour ne pas augmenter la charge. Mais d'un autre côté, j'ai toujours bien découpé mon code en fonction (avant de passer à l'objet).

Ne te prend pas la tête, comme le dit Sephi : "Premature optimization is the root of all evil.".

Va au bout de ton projet. Code tout ce dont tu as besoin et puis fais tes requêtes tant que tu en as besoin.
Quand tu auras un tout fonctionnel, et que tu constateras que ce que tu as fais est gourmand tu trouveras toujours un moyen de l'optimiser, point par point.

Du genre :
- tiens ici, obtenir la liste des joueurs connectés me prend du temps ? je modifie ma fonction pour stocker ça dans mon cache APC, et je remet à jour toutes les 5 minutes.

- tiens, là, quand l'utilisateur fais ça, j'effectue cette requête plutôt lourde, mais le résultat de cette dernière ne change pas souvent. J'identifie ce qui fait varier le résultat de cette requête et je met en place un cache adapté. Si deux autres actions font varier le résultat, je mais en place à ces deux endroits précis, une mise à jour de ce cache.

Bon, ce sont des cas bateaux, mais l'idée est là. Pense d'abord à ton application, la charge, tu as tout le temps d'y penser, ce n'est pas un vrai problème.