上周我阅读了有关vertx的文档。我不明白的是vertx处理器是如何工作的?例如
public class Client extends AbstractVerticle{
@Override
public void start() throws Exception {
final HttpClient httpClient = this.vertx.createHttpClient();
this.vertx.setPeriodic(1000, handler->{
httpClient.getNow(8080, "localhost", "/", responseHandler -> {
System.out.println("response");
});
});
}
}
和服务器是:
public class JdbcVertx extends AbstractVerticle{
@Override
public void start() throws Exception {
JDBCClient client = JDBCClient.createNonShared(this.vertx, new JsonObject()
.put("url", "jdbc:postgresql://localhost:5432/test")
.put("user", "user")
.put("password", "password")
.put("driver_class", "org.postgresql.Driver")
.put("max_pool_size", 30));
this.vertx.createHttpServer()
.requestHandler(r -> {
client.getConnection(handler -> {
final SQLConnection connection = handler.result();
connection.execute(execute(), hndlr -> {
connection.close(closehndlr -> {
r.response().putHeader("content-type", "text/html").end("Response");
});
});
});
}).listen(8080);
}
private String execute(){
return "insert into rubish (name) values ('test')";
}
}
(P.S.我知道我首先应该检查处理程序是否成功,然后采取一些措施,但为了简化代码,我删除了这种检查,如果在30秒内没有任何响应,则处理程序中会出现异常,也会从正式文档中删除。)
从上面的代码中,客户端每秒发送请求,并且不等待响应,但是它有一个处理程序,当响应到来时将执行该处理程序。
jdbcVertx监听端口8080,获取请求,插入到db睡眠例如3 s(我把1_000_000行到db并创建索引以减缓插入时间),然后发送响应,因此每个请求都是非阻塞的。
据我所知,vertx只有一个名为EventLoop事件循环的线程,来自jdbcVertx get reqest,但不会立即返回响应,而是放置了一个处理程序,该处理程序将在db插入成功时执行。事件循环如何知道何时执行IO操作。我认为它用了这样的东西
if(Thread.currentThread().getState != 'blocked' && sec != 30){
this.object.getHandler().execute();
} else if(sec == 30){
Thread.currentThread.inerrupt();
} else{
sec++;
}
但我们只有一个线程,当我们有阻塞调用时,它没有线程,只有处理程序。
问题是,事件循环如何知道阻塞操作何时结束,是时候执行处理程序了
回答问题:
事件循环如何知道阻塞操作何时结束以及执行处理程序的时间?
根据非阻塞模型,事件在调用时循环
connection.execute( execute(), hndlr )
生成一个新线程,执行阻塞代码,完成后(类似于Thread.join()
)调用事件循环线程中的hndlr
回调。因此,尽管可以执行阻塞代码,但主循环不会被阻塞。
但我们只有一个线程,当我们有阻塞调用时,它没有线程,只有处理程序。它是如何工作的,如果我们可以使用处理程序,为什么我们需要使用Worker Verticle?
处理程序只是在收到eventbus消息或http调用时触发的操作。它们不是为您处理可伸缩性而设计的。如果您只使用处理程序,并且如果您的操作开始花费很长时间,或者如果您的请求数量有任何增加,那么您将阻止verticle的eventloop,并且将有许多线程xxxx被阻止
警告。
要回答处理程序是如何工作的,以及为什么事件循环不等待处理程序结束后再启动另一个处理程序,请根据以下内容回答:https://vertx.io/docs/vertx-core/java/#_reactor_and_multi_reactor
每个Vertx实例维护多个事件循环,而不是单个事件循环。默认情况下,我们根据机器上可用的内核数量选择该数量,但这可以被覆盖。
这意味着单个Vertx进程可以在您的服务器上扩展,不同于Node.js.
我们将这种模式称为多反应器模式,以区别于单线程反应器模式。
但这还不足以为您解决所有可伸缩性和线程阻塞问题。在我看来,您也可以阅读以下内容:https://vertx.io/docs/vertx-core/java/#golden_rule
有很多方法可以设计垂直柱,但你必须尽可能保持无阻塞。在我看来,使用vert。x与传统的阻塞方法(例如阻塞restfullendpoint)无关。
就我个人而言,我会按照以下方式设计我的垂直线:
>
verticle A:它公开一个restfullendpoint,并获取一个回调url(无论操作GET/POST/PUT/PATCH/DELETE是什么)。verticle始终立即响应a202接受
,但没有结果,并在eventbus中向verticle B发送消息。
顶点B:获取消息,执行操作(最终与事件总线异步调用其他顶点并等待回复)并调用回调url进行回复。
我会避免使用worker verticle
或executeBlocking
方法,甚至避免创建线程池。我很荣幸将我的verticle B(在单独的PID中)的实例相乘,这些实例监听同一个eventbus集群(最终是带有http反向代理的verticle A)。我们甚至可以想象,根据实时请求的数量,有可变数量的verticle B实例(在单独的PID中)。
附言:有时我会使用一个功能更强大的消息代理工具,比如ApacheKafka,而不是原生的eventbus(当我需要尊重某种消息,或者当我需要重播一些消息时)。
在Vertx官方文件中,我阅读了以下段落 在关于Reactor的文章中: 据我所知,如果我写错了,请纠正我,Vertx的工作方式如下: 当我们为阻塞代码提供一个处理程序时,vertx将线程池中的一个线程(不是事件循环)放入该代码中,该线程等于内核数,例如我有4个内核,事件循环检查每次迭代后该线程的状态,如果它准备好执行与该阻塞代码相关的处理程序,当所有4个内核都忙时,vertx将任务放入队列,稍后
我正在上一门使用处理的课。 我在理解map()函数时遇到了问题。 根据文件记载(http://www.processing.org/reference/map_.html): 将数字从一个范围重新映射到另一个范围。 在上面的第一个示例中,数字25从0到100范围内的值转换为从窗口的左边缘(0)到右边缘(宽度)的值。 如第二个示例所示,范围之外的数字不会被钳制到最小和最大参数值,因为范围之外的值通常
我使用的是Vertx3.5.0,非常新。我试图在客户端取消请求时取消代码执行。 目前,我们要做的第一件事就是部署一个verticle来运行HttpServer,然后将所有路由添加到路由器。从这里开始,每个路由都有一个处理函数。在这个处理器中,我正在尝试: 这是我见过的唯一一个实际捕获连接关闭的方法,但问题是它没有在eventloop中足够早地执行处理程序。因此,如果我在那里有任何日志,它将看起来像
Vertx使用一个辅助线程来执行select语句,以避免阻塞事件循环线程,但是在这种情况下,每个sql查询都需要一个单独的线程来执行。但是如果Vertx不使用任何单独线程来执行查询呢?在这种情况下,事件循环如何知道结果何时来自DB呢?使用线程就很简单了,事件循环可以检查jdbc查询使用的线程的当前状态,如果状态准备就绪,就意味着事件循环应该执行回调 我说得对吗?
如果我有以下代码: 对该循环中某个处理程序的所有调用是并行执行还是顺序执行?如果是顺序的,那么要获得并行执行,正确的方法是什么? 当做
我正在运行VertX HTTP服务器。当内容类型为超文本标记语言/表单时,它可以理解请求,但当我尝试发布JSON数据时,它甚至从未进入请求处理程序。 我需要做些什么才能让Vertx期望JSON吗?是否支持?