vert.x 关于网络服务器的概念?

Concept of vert.x concerning a webserver?

我不太明白 vert.x 是如何应用于网络服务器的。

我所知道的网络服务器概念是基于线程的。

  1. 你启动你的网络服务器,然后是 运行ning。
  2. 然后对于每个连接的客户端,您都会得到一个套接字,然后将其传递给它自己的线程处理程序。
  3. 线程处理程序然后处理此特定套接字的任务。

所以明确定义了哪个线程在为哪个socket做工作。 但是,对于每个套接字,您都需要一个新线程,这对于许多套接字来说很长运行。

然后是 vert.x 提供的基于事件的概念。 到目前为止我已经明白,它应该像这样工作:

  1. Vertx 实例部署 Verticles。
  2. 后台线程中的 Verticles 运行,但并非每个 Verticle 都有自己的线程。例如,一个 Vertx 实例中可能部署了 1000 个 Verticle,但 Vertx 实例仅处理 8 个线程(核心数量 * 2)。
  3. 然后是事件循环。我不确定他们是如何引用 Verticles 的。我读到每个 Verticle 都有 2 个事件循环,但我真的不知道它是如何工作的。

作为网络服务器示例:

class WebServer: AbstractVerticle() {
    lateinit var server: HttpServer

    override fun start() {
        server = vertx.createHttpServer(HttpServerOptions().setPort(1234).setHost("localhost"))
        var router = Router.router(vertx);
        router.route("/test").handler { routingContext ->
            var response = routingContext.response();
            response.end("Hello from my first HttpServer")
        }
        server.requestHandler(router).listen()
    }
}

这个WebServer可以在一个Vertx实例中多次部署。看起来,每个 WebServer 实例都有自己的线程。当我尝试连接 100 个客户端并回复一个简单的响应时,似乎每个客户端都是同步处理的。因为当我在每个服务器处理程序中执行 Thread.sleep 语句时,每秒都会有一个客户端收到响应。然而,应该是所有服务器处理程序都应该开始他们的 1 秒休眠,然后在这段时间之后几乎相同地回复所有客户端。

这是启动 100 个客户端的代码:

fun main(){
    Vertx.vertx().deployVerticle(object : AbstractVerticle(){
        override fun start() {
            for(i in 0 .. 100)
                MyWebClient(vertx)
        }
    })
}

class MyWebClient(val vertx: Vertx) {
    init {
        println("Client starting ...")
        val webClient = WebClient.create(vertx, WebClientOptions().setDefaultPort(1234).setDefaultHost("localhost"))
        webClient.get("/test").send { ar ->
            if(ar.succeeded()){
                val response: HttpResponse<Buffer> = ar.result()

                println("Received response with status code ${response.statusCode()} + ${response.body()}")
            } else {
                println("Something went wrong " + ar.cause().message)
            }
        }
    }
}

有人知道这个的解释吗?

您的代码的问题是,默认情况下 Vert.x 每个 Verticle 最多只使用一个线程(如果 Verticle 多于可用线程,则单个线程必须处理多个 Verticle)。

因此,如果您对单个 Verticle 的单个实例执行 100 个请求,则这些请求将由单个线程处理。

要解决您的问题,您应该部署 Verticle 的多个实例,即

vertx.deployVerticle(MainVerticle::class.java.name, DeploymentOptions().setInstances(4))

这样做时,总是会几乎同时收到 4 个响应,因为 Verticle 的 4 个实例是 运行,因此使用了 4 个线程。

在之前的Vert.x版本中,如果您不想设置特定数量的实例,您也可以简单地为一个Verticle配置multi-threading。

vertx.deployVerticle(MainVerticle::class.java.name, DeploymentOptions().setWorker(true).setMultiThreaded(true))

但是,此功能已被弃用并替换为客户工作人员池。

有关此主题的更多信息,我鼓励您查看 Vert.x-core Kotlin documentation

那里有一些重大问题。

当你这样做时:

class WebServer: AbstractVerticle() {
    lateinit var server: HttpServer

    override fun start() {
        server = vertx.createHttpServer(HttpServerOptions().setPort(1234).setHost("localhost"))
       ...
    }
}

然后是这样的:

vertx.deployVerticle(WebServer::class.java.name, DeploymentOptions().setInstances(4)

您将获得 4 个 Verticle,但其中只有一个会实际侦听端口。因此,您不会再获得任何并发性。

其次,当您在 Vert.x 代码中使用 Thread.sleep 时,您会阻塞事件循环线程。

第三,你的客户端测试不正确。创建 WebClient 的成本非常高,因此通过一个接一个地创建 WebClient,您实际上会非常缓慢地发出请求。如果您真的想测试您的 Web 应用程序,请使用 https://github.com/wg/wrk