Open wangming1993 opened 7 years ago
升级 grpc 到 1.6.0 过程中 context 问题
https://github.com/grpc/grpc-go/blob/v1.6.0/Documentation/grpc-metadata.md#retrieving-metadata-from-context
最近在将 grpc 由 1.0.5 升级到 1.6.0 , 发现 metadata 包下面的接口发生了改变:
其中发送 grpc 调用时,需要使用 NewOutgoingContext 去创建 context, 在 grpc 的 service 里面调用
FromIncomingContext 去获取。
吐槽:真心感觉这样很是麻烦,原来的方式就很好啊, 可是人家觉得这样能分清楚
于是看了一下这其中的转化过程,为什么发送的是 NewOutgoingContext, 但是接收需要使用: NewIncomingContext:
client 发送数据
service: MemberService
method: GetMember
下面给出执行流程,但是只会涉及关键代码,部分代码会被省略:
grpc.Invoke(ctx, "/rpc.member.MemberService/GetMember", in, out, c.cc, opts...) // google.golang.org/grpc/call.go func Invoke(ctx context.Context, method string, args, reply interface{}, cc *ClientConn, opts ...CallOption) error { return invoke(ctx, method, args, reply, cc, opts...) } func invoke(ctx context.Context, method string, args, reply interface{}, cc *ClientConn, opts ...CallOption) (e error) { for { t, put, err = cc.getTransport(ctx, gopts) stream, err = t.NewStream(ctx, callHdr) if peer, ok := peer.FromContext(stream.Context()); ok { c.peer = peer } err = sendRequest(ctx, cc.dopts, cc.dopts.cp, &c, callHdr, stream, t, args, topts) err = recvResponse(ctx, cc.dopts, t, &c, stream, reply) t.CloseStream(stream, nil) return stream.Status().Err() } } // google.golang.org/grpc/transport/http2_client.go func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Stream, err error) { if md, ok := metadata.FromOutgoingContext(ctx); ok { for k, vv := range md { for _, v := range vv { t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) } } } }
server 处理数据
// google.golang.org/grpc/server.go func (s *Server) Serve(lis net.Listener) error { for { rawConn, err := lis.Accept() // Start a new goroutine to deal with rawConn // so we don't stall this Accept loop goroutine. go s.handleRawConn(rawConn) } } func (s *Server) handleRawConn(rawConn net.Conn) { s.serveHTTP2Transport(conn, authInfo) } func (s *Server) serveHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) { st, err := transport.NewServerTransport("http2", c, config) s.serveStreams(st) } // google.golang.org/grpc/transport/transport.go func NewServerTransport(protocol string, conn net.Conn, config *ServerConfig) (ServerTransport, error) { return newHTTP2Server(conn, config) } // google.golang.org/grpc/transport/http2_server.go func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err error) { return &http2Server{}, nil } func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context.Context, string) context.Context) { for { frame, err := t.framer.readFrame() switch frame := frame.(type) { case *http2.MetaHeadersFrame: if t.operateHeaders(frame, handle, traceCtx) { t.Close() break } case *http2.DataFrame: t.handleData(frame) } } func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) (close bool) { var state decodeState for _, hf := range frame.Fields { if err := state.processHeaderField(hf); err != nil { } } s := &Stream{} if len(state.mdata) > 0 { s.ctx = metadata.NewIncomingContext(s.ctx, state.mdata) } }
总结起来就是发送数据时,会根据 metadata.FromOutgoingContext(ctx) 来将数据写入 Header 帧,
server 在接收到客户端请求时,从 Header 帧获取,并写入 metadata.NewIncomingContext(s.ctx, state.mdata)
视使用的库不同, 有一部分有用的数据会直接存在ctx里而不是ctx的metadata里. 需要当心这个坑.
升级 grpc 到 1.6.0 过程中 context 问题
https://github.com/grpc/grpc-go/blob/v1.6.0/Documentation/grpc-metadata.md#retrieving-metadata-from-context
最近在将 grpc 由 1.0.5 升级到 1.6.0 , 发现 metadata 包下面的接口发生了改变:
其中发送 grpc 调用时,需要使用 NewOutgoingContext 去创建 context, 在 grpc 的 service 里面调用
FromIncomingContext 去获取。
吐槽:真心感觉这样很是麻烦,原来的方式就很好啊, 可是人家觉得这样能分清楚
于是看了一下这其中的转化过程,为什么发送的是 NewOutgoingContext, 但是接收需要使用: NewIncomingContext:
client 发送数据
service: MemberService
method: GetMember
下面给出执行流程,但是只会涉及关键代码,部分代码会被省略:
server 处理数据
总结起来就是发送数据时,会根据 metadata.FromOutgoingContext(ctx) 来将数据写入 Header 帧,
server 在接收到客户端请求时,从 Header 帧获取,并写入 metadata.NewIncomingContext(s.ctx, state.mdata)