Go语言 连接池相关总结:HTTP、RPC、Redis 和数据库等( 四 )

acquireConn

Go语言 连接池相关总结:HTTP、RPC、Redis 和数据库等

文章插图
 
6
流程比较简单,如果当前 client.conns 数组 > 0,说明有空闲连接,直接取最后一个元素就好,这个元素一般是最近放进去的连接 。
releaseConnfunc (c *HostClient) releaseConn(cc *clientConn) { cc.lastUseTime = time.Now() if c.MaxConnWaitTimeout <= 0 {  c.connsLock.Lock()  c.conns = append(c.conns, cc)  c.connsLock.Unlock()  return } // try to deliver an idle connection to a *wantConn c.connsLock.Lock() defer c.connsLock.Unlock() delivered := false if q := c.connsWait; q != nil && q.len() > 0 {  for q.len() > 0 {   w := q.popFront()   if w.waiting() {    delivered = w.tryDeliver(cc, nil)    break   }  } } if !delivered {  c.conns = append(c.conns, cc) }releaseConn 会先尽量尝试把当前的连接给正在等待连接的请求(wantConn),弹出等待队列(connsWait)的第一个元素 。并把连接转交给该请求 。如果该请求的状态已经不是 waiting 了,则继续弹出,直到找到了合适的来接盘,或者等待队列弹空 。
如果没有顺利地把连接交出去,把当前连接入空闲连接数组(c.conns) 。
需要注意 fasthttp 里的 conns 是连接池,clientConnPool 是 clientConn 对象的对象池 。
与标准库中的 client 不同的是,fasthttp 中没有 read write loop,所以每个请求是在当前协程中完成的:
  1. 把 request 的 header 和 body 写入到 conn
  2. 从 conn 中读取 response
  3. 释放连接、缓存各种过程中生成的 struct 对象
gRPC服务端gRPC 底层基于 http2,所以交互基于 http2 stream,服务端整体流程与 http2 没什么区别 。
客户端在 gRPC 中,客户端没有使用连接池,直接使用了 http2 连接:
Invoke-> invoke -> newClientStream -> newAttemptLocked -> getTransport -> blockingpiker.pick ->  getReadyTransport ->  addrConn.connect -> go ac.resetTransport()然后一路走到创建 http2Client 。
(dlv) bt0  0x00000000013e2539 in google.golang.org/grpc/internal/transport.newHTTP2Client   at /Users/xargin/go/src/google.golang.org/grpc/internal/transport/http2_client.go:1671  0x000000000145a5ca in google.golang.org/grpc/internal/transport.NewClientTransport   at /Users/xargin/go/src/google.golang.org/grpc/internal/transport/transport.go:5752  0x000000000145a5ca in google.golang.org/grpc.(*addrConn).createTransport   at /Users/xargin/go/src/google.golang.org/grpc/clientconn.go:12753  0x0000000001459e25 in google.golang.org/grpc.(*addrConn).tryAllAddrs   at /Users/xargin/go/src/google.golang.org/grpc/clientconn.go:12054  0x00000000014593b7 in google.golang.org/grpc.(*addrConn).resetTransport   at /Users/xargin/go/src/google.golang.org/grpc/clientconn.go:11205  0x000000000105b811 in runtime.goexit   at /usr/local/go/src/runtime/asm_amd64.s:1357thriftthrift 官方没有连接池,client 中生成的 seqid 只是用来和服务端返回的 rseqid 进行匹配 。
func (p *TStandardClient) Recv(iprot TProtocol, seqId int32, method string, result TStruct) error { rMethod, rTypeId, rSeqId, err := iprot.ReadMessageBegin() if err != nil {  return err } if method != rMethod {  return NewTApplicationException(WRONG_METHOD_NAME, fmt.Sprintf("%s: wrong method name", method)) } else if seqId != rSeqId {  return NewTApplicationException(BAD_SEQUENCE_ID, fmt.Sprintf("%s: out of order sequence response", method)) } else if rTypeId == EXCEPTION {  var exception tApplicationException  if err := exception.Read(iprot); err != nil {   return err  }  if err := iprot.ReadMessageEnd(); err != nil {   return err  }  return &exception } else if rTypeId != REPLY {  return NewTApplicationException(INVALID_MESSAGE_TYPE_EXCEPTION, fmt.Sprintf("%s: invalid message type", method)) } if err := result.Read(iprot); err != nil {  return err } return iprot.ReadMessageEnd()}


推荐阅读