我想测试我的系统与postgresql数据库的连接的吞吐量。我的系统由2个主要组件组成:ThreadPoolExecutor作为newFixedThreadPool最多10个线程和一个名为connectionPool的PGPoolingDataSource,最多有10个连接到数据库。我在postgres数据库中调用存储过程,存储过程做了一个简单的插入操作,并在插入失败时返回错误消息。执行此存储过程的单个调用大约需要20-30毫秒。使用线程池和连接池测试postgres数据库的吞吐量。但是,为什么我应该是6000时每秒只能有300个插入?
系统是这样工作的:主线程创建消息任务并将它们传递给线程池。消息任务执行以下操作:它从连接池获取连接并调用postgres服务器上的存储过程。它等待响应,然后任务完成。线程池中的线程现在可以处理新的消息任务。
现在,我认为这应该工作得很好,它在一定程度上。这只是非常缓慢,我完全不知道为什么。使用下面的代码,我记录大约300-500秒插入,当它应该是每秒6000插入。我不知道为什么。当使用系统监视器时,我看到所有的cpus都处于大约20%的负载。当我取消注释(1)所指的部分时,1个CPU处于100%负载,而其他CPU处于0%左右,这对我来说是个谜。
如果任何人都可以分享我做错的事情,那会很棒。难道我的postgres服务器配置不正确?当我使用top命令时,它显示java使用大约20%cpu,并且有8个postgres进程,每个使用大约3%。 (我使用Eclipse在Ubuntu 14.04上)。
这是我的MainTester代码,包含主要功能。它创建线程池和数据库连接池。
public class MainTester {
public static ThreadPoolExecutor threadPoolExecutor;
public static PGPoolingDataSource connectionPool;
public static void main(String[] args) {
establishConnectionPool(10);
threadPoolExecutor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
Operator operator = new Operator(1, 2, 30);
operator.run();
// i created an other thread here before.
//Now I just use the main thread to run the operator
}
private static void establishConnectionPool(int nrOfConnections)
{
connectionPool = new PGPoolingDataSource();
connectionPool.setDataSourceName("ConnectionPool");
connectionPool.setServerName(dbServerName);
connectionPool.setDatabaseName(dbName);
connectionPool.setUser(dbUser);
connectionPool.setPassword(dbPassword);
connectionPool.setMaxConnections(nrOfConnections);
}
这是我的操作员代码。它产生消息任务并将它们交给线程池。我想让它运行2分钟,然后检查它插入的消息数量。我希望始终保持线程池的队列已满,这就是为什么我检查线程池的队列是否少于1000个任务。如果它少了,我会为线程池产生新的任务来咀嚼。
public class Operator implements Runnable{
private int minutesToRun = 2;
private void run() {
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime < minutesToRun * 60 * 1000 + 10) {
while(MainTester.threadPoolExecutor.getQueue().size() < 1000) {
MessageTask messageTask = new MessageTask(QueueOperation.SEND, 1, 1, 1, "abc");
MainTester.threadPoolExecutor.execute(messageTask);
}
try { // (1)
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
(1)的时候,不睡觉这里,系统监视器的显示一个1级的CPU为100%,其余为0%。这对我来说没有意义。当然,这种方法将完全占用一个cpu,但线程池中的线程应该在另一个cpu上运行。
这里是我的消息任务代码:
public class MessageTask implements Runnable {
private QueueOperation operation;
private int senderId;
private int receiverId;
private int queueId;
private String message;
public MessageTask (QueueOperation op, int senderId, int receiverId, int queueId, String message)
{
operation = op;
this.senderId = senderId;
this.receiverId = receiverId;
this.queueId = queueId;
this.message = message;
}
@Override
public void run() {
Connection connection = null;
try {
connection = MainTester.connectionPool.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
try{
Statement statement = connection.createStatement();
String dbStoredProcedure = "SELECT send(" + senderId + "," + receiverId + "," + queueId + "," + "'"+message+"'"+ ");";;
ResultSet resultSet = statement.executeQuery(dbStoredProcedure);
resultSet.next();
String dbResponse = resultSet.getString(1);
}
catch (SQLException e) {
}
finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
所以我的问题是:为什么它这么慢?为什么我的全部8个产品只有20%的容量?也许我配置我的postgresql服务器是错误的?我没有改变任何默认配置。我误解了线程池的工作原理吗?还是连接池不能按我的意图工作?
为什么你使用存储过程来做一个简单的'INSERT'?由于上下文切换,从“SELECT”调用SP时总会有内在的缓慢。此外,不使用绑定变量进一步减慢了Postgres在执行语句之前必须执行的解析。 –
平行插入速度的基本问题:1.什么时候发生COMMIT?在每个插入? 2.表中有主键吗? #1有利于避免锁定,但对性能不利。 #2是相反的。 –
什么是磁盘负载? –