天天看点

Vert.x特性

参考官方文档

什么是Vert.x

Vert.x是一个运行在JVM上的多语言、非阻塞式、事件驱动的应用程序框架平台

一些显著的特性包括:

多语言支持:Vert.x类似于Node.js,但你可以使用JavaScript,Ruby,Groovy,Java或者Python等来编写你的应用组件(只要能再JVM上运行的常见语言,都可以直接编写基于Vert.x的应用),甚至你可以在一个单独的应用程序中混合使用数种编程语言,一句话概括就是Vert.x让不同的语言可以更容易的在JVM上协作。

异步编程:简单的类似actor的并发模型:Vert.x允许你以单线程方式来编写你的所有代码,你的程序都是基于异步事件且通信无阻塞,这可以避免你可能遇到的大部分多线程编程陷阱(你不需要关注线程间的调用、同步、死锁等繁琐的事情,不再会有synchronized,volatile和显示锁,简单的帮你实现一个非常不简单的事情)。Vert.x提供了一系列的异步API,你在Vert.x中所要做的大部分事情就是设置event handlers(事件处理函数),例如你设置了一个handler用来接受来自TCP socket的数据,当数据到达时这个handler 就会被调用。你也可以是设置handler来接受来自事件总线(event bus)的消息,也可以接受HTTP请求和响应,当一个连接关闭时触发,或者一个定时触发,这都是贯彻Vert.x API的普遍模式,使用传统的同步API,线程可能会阻塞API操作,一旦阻塞线程变无法工作了,一个很好的例子就是从socket中读取数据,当代码等待socket上的数据到达时将不会做其他的事情,这意味着如果我们想要支持一个百万级别的并发连接将需要百万的线程,这肯定是无法接受的。当然作为异步编程代码可读性肯定会很差,特别是当你需要处理来自多个event handler的结果时可能会非常难编程,可能会有很多很多的嵌套,处理这种情况我们可是使用mod-rx-vertx模块(这个模块使用了RxJava)以更好的方式来组织你的事件流。

高扩展:Vert.x继承了JVM的优点,可以无缝的扩展可用内核,无需手动的fork多个服务器,它可以很容易的处理服务模块之间的进程通信,做到水平扩展。

高并发:Vert.x有一个简单的异步编程模型(actor模型),非常适用于非阻塞的应用程序,它可以用最小数量的操作系统线程来达到10s、100s甚至百万级别的并发连接(Vert.x内置了和操作系统内核数量相等的线程数来处理verticles,这样你就可以不必使用更多的线程就可以实现一个完美的非阻塞应用)。Vert.x保证一个verticle实例只会被一个线程同时被执行,这对开发者来说好处多多,因为你可以以单线程的方式来编写代码,同时多个单线程的verticle实例会同时执行(取代多线程方式执行多个verticle实例),相互之间通过发送消息来通信。这让Vert.x酷似actor模型,但也有不同之处,比如Verticles比Actors更加粗粒化。

分布式消息:Vert.x包含一个跨越客户端和服务端的分布式的事件总线(event bus),它不仅能够提供点对点的通信,还提供了发布/订阅机制,通过它你的应用组件可以很轻松的进行相互通信,甚至在浏览器端event bus也被集成到了JavaScript中,这样你就可以构建一个real-time实时的web应用(特别是推送类应用web交互)。通过bus传递的事件可以是任意对象,但是如果你使用JAVA对象,你会遇到序列化和载入类的问题,这种情况下使用JSON来作为事件消息是比较靠谱的。需要注意的是事件是短暂的,它们没有存储在任何一种稳定的存储介质上,因此在传输的过程中可能会丢失,这和JMS不同,JMS强调可靠性,而vert.x的事件总线则把重点放在性能上。

便捷健壮:Vert.x具有健壮性,便捷性但是却不简单,最小化它的配置和模块。

模块化:如何让单独的模块可以分开部署?一种是使用OSGi,但是还未普及,另一种是在一台服务器上部署不同的WAR文件,并让它们通过SOAP来通信,这比较复杂也会带来很大的性能负载,而Vert.x包含了一个非常强劲的模块系统(module),以及公共的模块注册机制(集成了maven功能,你可以将你的代码打包成一个module,然后发布到私服上),所以你可以很简单的重复使用,以及和其他人分享Vert.x的模块。Vert.x中的模块拥有分离的classloader,所以可以视为一个真正的单独的组件,使用合适的模块化方法,你可以把大型系统分解为更小的部分,在vert.x中模块化的概念是基于消息的,而消息又提供了更多优势,这样系统便会仅仅依赖消息而不是依赖于调用特地的方法,可以让你达到耕松的耦合

嵌入式开发和热重部署:Vert.x可以嵌入到你现有的Java应用程序中,vert.x的热重部署机制会让你的开发更加简单,但是还没有相关的插件支持

基本概念

Verticle

Vert.x的代码执行包,它可以用JS、Ruby等多语言来编写,在同一个Vert.x实例中可以同时执行多个Verticle,一个应用可能由多个Verticle组成,他们被部署到不同的网络节点上,彼此之间通过在Vert.x的事件总线(event bus)上交换信息来通信。对于具体的verticle可以直接从命令行启动,但是通常会将它打包成modules。

Module

Vert.x应用程序一般是由一到多个modules组成的,Modules包含了多个verticles,这些verticle可能是由不同的语言来编写的。Modules可以被二次封装和重复使用。

Modules可以包装成任意maven或二进制包依赖,可以发布到vert.x模块注册中心。

Vert.x的模块系统支撑了一个由Vert.x管理社区的生态系统。

Vert.x实例

Verticles是运行在一个Vert.x实例上的,一个单独的Vert.x实例是运行在它自己的JVM实例上的。同一时刻可以有多个Verticles运行在同一个Vert.x实例上。

多个Vert.x实例可以同时运行在同一个JVM下,也可以运行在不同的JVM下。这些实例可以以集群的方式来配置,彼此之间通过分布式的event bus来通信。

Event Loops

在内部,一个Vert.x实例管理了一小撮线程,这些线程数量是同服务器上有效的CPU核数相匹配的。我们称这些线程为事件循环(Event Loops),它们将围绕是否有事件需要处理做循环,如果有需要处理的事件将会交给适合的handler来处理。这些被循环监控的事件可能是从一个socket读取数据,一个定时器被触发,或者一个HTTP请求被接受。

当一个标准的verticle实例被部署以后,服务器会为这个实例分配一个事件循环(Event Loop),用来处理相关的事件,后续相关的处理也会使用这个线程来处理。当然,因为有可能在同一时间有成百上千的verticles在运行,所以一个单独的Event Loop将会同一时间分配给多个verticles。

我们也称这为多反应堆模式即mulit-reactor pattern。它类似反应堆模式reactor pattern,但是前者至少有一个event loop。

有一个黄金法则:不要阻塞event loop!

前面说过一个单独的event loop可能会服务于多个verticle实例,所以千万不要在你的verticle中阻塞event loop,如果你阻塞了它就意味着这个event loop无法将事件交付给任何其他的handler处理,那么你的程序将会处于停滞状态。所以一下的阻塞代码请不要出现:

1、Thread.sleep()

2、Object.wait()

3、CountDownLatch.await()或者任何其他来自java.util.concurrent的阻塞操作

4、在一个loop循环中spinning自旋

5、执行一个长时间的计算操作

6、调用一个可能会花费大量时间才完成的阻塞的第三方库操作,比如一个JDBC查询

垂直工件 Worker Verticle

既然不能在一个verticle中编写阻塞代码,那么有替代方案么,这里就要介绍Worker模式的Verticles了

在一个标准的verticle中你永远不能阻塞event loop,但是在我们处理业务时肯定不可避免的遭遇到阻塞场景,或者你真的需要进行一个长时间的计算,典型的例子就是调用一个类似JDBC的标准Java API。

你也可能想直接编写阻塞代码,例如,如果你想要写一个简单的WEB服务,而且你直达你不会有大量的流量,所以不需要扩展很多连接。

对于像上面的这些例子,Vert.x允许你将一个特殊的verticle实例作为一个worker verticle。这个worker verticle不同于标准的verticle,前者不需要分配一个Vert.x event loop线程,它是通过一个叫做worker pool的内部线程池来得到线程来执行的。

和标准的verticle一样,worker verticles也不会被多个线程同时执行,但是也有不同的地方,worcker verticles可以在不同的时间被不同的线程执行,而标准verticle总是会被同一个线程执行。

所以在一个worker verticle中,是允许存在可能会引起阻塞线程的操作的。

通过既支持标准的非阻塞verticle和阻塞worker verticle,Vert.x提供了多样的线程模式以便你能够为你的应用程序使用适当的方式。这比要么阻塞要么非阻塞的单一方式框架要来的实用的多。

需要提醒的是,当你使用worker verticle需要非常小心,比如如果你想要处理高并发的连接,阻塞方式最好少用,它不能做到并发水平扩展。

Shared data

虽然消息传递是相当有用,但对于各种类型的应用程序来说这种方式不一定总是最佳的方式。对于一些案例,通过提供一个共享的数据结构可能是更好的方案,在vert.x便是shared data(map和sets),它允许在相同的Vert.x实例中被不同的verticle实例直接访问(数据共享)。

API

Vert.x提供一系列能直接被verticle调用的API,同时为每个vert.x支持的语言都提供了一份API。

Vert.x 提供2中API,一种是container api 一种则是core api。

Container API包含了一些类似下面的操作:

部署和卸载verticles

部署和卸载modules

获取verticle配置

日志功能

Core API提供下面一些相关的方法:

TCP/SSL 服务器端和客户端

HTTP/HTTPS 服务器端和客户端

WebSockets服务器端和客户端

分布式的事件总线event bus

一次性定时器和周期定时器

字节操作

流量控制

文件系统访问

共享的map和sets(shared data)

访问配置

SockJS

继续阅读