Vertx http 服务器线程已被阻塞 xxxx 毫秒,时间限制为 2000

Rez*_*eza 5 java multithreading http vert.x

我已经使用编写了一个大型http服务器,但是当并发请求数量增加时我收到此错误

 WARNING: Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 8458 ms, time limit is 1000
Run Code Online (Sandbox Code Playgroud)

io.vertx.core.VertxException:线程被阻止

这是我的完整代码:

  public class MyVertxServer {

public Vertx vertx = Vertx.vertx(new VertxOptions().setWorkerPoolSize(100));
private HttpServer server = vertx.createHttpServer();
private Router router = Router.router(vertx);

public void bind(int port){


    server.requestHandler(router::accept).listen(port);

}

public void createContext(String path,MyHttpHandler handler){

    if(!path.endsWith("/")){
        path += "/";
    }

    path+="*";


    router.route(path).handler(new Handler<RoutingContext>() {

        @Override
        public void handle(RoutingContext ctx) {

            String[] handlerID = ctx.request().uri().split(ctx.currentRoute().getPath());

            String suffix = handlerID.length > 1 ? handlerID[1] : null;
            handler.Handle(ctx, new VertxUtils(), suffix);

        }
    });
}


}
Run Code Online (Sandbox Code Playgroud)

以及我如何称呼它:

    ver.createContext("/getRegisterManager",new ProfilesManager.RegisterHandler());
    ver.createContext("/getLoginManager", new ProfilesManager.LoginHandler());
    ver.createContext("/getMapcomCreator",new ItemsManager.MapcomCreator());
    ver.createContext("/getImagesManager", new ItemsManager.ImagesHandler());

    ver.bind(PORT);
Run Code Online (Sandbox Code Playgroud)

然而我发现 eventbus() 对于处理发送/接收文件的 http 服务器没有用,因为你需要在消息中发送 RoutingContext 是不可能的。

你能指出我正确的方向吗?谢谢

添加了一些处理程序的代码:

  class ProfileGetter implements MyHttpHandler{

    @Override
    public void Handle(RoutingContext ctx, VertxUtils utils, String suffix) {

        String username = utils.Decode(ctx.request().headers().get("username"));
        String lang = utils.Decode(ctx.request().headers().get("lang"));

        display("profile requested : "+username);

        Profile profile = ProfileManager.FindProfile(username,lang);

        if(profile == null){
            ctx.request().response().putHeader("available","false");
            utils.sendResponseAndEnd(ctx.response(),400);
            return;
        }else{
            ctx.request().response().putHeader("available","true");
            utils.writeStringAndEnd(ctx, new Gson().toJson(profile));
        }

    }



  }
Run Code Online (Sandbox Code Playgroud)

这里 ProfileManager.FindProfile(username,lang) 在同一线程上执行长时间运行的数据库作业

...

基本上我所有的进程都发生在主线程上,因为如果我使用执行器,我会在 Vertx 中得到奇怪的异常和空指针,让我感觉 Vertx 中的请求处理器是并行的

Pau*_*pes 2

鉴于问题中的代码量很少,我们同意问题就在眼前:

Profile profile = ProfileManager.FindProfile(username,lang);
Run Code Online (Sandbox Code Playgroud)

假设这是在内部执行一些阻塞 JDBC 调用,这是 Vert.x 中的反模式,您可以通过多种方式解决此问题。

假设您可以完全重构ProfileManagerIMO 最好的类,然后您可以将其更新为响应式,因此您的代码将如下所示:

ProfileManager.FindProfile(username,lang, res -> {
  if (res.failed()) {
    // handle error, sent 500 back, etc...
  } else {
    Profile profile = res.result();

    if(profile == null){
      ctx.request().response().putHeader("available","false");
      utils.sendResponseAndEnd(ctx.response(),400);
      return;
    }else{
      ctx.request().response().putHeader("available","true");
      utils.writeStringAndEnd(ctx, new Gson().toJson(profile));
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

现在,幕后发生的情况是您的 JDBC 调用不会阻塞(这很棘手,因为 JDBC 本质上是阻塞的)。因此,要解决这个问题,并且您很幸运能够使用 MySQL 或 Postgres,那么您可以针对异步客户端编写 JDBC 代码,如果您无法使用其他 RDBMS 服务器,那么您需要使用jdbc-client,而 jdbc-client反过来将使用线程池用于卸载事件循环线程的工作。

现在假设您无法更改代码ProfileManager,那么您仍然可以通过将代码包装在块中来将其卸载到线程池executeBlocking

vertx.executeBlocking(future -> {
  Profile profile = ProfileManager.FindProfile(username,lang);
  future.complete(profile);
}, false, res -> {
  if (res.failed()) {
    // handle error, sent 500 back, etc...
  } else {
    Profile profile = res.result();

    if(profile == null){
      ctx.request().response().putHeader("available","false");
      utils.sendResponseAndEnd(ctx.response(),400);
      return;
    }else{
      ctx.request().response().putHeader("available","true");
      utils.writeStringAndEnd(ctx, new Gson().toJson(profile));
    }
  }
});
Run Code Online (Sandbox Code Playgroud)