Vert.x Core
Vert.x core contains fairly low-level functionality, including support for HTTP, TCP, file system access, and various other features. You can use this directly in your own applications, and it’s used by many of the other components of Vert.x.
Vert.x中,有以下的核心概念需要了解
Vertx
Vertx实例(instance)可以通过静态工厂方法
创建,一个Vertx实例可以用于部署HTTP、TCP Server,client等等操作,可以将Vertx instance看做一个Vert.x Core API 的入口。
Eventloop
Vert.x使用了Reactor模型,通过Event driven的方式,将Events分发到handlers中进行处理,任何event都不会阻塞Eventloop线程,这样Eventloop线程可以一直保持高速分发Events的速度。假设在同一时间有很多HTTP请求到达服务器,Eventloop会将每一个http request分发到handler中处理,比如有10K个Requests,假设服务器想在1s内处理这些requests,那么平均算下来Eventloop必须能在0.1ms内分发完每个event,一旦Eventloop被阻塞,整个服务器吞吐量都会受到极大影响。所以Eventloop绝对不应该被阻塞住,所有交给Eventloop去处理的event都应该是non-blocking(I/O)的方式或者CPU执行时间较短的,这样才能确保每个event得到及时的分发。
而Vert.x不仅仅实现了Reactor模型,还实现了Multi-Reactor模型,也就是说,每个Vertx instance都会有多个Eventloop,默认的设置是Eventloop数量对应CPU核心数量乘以2,在VertxOptions类中可以看到
|
|
可以通过setEventLoopPoolSize()
方法改变Vertx实例拥有Eventloop的数量。
Context
Context的字面意思是上下文或者环境,在Vert.x中,Context对应的是一次Handler执行过程的执行context。在Context接口中的文档已经说的十分清楚:
当Vert.x将一个事件event分发到handler中或者调用了一个Verticle的启动停止操作方法时,该次执行execution就被关联到了一个Context。
那么Context是用来干什么的呢,Context就是用来管理控制着handlers或者handlers创建的任务执行时的scope和order的。当使用Vert.x API把event分发到handler时,例如设置一个HttpServer的request handler时,会将该handler的callback和一个context绑定起来,这个Context就会被用来调度callbacks。如果执行任务当前所在的线程是Vert.x线程的话,那么该任务将复用已经和线程所绑定的context;如果当前线程不是Vert.x线程,那么就创建一个新的context。
Vert.x线程可以参考VertxThread类,继承了Netty中的FastThreadLocalThread。简略类图如下
可以看到VertxThread类中是包含了context信息的。
Vert.x中一共有三种类型的contexts
- Eventloop Context
- Worker Context
- Multi-Thread worker Context
一般来说,大部分操作都是关联Eventloop context的。
Eventloop Context 会和一个Eventloop线程绑定在一起,保证该Context下的executions一直在相同的Eventloop线程中。
需要注意的是,一个context只会在一个线程中执行,而一个线程可能会被多个contexts所使用。
Verticle
Verticle是Vert.x中提供的类似Actor Model的一种模型,在使用verticle部署自己的应用时,每个Vertx instance都会有多个Verticle instances,verticle之间通过eventBus来进行通信。
当部署一个新的Verticle时,会为这个Verticle创建一个新的Context, 每个Verticle会一直关联一个context,任何在这个Verticle上面注册的handler都会通过verticle的context关联。
而与Vert.x Context中三种Context对应,Verticle也有三种类型,简单说下每种Verticle特点。
Standard Verticle
这是最常用的Verticle类型, 这种Verticle会被指派到创建和启动时的Eventloop线程上,Vert.x会保证你在这个Verticle实例上调用任何的handler操作将在同样的eventloop线程上面执行。Worker Verticle
Worker Verticle目标是为了执行阻塞的代码,不会在Eventloop上执行,而是从Vert.x worker线程池中拿出一个线程来执行。这样的话即使进行的是阻塞操作,它也不会让eventloop阻塞挂掉。Worker verticle在同一个时间片内只会被Vert.x执行在一个线程内,它不会被并发执行,但是不同时间段有可能被不同线程执行。Multi-Thread worker Verticle
Multi-Thread worker Verticle跟Worker Verticle很像,不同的是,它会被多个线程执行。一旦使用了这种Verticle就一定得注意它在多个线程之间共享的状态所带来的问题。
EventBus
The event bus is the nervous system of Vert.x.
This is a crucial component of Vert.x.
See http://vertx.io/docs/vertx-core/java/#event_bus
AbstractVerticle
AbstractVerticle是Vert.x实现了Verticle接口提供给用户使用的一个抽象类,将自己的类继承自AbstractVerticle,在start()
方法或者stop()
方法中自定义一些操作,然后通过vertx实例来部署verticle。
一般的来说一个Vert.x应用应该是这样的
一个Vert.x实例对应多个Eventloop 线程,每个Eventloop线程包含多个Context,每个Context对应一个Verticle instance。注意这里不要把Vertx Instance与Verticle Instance混为一谈了,通常情况下对于你的应用Vertx Instance只会有一个,当然也可以部署多个Vertx Instance,比如想去隔离出多个EventBus。而进行水平扩展时一般是通过增加你的Verticle Instance来实现,部署多个Verticle Instance时,verticle instance会运行在不同EventLoop里面,利用CPU多核心完成水平扩展,运行时Vert.x能通过EventBus自动做负载均衡,这个特性非常的nice。
另外,部署多个instances时,这些verticle instance的线程是不同的(当然,因为他们跑在不同的EventLoop上),Context也不同(这也理所应当,因为context只会跟一个verticle相关联),但是他们的deploymentID是一样的,调用vertx.deploymentIDs()
方法只会看到一个ID。
AsyncResult
顾名思义, AsyncResult包装了进行异步操作的结果。
result()
方法可以用于获取操作的结果。
Handler
Handler仅仅是一个函数接口,只有一个抽象方法handle()
,通常会与AsyncResult一起使用,handler中包裹一个异步调用的结果,类似void doSomething(Handler<AsyncResult<T>> handler)
的形式。
Future
Future在Vert.x中用于表示一个操作的结果,如果使用handler包裹AsyncResult处理callback的方式,那么可能会产生callback hell,所以Vert.x自己提供了一个Future,用于对异步结果的处理。Future之间还可以用compose、otherwise等操作进行组合,在一定程度避免了回调地狱的出现。
参考资料
These are all awesome materials to learn, thanks for the authors!