我有一个java tcp套接字应用程序。 Tcp通信器解码GPS位置并将该数据插入数据库,在插入之前我们做了一些选择和更新,但我只是使用预处理语句。现在,TCP通信器的一个线程服务于一个设备请求。在创建线程之后,我们立即从池中获得一个连接。在解码GPS数据之后,我们执行多重选择,更新和插入每个数据。随着设备数量的增加,与我们的Mysql数据库的并发连接数量也在增加。所以我正在尝试进行模拟和压力测试,如下所示。问题在于这是顺序测试,但在实际环境中,设备将并行进行。如何实现mysql和java的近乎真实的压力情况,以找出mysql可以在第二个接受多少插入?
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();
}
}
}
以下是我的服务器套接字的样子。
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 :(得分:0)
您的解决方案无法很好地扩展。我会将要完成的工作(设备的GPS位置)封装在某个类的对象中,然后将每个工作单元放入队列中。最后,一个线程可以按顺序处理所有工作,一次处理一个请求。
如果一个线程无法跟上并且您的队列已满,那么通过添加更多工作人员来处理队列中的作业,可以非常轻松地进行扩展。 (或者,如果MySQL的一个实例无法处理所有插入,您还可以尝试对数据进行水平分片并添加多个MySQL实例)。
这是一些示例代码:
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;
}
}