为什么每笔交易都算作客户?

时间:2017-10-23 20:33:46

标签: postgresql go

我正在处理一堆文件,然后将结果转储到PostgreSQL中。我想同时处理许多工作人员,但不断收到错误" pq:抱歉,已经有太多客户"。这似乎发生在工人是> 100左右。 (为简单起见,下面的代码演示了该过程,但不是处理文件,而只是在每个表中插入1M行。)

由于我重复使用相同的* db,为什么我会收到此错误?每笔交易都算作客户还是我做错了什么?

package main

import (
    "database/sql"
    "flag"
    "fmt"
    "log"
    "sync"

    "github.com/lib/pq"
)

func process(db *sql.DB, table string) error {
    if _, err := db.Exec(fmt.Sprintf(`DROP TABLE IF EXISTS %v;`, table)); err != nil {
        return err
    }

    col := "age"
    s := fmt.Sprintf(`
        CREATE TABLE %v (
            pk serial PRIMARY KEY,
            %v int NOT NULL
    )`, table, col)

    _, err := db.Exec(s)
    if err != nil {
        return err
    }

    tx, err := db.Begin()
    if err != nil {
        return err
    }

    defer func() {
        if err != nil {
            tx.Rollback()
            return
        }
        err = tx.Commit()
    }()

    stmt, err := tx.Prepare(pq.CopyIn(table, col))
    if err != nil {
        return err
    }

    defer func() {
        err = stmt.Close()
    }()

    for i := 0; i < 1e6; i++ {
        if _, err = stmt.Exec(i); err != nil {
            return err
        }
    }

    return err

}

func main() {
    var u string
    flag.StringVar(&u, "user", "", "user")

    var pass string
    flag.StringVar(&pass, "pass", "", "pass")

    var host string
    flag.StringVar(&host, "host", "", "host")

    var database string
    flag.StringVar(&database, "database", "", "database")

    var workers int
    flag.IntVar(&workers, "workers", 10, "workers")

    flag.Parse()

    db, err := sql.Open("postgres",
        fmt.Sprintf(
            "user=%s password=%s host=%s database=%s sslmode=require",
            u, pass, host, database,
        ),
    )

    if err != nil {
        log.Fatalln(err)
    }

    defer db.Close()
    db.SetMaxIdleConns(0)

    var wg sync.WaitGroup
    ch := make(chan int)

    for i := 0; i < workers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for i := range ch {
                table := fmt.Sprintf("_table%d", i)
                log.Println(table)
                if err := process(db, table); err != nil {
                    log.Fatalln(err)
                }
            }
        }()
    }

    for i := 0; i < 300; i++ {
        ch <- i
    }

    close(ch)
    wg.Wait()
}

我意识到我可以简单地增加posgresql设置但想要理解这个问题:How to increase the max connections in postgres?

1 个答案:

答案 0 :(得分:4)

  

由于我重复使用相同的* db,为什么我会收到此错误?

我怀疑Postgress司机为每位员工使用单独的连接,这对大多数情况来说都是明智的决定。

  

每笔交易都算作客户还是我做错了什么?

在您的情况下,是的每个交易都被视为客户,因为您将process()称为goroutine。您正在创建与工作者一样多的并发事务。由于您的每个事务都很长,所以它们可能同时使用与数据库的单独连接,因此您达到了限制。

go func() {
        defer wg.Done()
        for i := range ch {
            table := fmt.Sprintf("_table%d", i)
            log.Println(table)
            if err := process(db, table); err != nil {
                log.Fatalln(err)
            }
        }
    }()