美文网首页
简析gRPC client 连接管理

简析gRPC client 连接管理

作者: 邵红晓 | 来源:发表于2019-07-22 14:24 被阅读0次
    • 客户端skd 使用gRPC作为通信协议,定时(大概是120s)向服务器发送pingServer 请求。服务端是80端口,如xxx:80.

    问题:

    发现客户端不断的端口重连服务器的。

    使用netstat -antp

    image.png

    如图, 如标红的服务器地址连接是TIME_WAIT,后面有和服务器建立连接 ESTABLISHED。TIME_WAIT 状态表明是client 端主动断开了连接。这和我之前的认知有点冲突,gRPC 应该是长连接,为什么这里每次都断开呢,这样不就长了短连接了吗?而且客户端主动断开的,会不会是client端哪里有问题?带着疑问,在client 抓了一包,发现client 总是受到一个length为17的包,然后就开始FIN 包,走TCP 挥手的流程。使用WireShark 对tcpdump的结果查看,发现这个length17的包,是一个GOAWAY 包。


    image.png
    • 这个是HTTP2定义的一个“优雅”退出的机制。

    • 这里有HTTP2 GOAWAY stream 包的说明。

    HTTP2 GOAWAY 说明

    根据之前的对gRPC的了解,gRPC client 会解析域名,然后会维护一个lb 负载均衡,这个应该是gRPC对idle 连接的管理。pingServer 的时间间隔是120s, 但是gRPC 认为中间是idle连接,所以通知client 关闭空闲连接?为了验证这个想法,修改了一下gRPC 的demo, 因为我们client 端使用是cpp 的gRPC 异步调用方式,所以更加gRPC 的异步demo, 写了一个简单访问服务器的async_client

    server

    # <-! coding=UTF-8 ->
    import sys
    import grpc
    from concurrent import futures
    import grpc_service_pb2
    import grpc_service_pb2_grpc
    import time
    import commands
    from concurrent.futures import ThreadPoolExecutor
    import logging
    
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    _HOST = 'localhost'
    _PORT = '50051'
    
    logging.basicConfig()
    
    
    def write_hive_file(dir, str):
        open(dir, 'a').write(str)
    
    
    def handler(cmdstr):
        cmd_arr = cmdstr.split(" ")
        if len(cmd_arr) <= 2:
            print "param error"
            sys.exit(1)
        cmd = ""
        for i in range(0, len(cmd_arr)):
            cmd = "%s %s" % (cmd, cmd_arr[i])
            log = "[%s] %s" % (time.strftime('%Y-%m-%d %H:%M:%S'), cmd)
        print log
        time.sleep(5)
    
    
    thread_pool = ThreadPoolExecutor(16)
    
    
    class ServiceMain(grpc_service_pb2_grpc.RemoteCallServiceServicer):
        def call(self, request, context):
            cmdstr = str(object=request.cmdReqStr)
            # 处理业务
            print cmdstr
            thread_pool.submit(handler, cmdstr)
            return grpc_service_pb2.RemoteResponse(cmdRespStr="service handler you cmd:\"%s\"" % cmdstr)
    
    
    def server():
        grpcserver = grpc.server(futures.ThreadPoolExecutor(max_workers=4))
        grpc_service_pb2_grpc.add_RemoteCallServiceServicer_to_server(ServiceMain(), grpcserver)
        grpcserver.add_insecure_port(_HOST+":"+_PORT)
        grpcserver.start()
        print "start success"
        #write_hive_file(_LOG_PATH, "server start success")
        try:
            while True:
                time.sleep(5)
                print "循环一次"
        except KeyboardInterrupt:
            grpcserver.stop(0)
    
    
    if __name__ == '__main__':
        server()
    

    client

    # <-! coding=UTF-8 ->
    import grpc
    import grpc_service_pb2
    import grpc_service_pb2_grpc
    
    _HOST = 'localhost'
    _PORT = '50051'
    
    
    def run():
        conn = grpc.insecure_channel(_HOST + ':' + _PORT)
        client = grpc_service_pb2_grpc.RemoteCallServiceStub(channel=conn)
        response = client.call(grpc_service_pb2.RemoteRequest(cmdReqStr='hello,world!'))
        print("received: " + response.cmdRespStr)
    
    
    if __name__ == '__main__':
        run()
    
    

    接下来的时间很简单,运行一下。
    使用netstat -natp 观察,可以重新。 async_client 也是断开,重连。
    进一步调试发现,把发包的时间修改为10s 的时候,可以保持连接,大于10s基本上连接就会断开。

    小结:

    gRPC 管理连接的方式,默认情况下,大于10s没有数据发送,gRPC 就会认为是个idle 连接。server 端会给client 端发送一个GOAWAY 的包。client 收到这个包之后就会主动关闭连接。下次需要发包的时候,就会重新建立连接。

    相关文章

      网友评论

          本文标题:简析gRPC client 连接管理

          本文链接:https://www.haomeiwen.com/subject/pdaoqqtx.html