grpc python 源码分析(2):server 处理请求

 

版本:1.24.3

  • 接受请求
    首先来看 上期文章 中提到的接受请求线程
  • def _serve(state):
        while True:
            timeout = time.time() + _DEALLOCATED_SERVER_CHECK_PERIOD_S
            event = state.completion_queue.poll(timeout)
            if state.server_deallocated:
                _begin_shutdown_once(state)
            if event.completion_type != cygrpc.CompletionType.queue_timeout:
                if not _process_event_and_continue(state, event):
                    return
            # We want to force the deletion of the previous event
            # ~before~ we poll again; if the event has a reference
            # to a shutdown Call object, this can induce spinlock.
            event = None
    

      

    #我们要强制删除上一个事件
    #〜之前〜我们再次投票; 如果事件有参考
    #到关闭的Call对象,这可能导致自旋锁。
    

      

负责处理请求的是 _process_event_and_continue 函数,在之前做了一些超时的判断,决定是否处理这个请求。
下面是 _process_event_and_continue 函数的代码

def _process_event_and_continue(state, event):
    should_continue = True
    if event.tag is _SHUTDOWN_TAG:
        with state.lock:
            state.due.remove(_SHUTDOWN_TAG)
            if _stop_serving(state):
                should_continue = False
    elif event.tag is _REQUEST_CALL_TAG:
        with state.lock:
            state.due.remove(_REQUEST_CALL_TAG)
            concurrency_exceeded = (
                state.maximum_concurrent_rpcs is not None and
                state.active_rpc_count >= state.maximum_concurrent_rpcs)
            rpc_state, rpc_future = _handle_call(event, state.generic_handlers,
                                                 state.interceptor_pipeline,
                                                 state.thread_pool,
                                                 concurrency_exceeded)
            if rpc_state is not None:
                state.rpc_states.add(rpc_state)
            if rpc_future is not None:
                state.active_rpc_count += 1
                rpc_future.add_done_callback(
                    lambda unused_future: _on_call_completed(state))
            if state.stage is _ServerStage.STARTED:
                _request_call(state)
            elif _stop_serving(state):
                should_continue = False
    else:
        rpc_state, callbacks = event.tag(event)
        for callback in callbacks:
            try:
                callback()
            except Exception:  # pylint: disable=broad-except
                _LOGGER.exception('Exception calling callback!')
        if rpc_state is not None:
            with state.lock:
                state.rpc_states.remove(rpc_state)
                if _stop_serving(state):
                    should_continue = False
    return should_continue

  

继续往下走

def _handle_call(rpc_event, generic_handlers, interceptor_pipeline, thread_pool,
                 concurrency_exceeded):
    if not rpc_event.success:
        return None, None
    if rpc_event.call_details.method is not None:
        try:
            method_handler = _find_method_handler(rpc_event, generic_handlers,
                                                  interceptor_pipeline)
        except Exception as exception:  # pylint: disable=broad-except
            details = 'Exception servicing handler: {}'.format(exception)
            _LOGGER.exception(details)
            return _reject_rpc(rpc_event, cygrpc.StatusCode.unknown,
                               b'Error in service handler!'), None
        if method_handler is None:
            return _reject_rpc(rpc_event, cygrpc.StatusCode.unimplemented,
                               b'Method not found!'), None
        elif concurrency_exceeded:
            return _reject_rpc(rpc_event, cygrpc.StatusCode.resource_exhausted,
                               b'Concurrent RPC limit exceeded!'), None
        else:
            return _handle_with_method_handler(rpc_event, method_handler,
                                               thread_pool)
    else:
        return None, None

  

这里我们主要关注 _find_method_handler_handle_with_method_handler

_find_method_handler 负责获取请求对应的接口方法,例如下面这个 SayHello 方法

class Greeter(helloworld_pb2_grpc.GreeterServicer):

    def SayHello(self, request, context):
        return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)

 

其实,这就是一个字典映射,键为 接口名,值为 接口方法

def _find_method_handler(rpc_event, generic_handlers, interceptor_pipeline):

    def query_handlers(handler_call_details):
        for generic_handler in generic_handlers:
            method_handler = generic_handler.service(handler_call_details)
            if method_handler is not None:
                return method_handler
        return None

    handler_call_details = _HandlerCallDetails(
        _common.decode(rpc_event.call_details.method),
        rpc_event.invocation_metadata)

    if interceptor_pipeline is not None:
        return interceptor_pipeline.execute(query_handlers,
                                            handler_call_details)
    else:
        return query_handlers(handler_call_details)

 

# 上面代码中的 generic_handler 类型
class DictionaryGenericHandler(grpc.ServiceRpcHandler):

    def __init__(self, service, method_handlers):
        self._name = service
        self._method_handlers = {
            _common.fully_qualified_method(service, method): method_handler
            for method, method_handler in six.iteritems(method_handlers)
        }  # 这是个字典推导

    def service(self, handler_call_details):
        return self._method_handlers.get(handler_call_details.method)

  

继续另一个函数 _handle_with_method_handler

def _handle_with_method_handler(rpc_event, method_handler, thread_pool):
    state = _RPCState()
    with state.condition:
        rpc_event.call.start_server_batch(
            (cygrpc.ReceiveCloseOnServerOperation(_EMPTY_FLAGS),),
            _receive_close_on_server(state))
        state.due.add(_RECEIVE_CLOSE_ON_SERVER_TOKEN)
        if method_handler.request_streaming:
            if method_handler.response_streaming:
                return state, _handle_stream_stream(rpc_event, state,
                                                    method_handler, thread_pool)
            else:
                return state, _handle_stream_unary(rpc_event, state,
                                                   method_handler, thread_pool)
        else:
            if method_handler.response_streaming:
                return state, _handle_unary_stream(rpc_event, state,
                                                   method_handler, thread_pool)
            else:
                return state, _handle_unary_unary(rpc_event, state,
                                                  method_handler, thread_pool)

 

这里的四个分支对应了四种rpc调用 ,详情可以看 gRPC 官方文档
我们看最简单的——请求和响应都一次性发送的 _handle_unary_unary

#请求反序列化,得到我们定义的请求对象

 
def _handle_unary_unary(rpc_event, state, method_handler, default_thread_pool):
    unary_request = _unary_request(rpc_event, state,
                                   method_handler.request_deserializer)
    thread_pool = _select_thread_pool_for_behavior(method_handler.unary_unary,
                                                   default_thread_pool)
    return thread_pool.submit(_unary_response_in_pool, rpc_event, state,
                              method_handler.unary_unary, unary_request,
                              method_handler.request_deserializer,
                              method_handler.response_serializer)

  

嗯,把任务提交给了线程池处理
继续向下挖

def _unary_response_in_pool(rpc_event, state, behavior, argument_thunk,
                            request_deserializer, response_serializer):
    cygrpc.install_context_from_request_call_event(rpc_event)
    try:
        argument = argument_thunk()
        if argument is not None:
            response, proceed = _call_behavior(rpc_event, state, behavior,
                                               argument, request_deserializer)
            if proceed:
                serialized_response = _serialize_response(
                    rpc_event, state, response, response_serializer)
                if serialized_response is not None:
                    _status(rpc_event, state, serialized_response)
    finally:
        cygrpc.uninstall_context()

  

我们看到了 _call_behavior 函数,就是这个函数调用了我们写得接口方法 ;-)

 
def _call_behavior(rpc_event,
                   state,
                   behavior,
                   argument,
                   request_deserializer,
                   send_response_callback=None):
    from grpc import _create_servicer_context
    with _create_servicer_context(rpc_event, state,
                                  request_deserializer) as context:
        try:
            response_or_iterator = None
            if send_response_callback is not None:
                response_or_iterator = behavior(argument, context,
                                                send_response_callback)
            else:
                response_or_iterator = behavior(argument, context)
            return response_or_iterator, True
        except Exception as exception:  # pylint: disable=broad-except
            with state.condition:
                if state.aborted:
                    _abort(state, rpc_event.call, cygrpc.StatusCode.unknown,
                           b'RPC Aborted')
                elif exception not in state.rpc_errors:
                    details = 'Exception calling application: {}'.format(
                        exception)
                    _LOGGER.exception(details)
                    _abort(state, rpc_event.call, cygrpc.StatusCode.unknown,
                           _common.encode(details))
            return None, False

  

里面的 behavior 就是我们的接口方法

对于之前提及的 helloworld 例子来说, behavior 就是下面这样(pycharm debug 得到的值)
<bound method Greeter.SayHello of <main.Greeter object at 0x0000024672710108>

还有一个工作要做,那就是发送响应,这个则是在 _unary_response_in_pool 中调用 _status 函数

 

 

def _status(rpc_event, state, serialized_response):
    with state.condition:
        if state.client is not _CANCELLED:
            code = _completion_code(state)
            details = _details(state)
            operations = [
                cygrpc.SendStatusFromServerOperation(
                    state.trailing_metadata, code, details, _EMPTY_FLAGS),
            ]
            if state.initial_metadata_allowed:
                operations.append(_get_initial_metadata_operation(state, None))
            if serialized_response is not None:
                operations.append(
                    cygrpc.SendMessageOperation(
                        serialized_response,
                        _get_send_message_op_flags_from_state(state)))
            rpc_event.call.start_server_batch(
                operations,
                _send_status_from_server(state, _SEND_STATUS_FROM_SERVER_TOKEN))
            state.statused = True
            _reset_per_message_state(state)
            state.due.add(_SEND_STATUS_FROM_SERVER_TOKEN)

  

 

在这里,python 只是做了一点微不足道的工作,主要工作是 c++ core 负责的

  • 总结

  •  

  •  

    返回标记位:

  •  

     

  •  

     

  •  

     

    def _serialize_response(rpc_event, state, response, response_serializer):
        serialized_response = _common.serialize(response, response_serializer)
        if serialized_response is None:
            with state.condition:
                _abort(state, rpc_event.call, cygrpc.StatusCode.internal,
                       b'Failed to serialize response!')
            return None
        else:
            return serialized_response
    

      

     

     

     
  • def _send_status_from_server(state, token):
    
        def send_status_from_server(unused_send_status_from_server_event):
            with state.condition:
                return _possibly_finish_call(state, token)
    
        return send_status_from_server
    

      

     

     


     
     
     

     

     

     非cancelled状态时候:

     

     

     

    最后返回:

     

     移除服务端标记

     

     移除服务端标记

     

     

     

     

     
     
     
     



参考链接:https://www.jianshu.com/p/d78015f2aaee

posted @ 2020-12-21 14:49  DaisyLinux  阅读(612)  评论(0编辑  收藏  举报