留意这里有reader和writer连个goroutines。 每个goroutine都须要本身的内存栈, 根据操作体系和Go版本可能具有2到8 KB的初始大年夜小。
在300万个在线连接的时刻,我们将须要24 GB的内存 (客栈为4 KB)用于保持所有连接。 这还没有计算为Channel构造分派的内存,传出的数据包ch.send和其他内部字段消费的内存。
- I/O goroutines
- func (c *Channel) reader() {
- // We make a buffered read to reduce read syscalls.
- buf := bufio.NewReader(c.conn)
- for {
- pkt, _ := readPacket(buf)
- c.handle(pkt)
- }
- }
这里我们应用bufio.Reader来削减read() syscalls的数量,并攫取与buf缓冲区大年夜小一样的数量。 在无穷轮回中,我们等待新数据的到来。 请记住: 估计新数据将会光降。 我们稍后会回来。
我们将分开传入数据包的解析和处理,因为对我们将要评论辩论的优化不重要。 然则, buf如今值得我们留意:默认情况下,它是4 KB,这意味着我们须要别的12 GB内存。 “writer”有类似的情况:
我们遍历c.send ,并将它蒙烫蛛缓冲区。细心读者已经猜到的,我们的300万个连接还将消费12 GB的内存。
HTTP
- GET /ws HTTP/1.1
- Host: mail.ru
- Connection: Upgrade
- Sec-Websocket-Key: A3xNe7sEB9HixkmBhVrYaA==
- Sec-Websocket-Version: 13
- Upgrade: websocket
- HTTP/1.1 101 Switching Protocols
- Connection: Upgrade
- Sec-Websocket-Accept: ksu0wXWG+YmkVx+KQR2agP0cQn4=
- Upgrade: websocket
我们已经有一个简单的Channel实现,如今我们须要一个WebSocket连接才能应用。
留意:如不雅您不知道WebSocket若何工作。客户端经由过程称为进级的特别HTTP机制切换到WebSocket协定。 在成功处理进级请求后,办事器和客户端应用TCP连接来交换二进制WebSocket帧。 这是连接中的框架构造的描述。
- import (
- "net/http"
- "some/websocket"
- )
- http.HandleFunc("/v1/ws", func(w http.ResponseWriter, r *http.Request) {
- conn, _ := websocket.Upgrade(r, w)
- ch := NewChannel(conn)
- //...
- })
请留意, http.ResponseWriter为bufio.Reader和bufio.Writer (应用4 KB缓冲区)进行内存分派,用于*http.Request初始化和进一步的响应写入。
无论应用什么WebSocket库,在成功响应进级请求后, 办事器在responseWriter.Hijack()调用之后,连同TCP连接一路接收 I/O缓冲区。
提示:在某些情况下, go:linkname 可用于 经由过程调用 net/http.putBufio{Reader,Writer} 精华冲区返回到 net/http 内 的 sync.Pool 。