繁体   English   中英

使用线程池和连接池测试postgres数据库的吞吐量。 但是为什么我每秒只有300次插入,而应该是6000次呢?

[英]Testing Throughput of postgres database using thread pool and connection pool. But why do I only have 300 inserts per second when it should be 6000?

我想测试与PostgreSQL数据库连接的系统的吞吐量。 我的系统由2个主要组件组成:一个为newFixedThreadPool的ThreadPoolExecutor,最多具有10个线程,一个称为connectionPool的PGPoolingDataSource,其与数据库的最多10个连接。 我在postgres数据库中调用存储过程,该存储过程执行简单插入,如果插入失败,则返回错误消息。 执行一次此存储过程的调用大约需要20到30毫秒。

系统的工作方式如下:主线程创建消息任务,并将其传递给线程池。 消息任务执行以下操作:它从连接池获取连接,并在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代码,其中包含main函数。 它创建线程池和数据库连接池。

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%,其他cpu占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();
        }
    }

}

所以我的问题是:为什么它这么慢? 为什么我的全部cpus都只有20%的容量? 也许我将Postgresql服务器配置错误? 我没有更改默认配置中的任何内容。 我是否误解了线程池的工作方式? 还是连接池无法正常工作?

当测量存储的proc执行时间时,您可能没有考虑提交花费的时间。 您似乎也将注意力集中在CPU上,而完全忽略了磁盘I / O和磁盘刷新的成本。

对于具有基本SSD的典型系统而言,每秒300个事务是一个相当合理的数字。 因此,我想说您是在每次插入之后提交。

为了获得更快的结果,您需要:

  • 将工作分批处理成多次插入的事务;
  • 启用commit_delay并将synchronous_commit = off设置synchronous_commit = off (存在某些数据丢失风险); 要么
  • 获得更快的磁盘

有关更多信息,请参见如何加快PostgreSQL中的插入性能。

如果您不介意崩溃后丢失整个数据集,也可以使用未unlogged表。 但是,实际上,不正常关机后,您的数据将被删除。 走了 无法恢复。 因此,请确保您是认真的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM