






















Why: 一个 Go 服务为什么可以同时处理几万甚至几十万连接?
答案并不复杂,Go net/http 的实现采用了每个 TCP 连接对应一个 Goroutine 的模型。
一个 HTTP 服务通常从下面这行代码开始:
http.ListenAndServe(":8080", nil)
它内部的调用流程如下:

核心代码:
for {
rw, err := l.Accept()
if err != nil {
if s.shuttingDown() {
return ErrServerClosed
}
if ne, ok := err.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
s.logf("http: Accept error: %v; retrying in %v", err, tempDelay)
time.Sleep(tempDelay)
continue
}
return err
}
connCtx := ctx
if cc := s.ConnContext; cc != nil {
connCtx = cc(connCtx, rw)
if connCtx == nil {
panic("ConnContext returned nil")
}
}
tempDelay = 0
c := s.newConn(rw)
c.setState(c.rwc, StateNew, runHooks) // before Serve can return
go c.serve(connCtx)
}
流程非常简单:
Accept() 接收新的 TCP 连接。conn.serve()。因此,一个 TCP 连接对应一个 conn.serve Goroutine。
假设:
那么服务端大约会维护:
10000 TCP Connection
≈
10000 conn.serve Goroutine
Go 的 Goroutine 初始栈只有几 KB,并由运行时负责调度,因此创建数万个 Goroutine 的成本远低于传统线程模型。
这也是 Go 非常适合编写网络服务器的重要原因之一。
在 http1.1 前提,开启 Keep-Alive 的情况下:
keep-alive 价值
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。