原文链接:https://mp.weixin.qq.com/s/ZqfN8UlWRpoGhznGH-L1mw
介绍
偶然间看到一篇写于15年的文章,说实话,标题确实吸引了我。
关于这篇文章,我就不直接翻译了,原文地址我放在文章最后了。
项目的需求就是很简单,客户端发送请求,服务端接收请求处理数据(原文是把资源上传至 Amazon S3 资源中)。本质上就是这样,
我稍微改动了原文的业务代码,但是并不影响核心模块。在第一版中,每收到一个 Request,开启一个 G 进行处理,很常规的操作。
初版
package main
import (
"fmt"
"log"
"net/http"
"time"
)
type Payload struct {
// 传啥不重要
}
func (p *Payload) UpdateToS3() error {
//存储逻辑,模拟操作耗时
time.Sleep(500 * time.Millisecond)
fmt.Println("上传成功")
return nil
}
func payloadHandler(w http.ResponseWriter, r *http.Request) {
// 业务过滤
// 请求body解析......
var p Payload
go p.UpdateToS3()
w.Write([]byte("操作成功"))
}
func main() {
http.HandleFunc("/payload", payloadHandler)
log.Fatal(http.ListenAndServe(":8099", nil))
}
这样操作存在什么问题呢?一般情况下,没什么问题。但是如果是高并发的场景下,不对 G 进行控制,你的 CPU 使用率暴涨,内存占用暴涨…,直至程序奔溃。
如果此操作落地至数据库,例如mysql。相应的,你数据库服务器的磁盘IO、网络带宽 、CPU负载、内存消耗都会达到非常高的情况,一并奔溃。所以,一旦程序中出现不可控的事物,往往是危险的信号。
中版
package main
import (
"fmt"
"log"
"net/http"
"time"
)
const MaxQueue = 400
var Queue chan Payload
func init() {
Queue = make(chan Payload, MaxQueue)
}
type Payload struct