Java和mysql高并发瓶颈解决方案

时间:2017-06-23 18:33:16

标签: java mysql

我们正在开发一种车辆跟踪系统,其中多个GPS设备使用Tcp连接将其GPS位置发送到服务器。 Tcp通信器解码GPS位置并将该数据插入数据库,在插入之前我们做了一些选择和更新,但我只是使用预处理语句。现在,TCP通信器的一个线程服务于一个设备请求。在创建线程之后,我们立即从池中获得一个连接。在解码GPS数据之后,我们执行多重选择,更新和插入每个数据。随着设备数量的增加,与Mysql数据库的并发连接数也在增加。我们现在预计每分钟会有30到5万个设备抽取数据。目前下面是整个tcp通信器的片段如何。我知道最终我们将面临插入数据库的瓶颈。在这种情况下,最好的解决方案是什么? Java还能够处理这么多并发吗?

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);

          }

    }
} 

2 个答案:

答案 0 :(得分:2)

一个问题是,如果设备编号增加,每个设备都会尝试连接不可扩展解决方案的数据库。 一种方法是异步处理批处理。将所有消息存储在队列中,直到达到批量大小,然后作为批处理插入。当你不是逐个插入记录时,它将保存网络。

如果您需要进一步的可扩展解决方案,那么可以使用nosql解决方案或主 - 主复制多节点拓扑来支持大流量和可用性。

对于选择和更新,您可以使用需要在您的用例上进行分析的合并查询。如果存在,则更新查询将更新,如果不存在则更新。

答案 1 :(得分:1)

从评论转到此处再解释一下。

dbconn = connectionPool.getConnection();
...
while (...) {
   // dbconn is held for up to 60 seconds which is not scalable
} 

因此,当有实际操作可以避免长期数据库连接时,你可以获得一个dbConn

while (...) {
    // got some more data to process - now get a dbConn 
    dbconn = connectionPool.getConnection();
    // do inserts, etc.
    // commit and release the connection!
} 

另一种方法是通过发布到队列或调用REST服务来完全卸载与数据库的交互。

while (...) {
    // got some more data to process
    // publish the data to a JMS queue
    // or post the data to a REST endpoint
    // there is no database interaction here at all!
} 

然后消息使用者或REST端点处理数据并插入/更新数据库。这些消息/请求中的每一个都很小,因此数据库连接只从池中借用了几毫秒(最多)。处理JMS消息/ POST请求的服务器集群可以独立于最初接收原始套接字数据的服务器进行扩展。