在使用Go和MySQL时,为什么使用wrk进行基准测试会产生奇怪的结果?

时间:2015-09-05 03:28:37

标签: go

我开始试图看看准备好的陈述和非准备陈述之间有多大差异。我最终坐了5个小时试图找出发生了什么。我发现的东西毫无意义。

我正在使用CentOS 7和supervisord在后台运行Go 1.4.2作为守护程序。我使用MariaDB作为sql数据库。

我正在进行基准测试的程序非常简单。

我试图用3种不同的方式做到这一点。

1(由于某种原因最有效的最不正确的方式):

package main

import (
    "database/sql"
    "fmt"
    "log"
    "net/http"

    _ "github.com/go-sql-driver/mysql"
    "github.com/julienschmidt/httprouter"
)

type User struct {
    Id       int64
    Email    string
    Username string
}

var DB *sql.DB

func getUser(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    query := `SELECT id, email, username FROM user WHERE id=3 LIMIT 1;`

    rows, _ := DB.Query(query)

    var users []*User
    for rows.Next() {
        u := new(User)
        rows.Scan(&u.Id, &u.Email, &u.Username)
        users = append(users, u)
    }

    fmt.Fprint(w, users[0])
}

func main() {
    // runtime.GOMAXPROCS(4)

    var err error
    DB, err = sql.Open("mysql", "root:pass@unix(/var/lib/mysql/mysql.sock)/dbname?charset=utf8")
    if err != nil {
        log.Fatal(err)
    }
    if err = DB.Ping(); err != nil {
        log.Fatal(err)
    }

    router := httprouter.New()
    router.GET("/api/user", getUser)
    log.Fatal(http.ListenAndServe(":80", router))
}

我没有在这里检查是否有任何错误。我没有关闭任何行等等。

这个方法在wrk:

中给出了很好的结果
Running 5s test @ http://127.0.0.1:80/api/user
  1 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    18.85ms   17.73ms 238.81ms   91.57%
    Req/Sec     7.19k     1.58k    8.45k    96.00%
  35776 requests in 5.04s, 5.02MB read
Requests/sec:   7096.50
Transfer/sec:      0.99MB

我似乎持续获得超过7000的r / s。当我从MySQL数据库中获取内容时,效果很好。

在第二种方法中,我只需要替换getUser函数中的内容,如下所示:

func getUser(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    query := `SELECT id, email, username FROM user WHERE id=3 LIMIT 1;`

    rows, err := DB.Query(query)
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    var users []*User
    for rows.Next() {
        u := new(User)
        err := rows.Scan(&u.Id, &u.Email, &u.Username)
        if err != nil {
            log.Fatal(err)
        }
        users = append(users, u)
    }

    if err = rows.Err(); err != nil {
        log.Fatal(err)
    }

    fmt.Fprint(w, users[0])
}

这是我理解的推荐查询方式: http://go-database-sql.org/retrieving.html

这给出了非常奇怪和可怕的结果!

Running 5s test @ http://127.0.0.1:80/api/user
  1 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    11.80ms    3.68ms  14.40ms  100.00%
    Req/Sec     0.00      0.00     0.00    100.00%
  2 requests in 5.01s, 294.00B read
  Socket errors: connect 0, read 1490, write 159932, timeout 0
Requests/sec:      0.40
Transfer/sec:      58.64B

只有当我减少连接数量时,我似乎才能获得更好的结果,但不是始终如一,结果有时会一直下降到1500 r / s左右,这对我来说毫无意义。

我尝试的第三种方式是:(只做一个简单的1行查询)

func getUser(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    query := `SELECT id, email, username FROM user WHERE id=3 LIMIT 1;`

    user := new(User)
    err := DB.QueryRow(query).Scan(&user.Id, &user.Email, &user.Username)

    if err != nil {
        if err != sql.ErrNoRows {
            log.Fatal(err)
        }
        http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
        return
    }

    fmt.Fprint(w, user)
}

在这里,我得到了相同的糟糕结果,每秒少于1个请求。

发生了什么事?这已经困扰了我几个小时了。希望有人对此有解释和解决方法..

编辑:

现在我删除了log.Fatal(err)的所有行,并将其替换为log.Println(err)

并设置

runtime.GOMAXPROCS(4)

单一查询给出了这样的结果:

[root@centos7 main]# wrk -t1 -c1000 -d5s http://127.0.0.1:80/api/user
Running 5s test @ http://127.0.0.1:80/api/user
  1 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    22.24ms   12.11ms 176.58ms   79.83%
    Req/Sec    38.01k     4.62k   48.75k    66.67%
  188080 requests in 5.04s, 24.09MB read
  Non-2xx or 3xx responses: 183505
Requests/sec:  37350.28
Transfer/sec:      4.78MB

但这不是太好吗?这里肯定有问题吗?

另一件事,您是不是应该在生产服务器中使用log.Fatal(err),而只是在开发时?由于所有关于如何使用MySQL驱动程序的示例在获得结果后每个错误后显示log.Fatal(err)的示例。

0 个答案:

没有答案