Go语言 gRPC上下文取消传播

7xllpg7q  于 2023-02-27  发布在  Go
关注(0)|答案(2)|浏览(150)

我试图理解Go语言上下文取消在客户机服务通信(比如任何gRPC API调用)中的工作原理。
假设一个客户端取消了上下文。这是否会导致一个新的HTTP请求发送到服务器,通知服务器先前/正在进行的gRPC请求的上下文被取消?服务器如何知道客户端是否取消了上下文?

8i9zcol2

8i9zcol21#

默认情况下,HTTP2用作gPRC的底层协议。HTTP2连接上可能有多个流。下图说明了HTTP2web dev的连接和流

如果在响应返回之前取消一个gRPC调用中的上下文。客户端的错误代码可能是CANCELmapping to RST_STREAM,则此RST_STREAM将被发送到服务器。RST_STREAM帧允许立即终止流,即当前RPC调用流将被终止。但是,HTTP2连接仍然存在。当调用下一个RPC调用时,将使用另一个新流来进行RPC调用。
下面是一些测试代码片段。
客户端:100毫秒后强制取消上下文。

conn, err := grpc.Dial(serverAddr,
        grpc.WithTransportCredentials(insecure.NewCredentials()))

    defer conn.Close()

    c := pb.NewGreeterClient(conn)

    for i := 0; i < 10; i++ {
        ctx, cancel := context.WithCancel(context.TODO())
        go func() {
            // force call cancel after 100 milliseconds
            time.Sleep(100 * time.Millisecond)
            cancel()
        }()

        r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "name"})
     }

服务器端:在1秒内延迟sayHello响应。

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    // Delay ack on server by 1 seconds
    randMS := 1000

    select {
    case <-time.After(time.Duration(randMS) * time.Millisecond):

    case <-ctx.Done():
        if ctx.Err() == context.Canceled || ctx.Err() == context.DeadlineExceeded {
            log.Printf("SayHello: context err %+v \n", ctx.Err())
            return nil, ctx.Err()
            
        }
    }

使用GODEBUG=http2debug=2运行代码,更多gRPC的调试日志可以帮助我们了解客户端和服务器之间的消息。
客户端日志

2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote SETTINGS len=0
2022/10/21 20:40:38 http2: Framer 0xc0005be000: read SETTINGS len=6, settings: MAX_FRAME_SIZE=16384
2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote SETTINGS flags=ACK len=0
2022/10/21 20:40:38 http2: Framer 0xc0005be000: read SETTINGS flags=ACK len=0
2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote HEADERS flags=END_HEADERS stream=1 len=98
2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote DATA flags=END_STREAM stream=1 len=12 data="\x00\x00\x00\x00\a\n\x05world"
2022/10/21 20:40:38 http2: Framer 0xc0005be000: read WINDOW_UPDATE len=4 (conn) incr=12
2022/10/21 20:40:38 http2: Framer 0xc0005be000: read PING len=8 ping="\x02\x04\x10\x10\t\x0e\a\a"
2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote PING flags=ACK len=8 ping="\x02\x04\x10\x10\t\x0e\a\a"
force call cancel in client
2022/10/21 20:40:38 could not greet: rpc error: code = Canceled desc = context canceled
2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote RST_STREAM stream=1 len=4 ErrCode=CANCEL
2022/10/21 20:40:41 http2: Framer 0xc0005be000: wrote HEADERS flags=END_HEADERS stream=3 len=7
2022/10/21 20:40:41 http2: Framer 0xc0005be000: wrote DATA flags=END_STREAM stream=3 len=12 data="\x00\x00\x00\x00\a\n\x05world"
2022/10/21 20:40:41 http2: Framer 0xc0005be000: read WINDOW_UPDATE len=4 (conn) incr=12
2022/10/21 20:40:41 http2: Framer 0xc0005be000: read PING len=8 ping="\x02\x04\x10\x10\t\x0e\a\a"
2022/10/21 20:40:41 http2: Framer 0xc0005be000: wrote PING flags=ACK len=8 ping="\x02\x04\x10\x10\t\x0e\a\a"
force call cancel in client
2022/10/21 20:40:41 could not greet: rpc error: code = Canceled desc = context canceled
2022/10/21 20:40:41 http2: Framer 0xc0005be000: wrote RST_STREAM stream=3 len=4 ErrCode=CANCEL
2022/10/21 20:40:44 http2: Framer 0xc0005be000: wrote HEADERS flags=END_HEADERS stream=5 len=7
2022/10/21 20:40:44 http2: Framer 0xc0005be000: wrote DATA flags=END_STREAM stream=5 len=12 data="\x00\x00\x00\x00\a\n\x05world"
2022/10/21 20:40:44 http2: Framer 0xc0005be000: read WINDOW_UPDATE len=4 (conn) incr=12
inb24sb2

inb24sb22#

假设一个客户端取消了它的上下文,这是否会导致一个新的HTTP请求发送到服务器,通知服务器先前/正在进行的GRPC请求的上下文被取消了?
否。它会关闭网络连接。
服务器如何知道客户端是否取消了上下文?
由于网络连接被关闭的事实。

相关问题