2017-02-28 15 views
-7

私はGo(Golang)で新しいです。 MySQLとの同時処理をテストするための簡単なベンチマークプログラムを作成しました。並行チャネルの数を増やすと "dial tcp 52.55.254.165:3306:getsockopt:connection refused"、 "unexpected EOF"というエラーが発生することがあります。golang MySQL "接続が拒否されました"

各goルーチンは、単純な顧客テーブルに1〜n行のバッチインサートを実行しています。このプログラムでは、変数の挿入サイズ(1つのステートメント内の行数)と並列実行ルーチンの数を設定できます(各ルーチンは上記の挿入を1回実行します)。プログラムは小さな数字の行< 100と数字のルーチンは<となります。しかし、数字が増えると予期しないEOFエラーが発生し始めます。特に並行して行くルーチンの数が増えます。

手がかりを検索しませんでした。それらに基づいて、私はデータベースの最大接続と 'max_allowed_pa​​cket'と 'max_connections'を設定しました。私もgoプログラムを設定しましたdb.db.SetMaxOpenConns(200)db.SetConnMaxLifetime(200)db.SetMaxIdleConns(10)。私は大きな数字と小さな数字で実験しました(10から2000まで)。プログラムを解決するものはありません。

私は1つのグローバルDB接続を開いています。以下のコードスニペット:

// main package 

func main() { 

    var err error 
    db, err = sql.Open("mysql","usr:[email protected](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 
} 
+2

表示する必要があります。 – Volker

+0

下記のコードを追加しました。ありがとうございます... – Gary

答えて

0

各ルーチンでsql.Openを呼び出すとしますか?

Open関数は一度呼び出す必要があります。開いているDB接続をルーチン間で共有する必要があります。 Open関数によって返されたDBは、同時に使用することができ、独自のプールを持ちます

関連する問題