每个持久连接使用HTTP内存

时间:2016-01-14 08:45:34

标签: http memory go profile

我正在写一个Go网络服务器,它将Server-Sent Events发送给一大堆客户端。我希望它支持成千上万的同时连接。这是我的代码(它只是保持连接打开并发送keep-alive事件):

func handleTest(w http.ResponseWriter, r *http.Request) {
    h := w.Header()
    h.Set("Content-Type", "text/event-stream; charset=utf-8")
    h.Set("Cache-Control", "no-cache, no-store, must-revalidate")
    h.Set("Connection", "keep-alive")

    flusher := w.(http.Flusher)
    notifier := w.(http.CloseNotifier)

    flusher.Flush()

    // Just send keep-alives.
    keepAliveTime := 5 * time.Second
    keepAlive := time.NewTimer(keepAliveTime)
    defer keepAlive.Stop()

    for {
        select {
        case <-notifier.CloseNotify():
            // The connection has been closed.
            return

        case <-keepAlive.C:
            if _, err := io.WriteString(w, "event: keep-alive\ndata: null\n\n"); err != nil {
                log.Println(err)
                return
            }
            flusher.Flush()
            keepAlive.Reset(keepAliveTime)
        }
    }
}

通过1000个连接,Windows报告每个连接使用大约70 kB的RAM。如果我添加了我实际正在做的所有内容(还有另一个goroutine,以及一些次要的事件编码函数),它每个连接都会增加到300 kB。这看起来很多。这里有1000个连接是pprof heap所说的:

14683.25kB of 14683.25kB total (  100%)
Dropped 12 nodes (cum <= 73.42kB)
Showing top 10 nodes out of 23 (cum >= 512.19kB)
      flat  flat%   sum%        cum   cum%
11091.50kB 75.54% 75.54% 11091.50kB 75.54%  io.copyBuffer
    2053kB 13.98% 89.52%     2053kB 13.98%  net/http.newBufioWriterSize
     514kB  3.50% 93.02%      514kB  3.50%  net/http.newBufioReader
  512.56kB  3.49% 96.51%   512.56kB  3.49%  runtime.makeslice
  512.19kB  3.49%   100%   512.19kB  3.49%  net.newFD
         0     0%   100% 11091.50kB 75.54%  io.Copy
         0     0%   100%  1540.19kB 10.49%  main.main
         0     0%   100%   512.19kB  3.49%  net.(*TCPListener).AcceptTCP
         0     0%   100%   512.19kB  3.49%  net.(*netFD).accept
         0     0%   100%   512.19kB  3.49%  net.(*netFD).acceptOne

所以我有几个问题:

  1. 为什么记忆的使用看起来很高。我希望每个连接可以达到10 kB。
  2. 为什么pprof认为堆是14 MB,但Windows说内存使用是70 MB?其余的是堆栈吗?
  3. 有什么方法可以将HTTP响应的控制转移到中央goroutine,并在不关闭连接的情况下从handleTest()返回?这会节省我的记忆力还是http.ResponseWriter对象中的所有内存使用?
  4. 修改:对于3.看起来我可以使用Hijacker

    编辑2 :我尝试使用Hijacker重新实现它。它将每个连接的内存使用量减少到大约10 kB,这更合理!

1 个答案:

答案 0 :(得分:1)

  

为什么pprof认为堆是14 MB,但Windows说内存使用量是70 MB?其余的是堆栈吗?

除了堆之外,还有Go运行时,堆栈和代码段。操作系统也可能分配超过实际需要的数量。另外,Windows报告的驻留内存量或OS内存分配的总量是多少?