Vert.x是基于事件的,提供一个事件驱动编程模型
使用Vert.x作为服务器时,程序员只要编写事件处理器event handler即可。(当TCP socket有数据时,event handler被创建调用)
另外它还可以在以下几种情况激活:
- 事件总线Event Bus接受到消息时
- 接收到HTTP消息时
- 一个连接断开时
- 计时器超时时
Vert.x是一个异步非阻塞框架,可以有更高并发特性
使用它,可以灵活的部署与卸载相应的灰度控制(热部署,无需重启服务),函数式,serverless。需要什么,把配置加上去,就可以实现服务。
Vert.x的核心运行机制是事件循环,当Vert.x实例启动后,Vert.x框架在每个CPU的内核创建一个事件循环线程(Event Loop Vertical)。此事件循环线程永不结束,它不断监听出现的各种事件,如事件总线的事件到达WebSocket上的数据接收,HTTP上的请求到达HTTP响应结束,定时器触发等等,并把事件分发到注册了监听此事件的Verticle
,再继续监听其他的事件,如此反复直到Vert.x实例停止。
核心概念
Vert.x的事件机制中有几个非常重要的概念:
Event Loop
:即事件循环,是由Vert.x启动的事件处理线程,也是Vert.x项目对外开放的入口,Vert.x由此接收请求事件。一个Vert.x有一个或多个事件循环线程组成,线程最大数量为主机有效的CPU核数。Event Loop Vertical
:事件的业务处理线程,存在于Event Loop中,用于处理非阻塞短任务。Worker Vertical
: 事件的业务处理线程,用于处理长任务阻塞任务。Event Bus
:即事件总线,是Vert.x事件模型中最核心的部分,所有的事件都经由事件总线进行分发,包括Vertical之间的通信事件。Vert.x Module
: Vert.x项目模块,一个应用通常由多个模块组成,每个模块一般包含多个Vertical
事件模型
Vert.x以非阻塞IO的思想来实现高性能,非阻塞IO的实现,基于Event Loop Vertical
和Worker Vertical
的分离。
在Vert.x中,Event Loop
用于接收,并将短业务操作交由其内部的Vertical来处理,该模块是非阻塞的,这样可以保证请求的处理效率;阻塞任务通过Vert.x的事件机制脱离当前线程,转移到Worker Vertical
中执行,并执行结果返回给Event Loop Vertical
。 这一过程完成的核心是Event Bus
,Event Bus
中注册了所有的事件,通过事件匹配完成事件转移和结果返回,从而将整个流程衔接起来
下面以一个HTTP请求的处理过程详述Vert.x的事件处理流程。
- Vert.x启动时,会将Worker Vertical的事件处理函数加载到Event Bus
- 当一个HTTP请求发送到Vert.x构建的应用时,Event Loop首先接收到请求,并对请求做分析、包装,然后将事件交给Event Bus来处理
- Event Bus为此次请求事件添加一个事件ID,然后根据注册的Worker Vertical事件寻找已经注册的监听函数,若未找到则会抛弃该事件,若找到则会对处理类进行实例化,并同时使用事件ID在Event Bus中注册一个返回结果处理事件,该事件为Event Vertical类型
- 由Worker Vertical实例执行事件处理函数,事件处理函数中通常包含业务处理、数据库操作等
- Worker Vertical实例处理结束后,将返回结果和事件信息返回给Event Bus,Event Bus找到在其中注册的Event Vertical实例,然后将返回数据交给该实例处理
- Event Vertical实例进一步处理数据并将结果返回给浏览器
事件驱动的处理过程,数据传递是非常重要的,Vert.x支持任意对象的数据格式。但使用对象时经常会遇到序列化和载入类的问题,比如在使用Java对象的时候,这种情况下使用JSON会更方便,这也是Vert.x推荐采用的方式
组件介绍
Vert.x Core
Vert.x 的核心 Java API 被我们称为 Vert.x Core。
Vert.x Core 提供了下列功能:
- 编写 TCP 客户端和服务端
- 编写支持 WebSocket 的 HTTP 客户端和服务端
- 事件总线
- 共享数据 —— 本地的Map和分布式集群Map
- 周期性、延迟性动作
- 部署和撤销 Verticle 实例
- 数据报套接字
- DNS客户端
- 文件系统访问
- 高可用性
- 集群
Vert.x Core中的功能相当底层——您在此不会找到诸如数据库访问、授权或高层Web应用的功能。您可以在Vert.x ext(扩展包)中找到这些功能。
Vert.x的扩展包是Vert.x的子项目集合,类似Web、Web Client、Data Access等
Vert.x Core小而轻,您可以只使用您需要的部分。它可整体嵌入现存应用中。我们并不会强迫您用特定的方式构造您的应用。
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>3.4.2</version>
</dependency>
Verticle 种类
这儿有三种不同类型的 Verticle:
Stardand Verticle
:这是最常用的一类 Verticle —— 它们永远运行在 Event Loop 线程上Worker Verticle
:这类 Verticle 会运行在 Worker Pool 中的线程上。一个实例绝对不会被多个线程同时执行Multi-Threaded Worker Verticle
:这类 Verticle 也会运行在 Worker Pool 中的线程上。一个实例可以由多个线程同时执行(因此需要开发者自己确保线程安全)
Standard Verticle
当 Standard Verticle 被创建时,它会被分派给一个 Event Loop 线程,并在这个 Event Loop 中执行它的start
方法。当您在一个 Event Loop 上调用了 Core API 中的方法并传入了处理器时,Vert.x 将保证用与调用该方法时相同的 Event Loop 来执行这些处理器。
这意味着我们可以保证您的 Verticle 实例中所有的代码都是在相同Event Loop中执行
同样意味着您可以将您的应用中的所有代码用单线程方式编写,让 Vert.x 去考虑线程和扩展问题。您不用再考虑 synchronized 和 volatile 的问题,也可以避免传统的多线程应用经常会遇到的竞态条件和死锁的问题。
Worker Verticle
Worker Verticle 和 Standard Verticle 很像,但它并不是由一个 Event Loop 来执行,而是由Vert.x中的 Worker Pool 中的线程执行。Worker Verticle 被设计来调用阻塞式代码,它不会阻塞任何 Event Loop。
如果您不想使用 Worker Verticle 来运行阻塞式代码,您还可以在一个Event Loop中直接使用内联阻塞式代码
若您想要将 Verticle 部署成一个 Worker Verticle,您可以通过setWorker
方法来设置:
DeploymentOptions options = new DeploymentOptions().setWorker(true);
vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options);
Worker Verticle 实例绝对不会在 Vert.x 中被多个线程同时执行,但它可以在不同时间由不同线程执行。
Multi-threaded Worker Verticle
一个 Multi-threaded Worker Verticle 近似于普通的 Worker Verticle,但是它可以由不同的线程同时执行。
警告:Multi-threaded Worker Verticle 是一个高级功能,大部分应用程序不会需要它。由于这些 Verticle 是并发的,您必须小心地使用标准的Java多线程技术来保持 Verticle 的状态一致性。
参考资料:
- Vert.x
- Vertx,融合Java、Ruby、Python等语言的高性能架构
- Vert.x doc