Голанг MySQL "отказано в соединении"

Я новичок в Го (Голанг). Я написал простую тестовую программу для тестирования параллельной обработки с MySQL. При увеличении количества одновременных каналов продолжают появляться сообщения об ошибках "dial tcp 52.55.254.165:3306: getsockopt: соединение отказано", "неожиданный EOF".

Каждая подпрограмма go выполняет пакетную вставку от 1 до n строк в простую таблицу клиентов. Программа позволяет установить переменный размер вставки (количество строк в одной инструкции) и количество подпрограмм параллельного запуска (каждая подпрограмма выполнения выполняет одну вставку выше). Программа отлично работает с небольшими числами строк<100 и число идти процедур <100. Но начните получать неожиданные ошибки EOF, когда число увеличивается, особенно количество процедур параллельного запуска.

Делал поиск улик. Основываясь на них, я установил максимальное соединение с базой данных и max_allowed_packet и max_connections. Я также установил программу го db.db.SetMaxOpenConns(200), db.SetConnMaxLifetime(200), db.SetMaxIdleConns(10), Я экспериментировал с большими числами и маленькими (с 10 до 2000). Ничто, кажется, не решает программу.

У меня открыто одно глобальное соединение с БД. Фрагмент кода ниже:

// main package

func main() {

    var err error
    db, err = sql.Open("mysql","usr:pwd@tcp(ip:3306)/gopoc")
    if err != nil {
        log.Panic(err)
    }
    db.SetMaxOpenConns(1000)
    db.SetConnMaxLifetime(1000)
    db.SetMaxIdleConns(10)

    // sql.DB should be long lived "defer" closes it once this function ends
    defer db.Close()

    if err = db.Ping(); err != nil {
        log.Panic(err)
    }

    http.HandleFunc("/addCust/", HFHandleFunc(addCustHandler))

    http.ListenAndServe(":8080", nil)
}

// add customer handler
func addCustHandler(w http.ResponseWriter, r *http.Request) {

    // experected url: /addCust/?num=3$pcnt=1
    num, _ := strconv.Atoi(r.URL.Query().Get("num"))
    pcnt, _ := strconv.Atoi(r.URL.Query().Get("pcnt"))

    ch := make([]chan string, pcnt) // initialize channel slice
    for i := range ch {
        ch[i] = make(chan string, 1)
    }

    var wg sync.WaitGroup

    for i, chans := range ch {
        wg.Add(1)
        go func(cha chan string, ii int) {
            defer wg.Done()
            addCust(num)
            cha <- "Channel[" + strconv.Itoa(ii) + "]\n"
        }(chans, i)
    }

    wg.Wait()

    var outputstring string

    for i := 0; i < pcnt; i++ {
        outputstring = outputstring + <-ch[i]
    }

    fmt.Fprintf(w, "Output:\n%s", outputstring)
}

func addCust(cnt int) sql.Result {
...
    sqlStr := "INSERT INTO CUST (idCUST, idFI, fName, state, country) VALUES "

    for i := 0; i < cnt; i++ {

        sqlStr += "(" + strconv.Itoa(FiIDpadding+r.Intn(CidMax)+1) + ", " + strconv.Itoa(FiID) +", 'fname', 'PA', 'USA), " 

    }

    //trim the last ,
    sqlStr = sqlStr[0:len(sqlStr)-2] + " on duplicate key update lname='dup';"

    res, err := db.Exec(sqlStr)
    if err != nil {
        panic("\nInsert Statement error\n" + err.Error()) 
    }

    return res
}

1 ответ

Я полагаю, вы звоните sql.Open в каждом из ваших рутины?

Функция Open должна вызываться только один раз. Вы должны разделить ваше открытое соединение с БД между вашими подпрограммами. БД, возвращаемая функцией Open, может использоваться одновременно и имеет свой собственный пул

Другие вопросы по тегам