2017-06-27 2 views
0

J'ai une application java tcp socket. Tcp communicateur décode l'emplacement GPS et insère ces données dans la base de données et avant d'insérer nous faisons quelques sélections et mises à jour, mais tout ce que je fais en utilisant des instructions préparées. À l'heure actuelle, un thread de TCP communicateur sert une demande de périphérique. Immédiatement après la création du thread, nous obtenons une connexion à partir du pool. Après le décodage des données GPS est l'endroit où nous effectuons la sélection multiple, mise à jour et insérer pour chaque donnée. Comme le nombre d'appareils augmente, le nombre de connexions simultanées à notre base de données Mysql augmente également. Donc, j'essaie d'effectuer une simulation et un test de stress quelque chose comme ci-dessous. Le problème est qu'il s'agit d'un test séquentiel, mais dans un environnement réel, les périphériques viendront en parallèle. Comment atteindre une situation de stress proche de la réalité pour mysql et java pour savoir combien d'insertions pourraient être prises en compte en second?Test de stress parallèle à MySQL et java

public class stress1 extends Thread { 
    public static void main(String[] argv) { 
     try { 
      for (int i = 0; i < 5000; i++) { 
      Socket socket = new Socket("192.168.2.102", 8000); 
      PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 
      BufferedReader in = new BufferedReader(new InputStreamReader(
      socket.getInputStream())); 
      out.println("$A12345,30061104075130528955N10024852E000068*03A1*"); 
      System.out.println(in.readLine() + i); 
      out.close(); 
      in.close(); 
      socket.close(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     } 
    } 

Voici à quoi ressemble mon socket serveur.

public class comm8888 { 
    HikariDataSource connectionPool = null; 
    private Socket receivedSocketConn1; 
    ConnectionHandler(Socket receivedSocketConn1) { 
     this.receivedSocketConn1=receivedSocketConn1; 
    } 
    Connection dbconn = null; 
    public void run() { // etc 
    DataOutputStream w = null; 
    DataInputStream r = null; 
    String message=""; 
    receivedSocketConn1.setSoTimeout(60000); 
     dbconn = connectionPool.getConnection(); 
    dbconn.setAutoCommit(false); 
    try { 
     w = new DataOutputStream(new BufferedOutputStream(receivedSocketConn1.getOutputStream())); 
     r = new DataInputStream(new BufferedInputStream(receivedSocketConn1.getInputStream())); 
     while ((m=r.read()) != -1){ 
      //multiple prepared based sql select,update and insert here. 
     } 
    } 
    finally{ 
     try { 
      if (dbconn != null) { 
       dbconn.close(); 
      } 
     } 
     catch(SQLException ex){ 
      ex.printStackTrace(); 
     } 
     try{ 
      if (w != null){ 
       w.close(); 
       r.close(); 
       receivedSocketConn1.close(); 
      } 
     } 
     catch(IOException ex){ 
      ex.printStackTrace(System.out); 
     } 
     } 
    } 
} 
    public static void main(String[] args) { 
     new comm8888(); 
    } 
    comm8888() { 
     try { 
      HikariConfig config = new HikariConfig(); 
       config.setJdbcUrl("jdbc:mysql://localhost:3306/testdata"); 
       config.setUsername("****"); 
       config.setPassword("****");  
       config.setMaximumPoolSize(20);  
      connectionPool = new HikariDataSource(config); // setup the connection pool   
     } 
      catch (Exception e) { 
       e.printStackTrace(System.out); 
     } 
      try 
      { 
        final ServerSocket serverSocketConn = new ServerSocket(8888);     
        while (true){ 
          try { 
            Socket socketConn1 = serverSocketConn.accept(); 
            new Thread(new ConnectionHandler(socketConn1)).start();      
          } 
          catch(Exception e){ 
           e.printStackTrace(System.out); 
          } 
         } 
      } 
      catch (Exception e) { 
      e.printStackTrace(System.out); 
      } 
    } 
} 
+0

instructions d'insertion sont vraiment lent. Je ne le ferais pas comme ça. Je voudrais d'abord enregistrer toutes les données dans un arraylist et puis le charger jusqu'à la base de données en utilisant quelque chose comme LOAD DATA IN FILE. Tu ne peux pas faire ça? Si vous voulez voir à quel point les instructions d'insertion sont mauvaises, il suffit de les inclure dans votre boucle et vous verrez le désordre. – Arminius

+0

@Arminius Je peux les garder dans un tableau de la question, ils sont quelques milliers d'unités se connecteront dans une minute. Ainsi, chacun enverra des données individuelles. Mais avant cela, j'ai besoin de lancer quelques instructions de sélection et de mise à jour, puis enfin faire ces instructions d'insertion. – user8012596

Répondre

0

Votre solution ne s'adapte pas bien. Je voudrais encapsuler le travail à faire (localisation GPS d'un appareil) dans des objets de quelque classe, puis mettre chaque unité de travail dans une file d'attente. Enfin, un thread peut traiter tout le travail de manière séquentielle, en traitant une requête à la fois.

Si un thread ne peut pas suivre et que votre file d'attente est saturée, il est alors très facile d'effectuer une mise à l'échelle en ajoutant plus de travailleurs pour traiter les travaux de la file d'attente. (ou si une instance de MySQL ne peut pas gérer tous les inserts, vous pouvez aussi essayer par exemple le partitionnement horizontal de vos données et l'ajout de plusieurs instances MySQL).

ceci est un exemple de code:

import java.sql.Connection; 
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingQueue; 


public class QueueingDatabaseProcessingExample { 

    public static void main(String[] args) throws InterruptedException { 
     QueueingDatabaseProcessingExample a = new QueueingDatabaseProcessingExample(); 
     a.doTheWork(); 
    } 

    private void doTheWork() throws InterruptedException { 

     BlockingQueue<TcpCommunicatorUnitOfWork> blockingQueue = new ArrayBlockingQueue(1000); 

     // add work to queue as needed 
     blockingQueue.put(new TcpCommunicatorUnitOfWork("device id", 40.7143528, -74.0059731, 10)); // blocks if queue is full 


     Connection connection; 

     // get connection to the database from database pool 

     // process requests one by one sequentially 
     while (true) { 
      TcpCommunicatorUnitOfWork tcpCommunicatorUnitOfWork = blockingQueue.take(); // blocks if queue is empty 

      proccess(tcpCommunicatorUnitOfWork); 
     } 
    } 

    private void proccess(TcpCommunicatorUnitOfWork tcpCommunicatorUnitOfWork) { 
     // do queries, inserts, deletes to database 
    } 

} 


/** 
* this class should have all the information needed to query/update the database 
*/ 
class TcpCommunicatorUnitOfWork { 

    private final String deviceId; 
    private final double latitude; 
    private final double longitude; 
    private final int seaLevel; 

    public TcpCommunicatorUnitOfWork(String deviceId, double latitude, double longitude, int seaLevel) { 
     this.deviceId = deviceId; 
     this.latitude = latitude; 
     this.longitude = longitude; 
     this.seaLevel = seaLevel; 
    } 


} 
+0

merci pour l'idée. Actuellement, je suis en cours d'exécution multithread application sur le serveur où chaque client se connecte, il ouvre un nouveau thread. Alors, quel est l'inconvénient par rapport à votre suggestion? Votre suggestion consiste à faire l'insertion en vrac dans DB est-il? Je pense que finalement il arrive à la même chose que la file d'attente va s'ajouter à droite? Alors, où est la connexion socket fait le problème est que l'appareil ne ferme pas le socket pendant très longtemps est-ce une bonne ou une mauvaise chose? – user8012596

+0

La création et le démarrage d'un nouveau thread par client entraîneront un manque de ressources pour votre ordinateur et une surcharge inutile, car votre ordinateur ne peut pas exécuter trop de threads simultanément. Avec ma solution, vous contrôlez le nombre total de threads qui effectuent le travail réel (traitement, connexion à la base de données) –

+0

alors avec votre idée, vous avez toujours le multi-thread pour le socket? Parce que je ne vois pas le socket? Donc, je suppose qu'après avoir reçu les données, vous pompez dans un rite de file d'attente, mais cela ne ralentirait pas le processus. Donc, au cas où j'arrêterais mon application, tout ce qui est dans la file d'attente manquera? J'ai peur que tous les inserts soient ralentis, n'est-ce pas? – user8012596