ServiceComb【2】CSE请求转发

356 阅读5分钟

Producer如何接受请求

有以下重要问题

  • 怎么将HTTP请求映射到Controller方法调用的;
  • CSE提供的各种扩展,如HttpServerFilter,Handler是如何嵌入到处理流程的;

HttpServer创建

CSE使用Vertx创建HttpServer,入口类为VertxRestTransport

1、org.apache.servicecomb.transport.rest.vertx.VertxRestTransport.init()方法如下:

@Override
public boolean init() throws Exception {
  restClient = RestTransportClientManager.INSTANCE.getRestClient();
  
  // 部署transport server
  DeploymentOptions options = new DeploymentOptions().setInstances(TransportConfig.getThreadCount()); // 新建rest请求的client
  SimpleJsonObject json = new SimpleJsonObject();
  json.put(ENDPOINT_KEY, getEndpoint());
  json.put(RestTransportClient.class.getName(), restClient);
  options.setConfig(json);
  return VertxUtils.blockDeploy(transportVertx, TransportConfig.getRestServerVerticle(), options);
}

2、所有的请求走到VertxRestDispatcher.onRequest方法进行处理:

protected void onRequest(RoutingContext context) {
  if (transport == null) {
    transport = CseContext.getInstance().getTransportManager().findTransport(Const.RESTFUL);
  }
  HttpServletRequestEx requestEx = new VertxServerRequestToHttpServletRequest(context); // 新建请求对象
  HttpServletResponseEx responseEx = new VertxServerResponseToHttpServletResponse(context.response()); // 新建响应对象
  
  VertxRestInvocation vertxRestInvocation = new VertxRestInvocation();
  context.put(RestConst.REST_PRODUCER_INVOCATION, vertxRestInvocation);
  vertxRestInvocation.invoke(transport, requestEx, responseEx, httpServerFilters); // 请求的处理
}

context的信息如下:

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

requestEx的信息如下:

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

responseEx的信息如下:

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

3、org.apache.servicecomb.common.rest.RestProducerInvocation.invoke()方法如下:

public void invoke(Transport transport, HttpServletRequestEx requestEx, HttpServletResponseEx responseEx, List<HttpServerFilter> httpServerFilters) {
        this.transport = transport;
        this.requestEx = requestEx;
        this.responseEx = responseEx;
        this.httpServerFilters = httpServerFilters;
        requestEx.setAttribute("servicecomb-rest-request", requestEx);  // 其中放入requestEx的引用

        try {
            this.findRestOperation();
        } catch (InvocationException var6) {
            this.sendFailResponse(var6);
            return;
        }

        this.scheduleInvocation();
    }

进入RestProducerInvocation.findRestOperation()方法:

protected void findRestOperation() {
    MicroserviceMeta selfMicroserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta();
    this.findRestOperation(selfMicroserviceMeta);
}

selfMicroserviceMeta的内容如下:

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

4、org.apache.servicecomb.common.rest.AbstractRestInvocation.findRestOperation()方法如下:

protected void findRestOperation(MicroserviceMeta microserviceMeta) {
    ServicePathManager servicePathManager = ServicePathManager.getServicePathManager(microserviceMeta); // 获取所有的schema的信息
    if (servicePathManager == null) {
        LOGGER.error("No schema defined for {}:{}.", microserviceMeta.getAppId(), microserviceMeta.getName());
        throw new InvocationException(Status.NOT_FOUND, Status.NOT_FOUND.getReasonPhrase());
    } else {
        OperationLocator locator = this.locateOperation(servicePathManager); // 定位到具体的处理rest
        this.requestEx.setAttribute("servicecomb-paths", locator.getPathVarMap());
        this.restOperationMeta = locator.getOperation();
    }
}

servicePathManager的参数如下:

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

locator的参数如下:

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

此时找到对应的处理rest,下面将请求转发过去。

此时,回到org.apache.servicecomb.common.rest.RestProducerInvocation.invoke()方法:

public void invoke(Transport transport, HttpServletRequestEx requestEx, HttpServletResponseEx responseEx, List<HttpServerFilter> httpServerFilters) {
    this.transport = transport;
    this.requestEx = requestEx;
    this.responseEx = responseEx;
    this.httpServerFilters = httpServerFilters;
    requestEx.setAttribute("servicecomb-rest-request", requestEx);
    
    try {
        this.findRestOperation();
    } catch (InvocationException var6) {
        this.sendFailResponse(var6);
        return;
    }
    
    this.scheduleInvocation(); // 下一步,进行请求的处理
}

5、进入org.apache.servicecomb.common.rest.AbstractRestInvocation.scheduleInvocation()方法:

protected void scheduleInvocation() {
        try {
            this.createInvocation(); // 创建invovation对象属性
        } catch (Throwable var6) {
            this.sendFailResponse(var6);
            return;
        }

        this.invocation.onStart(this.requestEx, this.start);
        this.invocation.getInvocationStageTrace().startSchedule(); // 初始化InvocationStageTrace.startSchedule变量为当前时间
        OperationMeta operationMeta = this.restOperationMeta.getOperationMeta();

        try {
            this.setContext();
        } catch (Exception var5) {
            LOGGER.error("failed to set invocation context", var5);
            this.sendFailResponse(var5);
            return;
        }

        Holder<Boolean> qpsFlowControlReject = this.checkQpsFlowControl(operationMeta);
        if (!(Boolean)qpsFlowControlReject.value) {
            try {
                operationMeta.getExecutor().execute(() -> {
                    synchronized(this.requestEx) {
                        try {
                            if (this.isInQueueTimeout()) {  // 判断是否已经超时
                                throw new InvocationException(Status.INTERNAL_SERVER_ERROR, "Timeout when processing the request.");
                            }

                            if (this.requestEx.getAttribute("servicecomb-rest-request") != this.requestEx) {
                                LOGGER.error("Rest request already timeout, abandon execute, method {}, operation {}.", operationMeta.getHttpMethod(), operationMeta.getMicroserviceQualifiedName());
                                return;
                            }

                            this.runOnExecutor();
                        } catch (Throwable var5) {
                            LOGGER.error("rest server onRequest error", var5);
                            this.sendFailResponse(var5);
                        }

                    }
                });
            } catch (Throwable var4) {
                LOGGER.error("failed to schedule invocation, message={}, executor={}.", var4.getMessage(), var4.getClass().getName());
                this.sendFailResponse(var4);
            }

        }
    }

6、创建invocation的方法如下:

protected void createInvocation() {
    super.createInvocation();
    ((VertxServerRequestToHttpServletRequest)this.requestEx).getContext().put("servicecomb-rest-invocation-context", this.invocation);
}

invocation的参数内容如下:

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

7、调用org.apache.servicecomb.core.Invocation.onStart()方法

public void onStart(HttpServletRequestEx requestEx, long start) {
        this.requestEx = requestEx;
        this.onStart(start); 
    }

public void onStart(long start) {
    this.invocationStageTrace.start(start); // InvocationStageTrace为处理过程的追踪类
    this.initTraceId(); // 生成traceid
    EventManager.post(new InvocationStartEvent(this)); // 发送InvocationStartEvent事件
}

8、AbstractRestInvocation.setContext()方法如下:

protected void setContext() throws Exception {
        String strCseContext = this.requestEx.getHeader("x-cse-context");
        if (!StringUtils.isEmpty(strCseContext)) {
            Map<String, String> cseContext = (Map)JsonUtils.readValue(strCseContext.getBytes(StandardCharsets.UTF_8), Map.class);
            this.invocation.mergeContext(cseContext); // 将header中的x-cse-context的信息合并入InvocationContext的context对象中
        }
    }

9、AbstractRestInvocation.checkQpsFlowControl进行流控:

private Holder<Boolean> checkQpsFlowControl(OperationMeta operationMeta) {
    Holder<Boolean> qpsFlowControlReject = new Holder(false);
    Handler providerQpsFlowControlHandler = operationMeta.getProviderQpsFlowControlHandler();
    if (null != providerQpsFlowControlHandler) {
        try {
            providerQpsFlowControlHandler.handle(this.invocation, (response) -> {
                qpsFlowControlReject.value = true;
                this.produceProcessor = ProduceProcessorManager.JSON_PROCESSOR;
                this.sendResponse(response);
            });
        } catch (Throwable var5) {
            LOGGER.error("failed to execute ProviderQpsFlowControlHandler", var5);
            qpsFlowControlReject.value = true;
            this.sendFailResponse(var5);
        }
    }
    
    return qpsFlowControlReject;
}

operationMeta的信息如下:

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

如果设置对应的Qps的限制的handler,会在此处生效,返回结果为是否拒绝对应的请求。

10、operationMeta.getExecutor().execute获取对应的处理线程进行请求的异步处理

对应的线程池信息如下:

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

首先判断请求是否已经超时:

private boolean isInQueueTimeout() {
        return System.nanoTime() - this.invocation.getInvocationStageTrace().getStart() > this.invocation.getOperationMeta().getConfig().getNanoRestRequestWaitInPoolTimeout();
    }

this.requestEx.getAttribute("servicecomb-rest-request") != this.requestEx判断当前的请求的请求信息是否还在,请求信息是否已经被抛弃。

11、进入请求的处理方法AbstractRestInvocation.runOnExecutor()

protected void runOnExecutor() {
        this.invocation.onExecuteStart(); // 重置InvocationStageTrace.startExecution变量的值为当前时间戳
        this.invoke();
    }

public void invoke() {
    try {
        Response response = this.prepareInvoke();
        if (response != null) { // 如果返回的结果不为null,直接进行返回,不做后续的处理
            this.sendResponseQuietly(response);
            return;
        }
         
        this.doInvoke(); // 处理到对应的方法
    } catch (Throwable var2) {
        LOGGER.error("unknown rest exception.", var2);
        this.sendFailResponse(var2);
    }
    
}

protected Response prepareInvoke() throws Throwable {
    this.initProduceProcessor();
    this.invocation.getHandlerContext().put("servicecomb-rest-request", this.requestEx);
    this.invocation.getInvocationStageTrace().startServerFiltersRequest();
    Iterator var1 = this.httpServerFilters.iterator(); // 获取到所有的HttpServerFilters的实现类
    
    while(var1.hasNext()) {
        HttpServerFilter filter = (HttpServerFilter)var1.next();
        if (filter.enabled()) {
            Response response = filter.afterReceiveRequest(this.invocation, this.requestEx); // 依次调用HttpServerFilter的afterReceiveRequest方法
            if (response != null) {
                return response; // 如果response不为null,返回
            }
        }
    }
    
    return null;
}

12、进入AbstractRestInvocation.doInvoke方法

protected void doInvoke() throws Throwable {
        this.invocation.getInvocationStageTrace().startHandlersRequest(); // 将InvovationStageTrace.startHandlersRequest初始化为当前时间戳        this.invocation.next((resp) -> {            this.sendResponseQuietly(resp);        });    }protected void sendResponseQuietly(Response response) {
    if (this.invocation != null) {
        this.invocation.getInvocationStageTrace().finishHandlersResponse();
    }

    try {
        this.sendResponse(response);
    } catch (Throwable var3) {
        LOGGER.error("Failed to send rest response, operation:{}, request uri:{}", new Object[]{this.getMicroserviceQualifiedName(), this.requestEx.getRequestURI(), var3});
    }

}
protected void sendResponseQuietly(Response response) {
    if (this.invocation != null) {
        this.invocation.getInvocationStageTrace().finishHandlersResponse();
    }
    
    try {
        this.sendResponse(response);
    } catch (Throwable var3) {
        LOGGER.error("Failed to send rest response, operation:{}, request uri:{}", new Object[]{this.getMicroserviceQualifiedName(), this.requestEx.getRequestURI(), var3});
    }
    
}

13、进入org.apache.servicecomb.core.Invocation.next()方法

public void next(AsyncResponse asyncResp) throws Exception {
int runIndex = this.handlerIndex++;
((Handler)this.handlerList.get(runIndex)).handle(this, asyncResp);
}

this.handlerList为Handler的实现类,当前存在InterceptorHandler,ValidateHandler,ProducerOperationHandler实现,优先级从高到低。

14、进入org.apache.servicecomb.core.handler.impl.ProducerOperationHandler.handle()方法中


public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception {
SwaggerProducerOperation producerOperation = (SwaggerProducerOperation)invocation.getOperationMeta().getExtData("producer-operation");
if (producerOperation == null) {
asyncResp.producerFail(ExceptionUtils.producerOperationNotExist(invocation.getSchemaId(), invocation.getOperationName()));
} else {
producerOperation.invoke(invocation, asyncResp);
}
}

15、进入org.apache.servicecomb.swagger.engine.SwaggerProducerOperation.invoke()方法


public void invoke(SwaggerInvocation invocation, AsyncResponse asyncResp) {
if (CompletableFuture.class.equals(this.producerMethod.getReturnType())) {
this.completableFutureInvoke(invocation, asyncResp);
} else {
this.syncInvoke(invocation, asyncResp);
}
}

public void syncInvoke(SwaggerInvocation invocation, AsyncResponse asyncResp) {
ContextUtils.setInvocationContext(invocation);
Response response = this.doInvoke(invocation);
ContextUtils.removeInvocationContext();
asyncResp.handle(response);
}

public Response doInvoke(SwaggerInvocation invocation) {
Response response = null;

try {
     invocation.onBusinessMethodStart();
     Object[] args = this.argumentsMapper.toProducerArgs(invocation);
     Iterator var4 = this.producerInvokeExtenstionList.iterator();

     while(var4.hasNext()) {
         ProducerInvokeExtension producerInvokeExtension = (ProducerInvokeExtension)var4.next();
         producerInvokeExtension.beforeMethodInvoke(invocation, this, args);
     }

     Object result = this.producerMethod.invoke(this.producerInstance, args);
     response = this.responseMapper.mapResponse(invocation.getStatus(), result);
     invocation.onBusinessMethodFinish();
     invocation.onBusinessFinish();
 } catch (Throwable var6) {
     if (this.shouldPrintErrorLog(var6)) {
         LOGGER.error("unexpected error operation={}, message={}", invocation.getInvocationQualifiedName(), ExceptionUtils.getExceptionMessageWithoutTrace(var6));
     }

     invocation.onBusinessMethodFinish();
     invocation.onBusinessFinish();
     response = this.processException(invocation, var6);
 }

 return response;

}

this.producerMethod的参数为

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

this.producerInstance的参数如下:

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

args的参数为

![image转存失败,建议直接上传图片文件](<转存失败,建议直接上传图片文件 )

this.producerMethod就是目标处理方法的代理对象

private List producerInvokeExtenstionList = SPIServiceUtils.getSortedService(ProducerInvokeExtension.class);实现了处理前的扩展点。