IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

MySQL en multithread pour MMORPG?


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Inscrit en
    Mai 2011
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mai 2011
    Messages : 17
    Par défaut MySQL en multithread pour MMORPG?
    Bonsoir,

    J'ai un serveur d'MMORPG en Java (open source) mal optimisé à ce qu'il parait. (Je ne suis pas le créateur, je cherche juste à l'optimiser un petit peu).

    Le serveur tourne bien, chaque client a son propre thread, mais une fois plus de 600 joueurs se connectent, le serveur commence à rencontrer des lags quand il s'agit de requêtes MySQL.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public synchronized static ResultSet executeQuery(String query) throws SQLException
    {
    	if(!_isInit)
    		return null;
     
    	Connection DB = _dynamiqueCon;
     
    	Statement stat = DB.createStatement();
    	ResultSet RS = stat.executeQuery(query);
    	stat.setQueryTimeout(300);
    	return RS;
    }
    Après avoir jeter un coup d’œil sur le code j'ai vue cette fonction dans la class de base de donnés. C'est la fonction qui permet d’exécuter des requêtes MySQL, elle est très appelée dans le code. Elle doit être très optimisé à mon avis, help

    Bref, etant donné que chaque client a son propre Thread, quand plus de 600 joueurs se connectent les requettes mysql se font une par une (à cause de: synchronized dans la fonction je pense).

    J'aimerais savoir si je retire le "synchronized" dans la déclaration, est-ce que je risque des problèmes? Je veux que la fonction soit appelé plusieurs fois car le serveur dépends trop de MySQL pour sauvegarder les personnages à chaque fois.

    Qu'est ce que je dois ajouter à la fonction pour qu'elle s'exécute en multhithreading sans problèmes ?


    Go easy on me les gars, je députe en Java.

  2. #2
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Oui tu risque des emmerde puisque les objets provenant du driver ne sont pas prévu pour un accès concurrent. Pour gérer correctement du multithread avec une base de donnée il faudrait que chaque thread aie sa propre connexion, mais ca nécessite probablement un redesign complet de l'application qui est derrière car il va falloir gérer les transactions.


    De prime abord, pour du "massif", avoir un thread par joueur c'est en général pas la panacée. 600 joueurs c'est peu pour du massif, et une application ne supportera jamais 50.000 threads.

  3. #3
    Membre averti
    Homme Profil pro
    Inscrit en
    Mai 2011
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mai 2011
    Messages : 17
    Par défaut
    Merci pour ta réponse tchize_.

    J'ai quand même essayer de créer environs 6 autres connexions, et une fonction que j'ai nommer: getNextConnexion() qui switch entre les 6 connexions à MySQL. Il parait que ça soulage le serveur coté requêtes, et ça marche.

    Je ne suis pas sûr si c'est ce qu'on appelle le pooling, mais ça marche en tout cas.

  4. #4
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Un connexion pool c'est une peu plus complexe que ça a gérer. En gros, avec un connexion pool, votre méthode devrais ressembler à ça pour être valable.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public synchronized static void executeQuery(String query) throws SQLException
    {
     
    	Connection DB = dataSource.getConnection(); // prend une connexion du pool
            try{
                Statement stat = DB.createStatement();
                try{
    	      ResultSet RS = stat.executeQuery(query);
                  try{
    	        stat.setQueryTimeout(300);
    	        // traiter le résultat
                  } finally {
                    RS.close(); // libère le resultset
                  }
                } finally {
                    stat.close(); // libère le statement
                }
            } finally {
              DB.close(); // rend la connexion au pool
            }
     
    }
    Accessoirement, votre méthode précédent commet les erreurs suivantes qui tôt ou tard vous pêteront à la figure:

    Risque de réutilisation par un autre thread de la connexion alors qu'on a pas fini d'utiliser le resultset qui en est sorti.
    risque de fuite mémoire dans le driver à cause des statement et du resultset qui ne sont pas fermés.

  5. #5
    Membre averti
    Homme Profil pro
    Inscrit en
    Mai 2011
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mai 2011
    Messages : 17
    Par défaut
    Merci pour votre réponse.

    Je n'ai jamais fais de pooling, à peine je viens de découvrir ce mot il y a quelques jours. Je crois que c'est ce que j'ai fait dans mon code. Voici une partie du code pour expliquer:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    private static ArrayList<Connection> _poolConnexionsList = new ArrayList<Connection>();	//pool de connexions.
    private static int _poolCursor	=	0;	//Curseur qui permet de switch en série (à tour de rôle) entre les pools.
     
     
    private static Connection getNextConnexion()
    {
    	try {
    		_poolCursor++;
    		if((_poolCursor+1)>_poolConnexionsList.size())_poolCursor=0; // Reset le curseur.
     
    		return _poolConnexionsList.get(_poolCursor);
    	} catch (Exception e) {
    		e.printStackTrace();
    		return _poolConnexionsList.get(0);// Doit pas arriver, mais on return la première connexion dans la liste au cas où.
    	}
    }
     
    public static ResultSet executeQuery(String query) throws SQLException // Ce n'est pas syncronisé !
    {	
    	Connection DB = getNextConnexion(); // la function en haut.
     
    	Statement stat = DB.createStatement();
    	stat.setQueryTimeout(120);//2min
    	ResultSet RS = stat.executeQuery(query);
     
    	return RS;
    }
     
    public static void refreshIfClosed(){ ... }
    public static void createConnexions() { ... }
    _poolConnexionsList contient une liste de connexions à MySQL qui restent ouvertes pour toute la session. Et getNextConnexion() en choisis une à chaque fois à tour de rôle.

    J'ai tester hier ceci, en créant à peu près 256 Connexions dans _poolConnexionsList.

    Résultat: 256 fois plus de vitesse dans mon serveur
    Le serveur n'a pas crash, RAM été stable (je ne pense pas qu'il y a du memory leaking). ça fait déjà 12heurs d'upTime pour mon serveur sans problèmes..

    Toutes fois, vue que je débute en Java, je ne suis toujours pas sûr de moi malgré ces résultats. J'ai besoin d'avis de pro, pouvez-vous confirmer que ma technique est bonne s'il vous plait? Quelles seront les inconvénients à votre avis? Ce que j'ai fais là c'est bien le pooling, exacte ?

    Merci pour vos réponses, c'est très apprécié.

  6. #6
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,



    Ca "marche" peut-être mais ce n'est pas correct, et ca risque de te répéter à la figure si la charge augmente encore...



    Déjà ton pool est trop simpliste, et si tu as plus de 256 users simultanées, certains vont partager la même connexion
    De plus tu considères que la connexion sera toujours valide, ce qui ne sera pas forcément toujours le cas !!!

    Utilises de préférence un vrai système de pool au lieu de réinventer la roue. Surtout qu'il y a plein d'implémentation existante.
    Si tu tournes sous un serveur J2EE tu dois surement déjà avoir cela (voir la doc de ton serveur pour le configurer), sinon tu peux utiliser Commons DBCP par exemple...





    Enfin tu ne libère jamais tes ressources. La RAM de ton application reste peut-être stable mais le fait de ne pas libérer les Statment/ResulSet peut bloquer certains ressources sur ton serveur de BD

    Donc il faut impérativement libérer tous les Statment/ResulSet via des try/finally comme l'indique tchize_

    Et de même pour la Connection avec un vrai système de pool : le fait de la fermer la rendra au pool qui pourra la réutiliser...



    a++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [MySQL] [débutant] probleme pour recuperer ID max et ID min
    Par fabien14 dans le forum Langage SQL
    Réponses: 1
    Dernier message: 25/09/2006, 10h48
  2. [[xml]->[php]->[MySQL]] script php pour lire du xml
    Par koudjo dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 2
    Dernier message: 30/06/2006, 03h18
  3. MySQL - LOCK invisible pour le SELECT
    Par SergentHeinz dans le forum Requêtes
    Réponses: 2
    Dernier message: 03/01/2006, 10h47
  4. Mysql (5) Embarquée pour le OFFLINE
    Par joe_le_mort dans le forum Installation
    Réponses: 3
    Dernier message: 15/11/2005, 19h34
  5. Réponses: 2
    Dernier message: 05/07/2004, 17h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo