【发布时间】:2015-11-24 07:17:06
【问题描述】:
因此,经过 3 个月的努力开发和将公司 API 从 PHP 切换到 Go,我发现我们的 Go 服务器不能处理超过 20 个请求/秒。
我们的 API 基本上是如何工作的:
- 接受请求
- 验证请求
- 使用 MYSQL 从数据库中获取数据
- 将数据放入地图中
- 以 JSON 格式发送回客户端
因此,在编写了大约 30 个 API 之后,我决定试一试,看看它在负载测试下的性能如何。
测试 1: ab -n 1 -c 1 http://localhost:8000/sales/report 结果是 "Time per request: 72.623 [ms] (mean)" 。
测试 2: ab -n 100 -c 100 http://localhost:8000/sales/report 结果是“每次请求的时间:4548.155 [ms](平均值)”(没有 MYSQL 错误)。
在第二次测试中,这个数字是如何突然从 72.623 飙升到 4548 毫秒的?我们预计每天会有数千个请求,所以我需要在最终发布之前解决这个问题。当我看到这些数字时,我很惊讶;我简直不敢相信。我知道 GO 可以做得更好。
关于服务器和设置的基本信息:
- 使用 GO 1.5
- 16GB 内存
- GOMAXPROCS 正在使用所有 8 个内核
- db.SetMaxIdleConns(1000)
- db.SetMaxOpenConns(1000)(还确保我们使用的是 连接)
- 通过 unix socket 连接到 MYSQL
- 系统在 Ubuntu 下运行
我们正在使用的外部库:
github.com/go-sql-driver/mysql
github.com/gorilla/mux
github.com/elgs/gosqljson
任何想法可能导致这种情况? .我看了一下这个post,但没有像我上面提到的那样工作,我从来没有遇到任何 MYSQL 错误。提前感谢您提供的任何帮助。
【问题讨论】:
-
我相信您明白,如果不进一步了解正在做的事情,我们可以说的很少。你描述它的方式听起来太简单了,不会那么慢。
-
database/sql 已经有连接池,所以如果你在上面写了某种池,那会伤害你。你真的应该只需要在你的进程的生命周期内调用一次 sql.Open 。如果您的 sql 不重要,您可能无法从 MySQL 中获得更多吞吐量。 MySQL 在并发复杂查询时并不总是具有良好的性能。
-
当您说将其放入地图时,这可能意味着任何事情。你为什么不分析子组件并更好地解决它
-
查询本身并不复杂。只是从结构良好的数据库表中选择查询。运行时间为 0.06(未缓存)。当然,当它被数据库缓存时,这个数字会下降。
-
发布端点/处理程序的代码。常见问题包括 a) 为每个请求创建新的数据库池,而不是重用池成员; b) 将数千行复制到新的地图/切片中; c) 反映太多。话虽如此,4548ms 很多,可能是由网络级别的某些原因引起的(MySQL 是否配置为允许超过 100 个 conns?)