漫谈grpc 3:从实践到原理,带你参透 gRPC (8)

在 newClientStream 方法中,我们通过 getTransport 方法获取了 Transport 层中抽象出来的 ClientTransport 和 ServerTransport,实际上就是获取一个连接给后续 RPC 调用传输使用。

四、关闭连接 // conn.Close() func (cc *ClientConn) Close() error {  defer cc.cancel()     ...  cc.csMgr.updateState(connectivity.Shutdown)     ...  cc.blockingpicker.close()  if rWrapper != nil {   rWrapper.close()  }  if bWrapper != nil {   bWrapper.close()  }  for ac := range conns {   ac.tearDown(ErrClientConnClosing)  }  if channelz.IsOn() {   ...   channelz.AddTraceEvent(cc.channelzID, ted)   channelz.RemoveEntry(cc.channelzID)  }  return nil }

漫谈grpc 3:从实践到原理,带你参透 gRPC

该方法会取消 ClientConn 上下文,同时关闭所有底层传输。涉及如下:

Context Cancel

清空并关闭客户端连接

清空并关闭解析器连接

清空并关闭负载均衡连接

添加跟踪引用

移除当前通道信息

Q&A 1. gRPC Metadata 是通过什么传输?

图片

漫谈grpc 3:从实践到原理,带你参透 gRPC

2. 调用 grpc.Dial 会真正的去连接服务端吗?

会,但是是异步连接的,连接状态为正在连接。但如果你设置了 grpc.WithBlock 选项,就会阻塞等待(等待握手成功)。另外你需要注意,当未设置 grpc.WithBlock 时,ctx 超时控制对其无任何效果。

3. 调用 ClientConn 不 Close 会导致泄露吗?

会,除非你的客户端不是常驻进程,那么在应用结束时会被动地回收资源。但如果是常驻进程,你又真的忘记执行 Close 语句,会造成的泄露。如下图:

3.1. 客户端

图片

漫谈grpc 3:从实践到原理,带你参透 gRPC

3.2. 服务端

图片

漫谈grpc 3:从实践到原理,带你参透 gRPC

3.3. TCP

图片

漫谈grpc 3:从实践到原理,带你参透 gRPC

4. 不控制超时调用的话,会出现什么问题?

短时间内不会出现问题,但是会不断积蓄泄露,积蓄到最后当然就是服务无法提供响应了。如下图:

图片

漫谈grpc 3:从实践到原理,带你参透 gRPC

5. 为什么默认的拦截器不可以传多个? func chainUnaryClientInterceptors(cc *ClientConn) {  interceptors := cc.dopts.chainUnaryInts  if cc.dopts.unaryInt != nil {   interceptors = append([]UnaryClientInterceptor{cc.dopts.unaryInt}, interceptors...)  }  var chainedInt UnaryClientInterceptor  if len(interceptors) == 0 {   chainedInt = nil  } else if len(interceptors) == 1 {   chainedInt = interceptors[0]  } else {   chainedInt = func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error {    return interceptors[0](ctx, method, req, reply, cc, getChainUnaryInvoker(interceptors, 0, invoker), opts...)   }  }  cc.dopts.unaryInt = chainedInt }

漫谈grpc 3:从实践到原理,带你参透 gRPC

当存在多个拦截器时,取的就是第一个拦截器。因此结论是允许传多个,但并没有用。

6. 真的需要用到多个拦截器的话,怎么办?

可以使用 go-grpc-middleware 提供的 grpc.UnaryInterceptor 和 grpc.StreamInterceptor 链式方法,方便快捷省心。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgffdj.html