1

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

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

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

因此明确定义了哪个线程为哪个套接字工作。但是,对于每个套接字,您都需要一个新线程,从长远来看,这对于许多套接字来说是昂贵的。

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

  1. Vertx 实例部署 Verticle。
  2. Verticle 在后台线程中运行,但并不是每个 Verticle 都有自己的线程。例如,一个 Vertx 实例中可能部署了 1000 个 Verticle,但 Vertx 实例仅处理 8 个线程(nr of cores * 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)
            }
        }
    }
}

有人知道对此的解释吗?

4

2 回答 2

1

那里有一些重大问题。

当你这样做时:

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,但其中只有一个会实际侦听端口。因此,您不再获得任何并发性。

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

第三,您对客户的测试不正确。创建 WebClient 非常昂贵,因此通过一个接一个地创建这些,您实际上发出请求的速度非常慢。如果您真的想测试您的 Web 应用程序,请使用https://github.com/wg/wrk 之类的东西

于 2019-05-30T07:30:27.823 回答
0

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

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

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

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

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

在以前的 Vert.x 版本中,如果您不想设置特定数量的实例,也可以简单地为 Verticle 配置多线程。

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

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

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

于 2019-05-29T12:27:58.123 回答