整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

一文带你认识目前最快的Java框架:Vert.x

一文带你认识目前最快的Java框架:Vert.x


果您最近使用Google搜索“最佳网络框架”,您可能会偶然发现Techempower基准测试,其中排名超过300个框架。在那里你可能已经注意到Vert.x是排名最高的之一。

Vert.x是一个多语言Web框架,它支持Java,Kotlin,Scala,Ruby和Javascript支持的语言之间的共同功能。无论语言如何,Vert.x都在Java虚拟机(JVM)上运行。模块化和轻量级,它面向微服务开发。

Techempower基准测试衡量从数据库更新,获取和交付数据的性能。每秒提供的请求越多越好。在这种涉及很少计算的IO场景中,任何非阻塞框架都会有优势。近年来,这种范式几乎与Node.js不可分割,Node.js通过其单线程事件循环来推广它。

与Node类似,Vert.x运行单个事件循环。但Vert.x也利用了JVM。Node运行在单个核心上,而Vert.x维护的线程池大小可以与可用核心数相匹配。凭借更强的并发支持,Vert.x不仅适用于IO,也适用于需要并行计算的CPU繁重流程。

然而,事件循环只是故事的一半。另一半与Vert.x几乎没有关系。

要连接到数据库,客户端需要连接器驱动程序。在Java领域,Sql最常见的驱动程序是JDBC。问题是,这个驱动程序阻塞了。它在套接字级别阻塞。一个线程总会卡在那里,直到它返回一个响应。

毋庸置疑,驱动程序一直是实现完全无阻塞应用程序的瓶颈。幸运的是,在具有多个活动分叉的异步驱动程序上取得了进展(尽管是非官方的),其中包括:

  • https://github.com/jasync-sql/jasync-sql(适用于Postgres和MySql)
  • https://github.com/reactiverse/reactive-pg-client(Postgres)

黄金法则

使用Vert.x非常简单,只需几行代码即可启动http服务器。

val vertx=Vertx.vertx()
  vertx.createHttpServer().requestHandler(req=> {
    
  }).listen(8080)

方法requestHandler是事件循环传递请求事件的地方。由于Vert.x没有意见,处理它是自由的风格。但请记住非阻塞线程的唯一重要规则:不要阻止它。

在使用并发时,我们可以从如今的许多选项中获取,例如Promise,Future,Rx,以及Vert.x自己的惯用方法。但随着应用程序复杂性的增加,单独使用异步功能是不够的。我们还需要轻松协调和链接调用,同时避免回调地狱,以及优雅地传递任何错误。

Scala Future满足上述所有条件,并具有基于函数式编程原理的额外优势。虽然本文不深入探讨Scala Future,但我们可以通过一个简单的应用程序来尝试它。假设该应用程序是一个API服务,用于查找给定其ID的用户:

 val vertx=Vertx.vertx()
  vertx.createHttpServer().requestHandler(req=> {

    req.path() match {
      case p if p contains("/user")=>
        val f=for {
          f1 <- Future { req.getParam("id").get.toInt }
          f2 <- if (f1 < 100) Future.unit else Future.failed(CustomException())
          f3 <- Future { getUserFromDb(f1) }
        } yield f3
        f map (r=> printout(req, r)) recover {case exception=> printout(req, handleException(exception))}

      case _=> printout(req, "Default page")
    }

  })
  .listen(8080)

  def printout(req: HttpServerRequest, msg: String)=req.response().end(msg)

  def handleException(e: Throwable): String={
    e match {
      case t: NoSuchElementException=> "Missing parameter"
      case t: NumberFormatException=> "Parameter not number"
      case t: CustomException=> "Custom exception"
      case t: SQLException=> "Database error" 
      case _=> "Unknown error"
    }
  }

  def getUserFromDb(id: Int)="mock user name"

  case class CustomException() extends Exception("custom exception")

涉及三个操作:检查请求参数,检查id是否有效以及获取数据。我们将把这些操作包装在Future中,并在“for comprehension”结构中协调执行。

  • 第一步是将请求与服务匹配。Scala具有强大的模式匹配功能,我们可以将其用于此目的。在这里,我们拦截任何提及“/ user”并将其传递给我们的服务。
  • 接下来是这项服务的核心,我们的期货按顺序排列。第一个furture 未来f1包装参数检查。我们特别想从get请求中检索id并将其转换为int。(如果返回值是方法中的最后一行,Scala不需要显式返回。)如您所见,此操作可能会抛出异常,因为id可能不是int或甚至不可用,但现在可以。
  • 第二个furture f2检查id的有效性。我们通过使用我们自己的CustomException显式调用Future.failed来阻止任何低于100的id。否则,我们以Future.unit的形式传递一个空的Future作为成功验证。
  • 最后的furture f3将使用f1提供的id检索用户。由于这只是一个示例,我们并没有真正连接到数据库。我们只返回一些模拟字符串。
  • map运行从f3生成用户数据的排列,然后将其打印到响应中。
  • 现在,如果在序列的任何部分发生错误,则传递Throwable进行恢复。在这里,我们可以将其类型与合适的恢复策略相??匹配。回顾一下我们的代码,我们已经预料到了几个潜在的失败,例如缺少id,或者id不是int或者无效会导致特定异常。我们通过向客户端传递错误消息来处理handleException中的每一个。

这种安排不仅提供从开始到结束的异步流程,还提供处理错误的干净方法。由于它是跨处理程序的简化,我们可以专注于重要的事情,如数据库查询。

Verticles,Event Bus和其他陷阱

Vert.x还提供了一个名为verticle的并发模型,类似于Actor系统。Verticle隔离其状态和行为以提供线程安全的环境。与之通信的唯一方法是通过事件总线。

但是,Vert.x事件总线要求其消息为String或JSON。这使得传递任意非POJO对象变得困难。在高性能系统中,处理JSON转换是不可取的,因为它会带来一些计算成本。如果您正在开发IO应用程序,最好不要使用Verticle或事件总线,因为这样的应用程序几乎不需要本地状态。

使用某些Vert.x组件也非常具有挑战性。您可能会发现缺少文档,意外行为甚至无法正常运行。Vert.x可能正在遭受其雄心壮志,因为开发新组件需要移植多种语言。这是一项艰巨的任务。因此,坚持核心将是最好的。

如果您正在开发公共API,那么vertx-core就足够了。如果它是一个Web应用程序,您可以添加vertx-web,它提供http参数处理和JWT / Session身份验证。无论如何,这两个是主导基准的。在使用vertx-web的一些测试中,性能有所下降,但由于它似乎源于优化,因此可能会在后续版本中得到解决。

来源:https://www.jdon.com/51872


pring Framework 1.0 自 2003 年发布以来,主打轻量级、非侵入、AOP(切面编程)、IoC(控制反转)等特性,在段时间内迅速走红,在 Java 社区广受欢迎。2004 - 2007 年,Spring 取得了相当辉煌的成就,不仅将 EJB 2 赶下舞台,而且牢牢确立了 Spring 作为 Java 企业应用开发的主流地位。其后一段时间,SSH 框架组合(Spring + Struts + Hibernate)引领了 Java 企业开发的主流模式,当时对技术比较保守的电信金融等行业,也言必称 Spring,Spring 成为了 Java 框架的事实标准。

再后来,Struts 被 Spring MVC 替代,Hibernate 变成了 JPA 的实现,Spring 却热度不减,一枝独秀。 而 2014 年 Spring Boot 发布,时值微服务概念的普及,Spring Boot 再次成为 Java 微服务的代名词。Spring Boot 基于 Spring 4.0 设计,不仅继承了 Spring 框架原有的优秀特性,而且还通过简化配置来进一步简化了 Spring 应用的整个搭建和开发过程。另外 Spring Boot 通过集成大量的框架使得依赖包的版本冲突、以及引用的不稳定性等问题得到了很好的解决。

如今的 Spring 5.0 版本,引入了全新的响应式编程等概念,在原 Spring 基础上推出了 WebFlux 技术, 实现完全非阻塞,支持 Reactive Streams 背压等特性,能基于 Netty 运行,提供不小的性能提升。其底层依赖 Spring 推出的另外一个全新项目 Project Reactor,原理类似 RxJava 等响应式框架。


Spring Framework 十多年来攻城掠寨,在取得巨大成功的同时,也变得越来越复杂,体积变大,启动变慢,当初的“轻量”变得越来越遥远。IoC、AOP 等概念让新手迷惑,JavaBean、XML 和 @Controller、@Service、@Repository 等各种注解让人们误以为这就是 Java 开发的全部。

时间来到了 2020 年,随着 Scala、Kotlin、Groovy 等 JVM 语言的繁荣,以及函数式编程的流行,一款名为 Vert.x 的框架正异军突起,拥有轻量、异步、可伸缩、高并发等特性,旨在为 JVM 提供一个 Node.js 的替代方案。下面就介绍 Vert.x 框架的一些特点,看看它能不能成为 Spring 框架的有力竞争对手。


背靠 Red Hat,并得到 Eclipse 基金会支持

Vert.x 由 Tim Fox 于 2011 年创立,最初命名为 Node.x(受 Nodejs 启发),当时他受雇于 VMware 旗下 SpringSource。后来 Tim 跳槽去了 RedHat / JBoss,领导 JBoss HornetQ 等项目开发。

2012 年末,在 Tim 离开工作岗位后,VMware 将 Tim 告上法庭,要求控制 Vert.x 社区的 商标、域名、博客和 Github 账户。在大量讨论和妥协之后,2013 年 1 月,VMware 被说服将 Vert.x 社区移交给中立的法人实体 Eclipse Foundation,这符合 Vert.x 社区的最大利益。

2016 年初,Tim Fox 卸任 Vert.x 项目的负责人,另一位 Red Hat 员工、Vert.x 核心开发者 Julien Viet 取代了他的位置。目前 Vert.x 的核心开发者主要来自 Red Hat。

官方多语言支持

Vert.x 支持 Java、JavaScript、Groovy、Ruby、Ceylon、Scala 和 Kotlin 语言,并为每种语言提供了方便的、符合该语言习惯的 API。Vert.x 并没有指定选择优先级,您可以选择其中任一门您熟悉的语言。当然如果需要协程支持,最好的选择是 Kotlin。

官方多框架支持

类似 Spring 全家桶,Vertx 对各种常用技术有很好的集成,比如各种 db 的连接库 vertx-mysql-client、vertx-redis-client、vertx-mongo-client,对 Kafka、Consul 的集成 vertx-kafka-client、vertx-consul-client,对 RxJava 支持的 vertx-rx-java,用于单元测试的 vertx-unit、vertx-junit,涉及了 Java 开发的方方面面。

基于 Netty,事件驱动、非阻塞、高性能

Vert.x 最大的特点就在于异步(基于 Netty),通过事件循环(EventLoop 线程)来调起存储在异步任务队列(CallBackQueue)中的任务(Verticle)。在 EventLoop 线程里面的代码,不能有阻塞操作,比如使用阻塞 IO、加锁、长时间占用 CPU 等,Vert.x 提供了单独的 Worker 线程池来运行阻塞的代码,比如传统的 JDBC 操作,这种模式大大降低了传统阻塞模型中线程对于操作系统的开销。

而通过 EventBus 则可以非常简单的实现分布式消息,进而为分布式系统调用和微服务奠定基础。通过不同的模块组合, Vert.x 可以实现 TCP、UDP、HTTP、WebSocket、MQ 各种不同功能,创建功能强大的应用程序。

体积小巧

十多年前讨论何为 Java 轻量级框架,有一个观点是认为该框架的 jar 包需要小于 1M,当年的 Spring 1.0 的确如此,所有内容打包在一起为 935K。然而现在光是 spring-core 就 1.4M, 加上 spring-contex、spring-aop、spring-beans、spring-mvc,以及 spring-boot、spring-data、spring-orm、spring-security,配上各种实现如 Hibernate、Redis、Mail 等,轻松过 50M 甚至 100M。Spring 不再是一个小而美的框架,而将交由 Vertx、Ktor 等新型框架接棒。

Vert.x 是用于创建轻量化、高性能的微服务的理想选择。

启动快、支持热部署

由于体积小巧,不依赖 Tomcat、Jetty 等传统 Web 容器,Vertx 启动非常快。Vert.x 自带热部署功能,不需要任何设置。相较于 Spring 需要引入 spring-loaded 和 spring-boot-devtools 并启用相关设置,方便许多。

支持 GrpahQL

Vertx 官方库 vertx-web-graphql 提供了对 GraphQL 技术的支持,依赖 graphql-java 和 reactive-streams 实现,开发非常方便。GraphQL 被认为是接棒 Restful 的下一代技术,已被许多的公司( Facebook、Twitter、Github 等)大规模用于生产环境,相信其未来还有很大的发展前景。

支持 MQTT

官方模块 vertx-mqtt 提供了对 MQTT 的支持。

简单、容易上手

虽然 Vert.x 提供了众多创新概念和特性,但暴露给开发者的接口屏蔽了复杂的实现,异常简单。类似于 Node.js,Vert.x 可以快速上手,相比 Akka 等框架简单许多,堪称生产力工具。

: 创新性地使用最新的Vert.x框架,利用其异步、非阻塞、实时性、高并发的工作模式,对现有的工业过程监控系统进行全面改造,极大提升了系统的响应速度,实时性得到显著提高,完全满足大量客户端并发的实时请求。

0 引言

工业生产监控系统的Web化[1]已成为标准,客户端只使用浏览器即可实现对监控数据的实时显示,不需要安装各种监控组件,简化了监控系统维护。实现监控数据的实时传输和显示技术也在不断地出现,从传统HTTP请求/响应模式,到AJAX的Comet及HTML5的WebSocket,采用数据推送技术,使得Web监控系统的实时性得到极大提高。然而监控服务器在面对大量客户连接的并发请求时,实时性难以满足。无论JavaEE,还是NET都如此,它们的多线程工作模式是根源所在。为解决此问题,Vert.x框架[2-3]应运而生,它采用全新工作模式,特别适合开发实时性要求极高的系统。

Vert.x是用于下一代异步、可伸缩、并发应用的框架,轻量级的高性能JVM应用平台,适合开发各种移动及企业应用。它彻底解决了业界遭遇C10K问题,即当并发连接超过一万以上时,传统技术会引发暂停。以Tomcat为例,它在超过100个并发长请求就堵塞,而Vert.x可支持超10万个并发请求。

本文采用Vert.x对现有的供热监控系统进行改造,对监控服务器端和客户端进行重构。在服务器端使用Vert.x的Web服务器取代现有Tomcat7,采用Vert.x TCP读取西门子PLC300的监控数据。用户端采用Vert.x的Event Bus Bridge技术,实时接收服务器端监控数据,改造后的监控系统的性能和响应速度比原有系统有显著的提高。

1 Vert.x框架概述

Vert.x核心采用与Node.js相同的事件驱动的异步工作模式,使用单线程的事件循环机制实现高并发的请求处理,而不像传统的服务器采用多线程的模式。

Vert.x的核心组件是Verticle,运行在Vert.x实例中。Vert.x启动后,根据服务器CPU的内核数,自动创建对应的Vert.x实例,并发运行Verticle。

Vert.x采用事件驱动的异步编程模式,通过触发事件以及注册事件处理器完成所有编程任务。Verticle之间不能直接调用,只能发送和接收事件实现协作。

Vert.x的核心是事件总线,Verticle在事件总线发送和接收事件。事件总线是分布式的,能连接服务器和客户端。事件总线支持点对点和发布-订阅模式的事件传输,监控系统中服务器向所有连接的客户端发送监控数据就使用发布订阅模式,使得所有客户端浏览器都能实时接收到监控数据。

2 实时监控系统设计与实现

大连柳树供热公司监控系统现场采用西门子PLC S7-300[4],通过屏蔽双绞线连接到中心机房的核心交换机上,中心监控主机CPU采用志强8核服务器,可并发运行8个Vert.x实例,能支持十几万个并发请求。页面采用最新的Bootstrap模版技术[5],自动适应不同尺寸的屏幕显示,包括手机、平板等。

2.1 读取PLC监控数据TCP编程

西门子S7-300采用TCP FETCH WRITE通信方式[6],该模式下通过TCP协议的Socket,主机可与PLC进行数据交换。

Vert.x内置TCP Client方法,如下是TCP客户端读取PLC数据的代码:

var vertx=require(′vertx′);//获得Vert.x运行实例

var eb=require(′vertx/event_bus′)//获得Event Bus对象

var client=vertx.createNetClient;//创建TCP客户端

client.reconnectAttempts(1000);//设置连接尝试次数

client.reconnectInterval(500);//设置尝试间隔时间

//连接PLC Socket端口,并定义回调函数

client.connect(config.port,config.ip,function(err,socket){//定义接收到PLC数据的事件处理器

socket.dataHandler(function(buffer){

var data=JSON.parse(buffer);

//将接收的数据发布到Evnet Bus上

eb.publish("rtdata.in.receive",{info:data},function(result){});

//使用定时器,每间隔0.5 s发送请求数据指令到PLC

var timer=vertx.setPeriodic(500,function(timerID){sock.write("datain");});

}});

客户端定时发送数据指令,PLC数据到达后,Socket上的事件监听器工作,从回调函数中取得监控数据,并转换为JSON格式,使用总线方法publish发布事件。总线上监听的Web客户端都能同步接收监控数据。Vert.x采用推模式实现数据传输,由Vert.x服务器主动发送数据,不需客户端请求,节省了网络带宽,提高了传输速度,满足了监控系统实时性。监控系统的总体架构如图1所示。

在Vert.x服务器中,可启动多个TCP客户端Verticle,实现多路监测数据的并发读取,如下代码展示主服务器依次启动Http Web Server和TCP Client监控Verticle等实例。

//获得Vert.x实例容器

var container=require("vertx/container");

//启动Web服务器

container.deployVerticle("HttpServer.js");

//启动PLC TCP客户端

container.deployVerticle("TCPClient.js",{port:2201,ip:192.168.1.101});

2.2 监控Web服务器的编程

系统采用Vert.x的服务器模块web-server~2.0,实现功能强大的Web服务器,并使用异步模式接收客户端浏览器的HTTP请求,支持客户高并发的HTTP连接请求,示意代码如下。

var container=require("vertx/container");

container.deployModule("io.vertx~mod-web-server~2.0.0-final",{port:80,host:"localhost",

bridge:true,

inbound_permitted:[

{address:′rtdata.in.receive′},

{address:′rtdata.out.receive′}

]);

Vert.x通过deployModule载入Web模块,Web模块自动将目录/web作为站点发布目录,在/web目录中存储站点的页面文件。

代码中bridge:true表示将服务器端的事件总线延伸到Web客户端,实现服务器和客户端的数据传输。每个Verticle都可以在Event Bus注册事件处理器,以此实现数据的接收和发送。

2.3 监控客户端编程

客户端使用普通的HTML即可,不需要动态页面。为实现与Vert.x服务器的Event Bus通信,客户端页面需要引入Vert.x的Event Bus Bridge的库文件vertxbus-2.1.js。

监控数据显示使用<div>,使用Bootstrap框架布局,将<div>悬浮在图片指定位置。监控客户端页面的数据接收和显示代码如下:

$(document).ready(function{

var eb=new vertx.EventBus(′localhost/eventbus′);

eb.onopen=function{

eb.registerHandler("rtdata.in.receive",function(args){var data=args.data;

$("#rt1010").html(data);});

};});

代码中关键是取得Vert.x的Event Bus对象,通过事件总线提供的vertx.EventBus,使用Javascript创建一个实例即可。如果与服务端的Event Bus连接成功,则eb.onopen回调函数工作。在此方法内,通过Event Bus的registerHandler对指定的地址进行监听,当有此地址的事件event到达时,定义的回调函数function(args)开始运行,参数args为事件中包含的JSON数据,解析出JSON数据,使用jQuery的函数html将数据显示在指定的 <div>元素内,实现监控数据的实时显示。实时监控系统监控界面如图2所示。

3 结论

Vert.x具有的实时通信、全新的异步响应式工作模式和分布式Event Bus等特性,使其必将在实时系统开发中得到广泛应用。与Node.js相比,Vert.x以其性能压倒性的绝对优势,必将推动实时Web的飞速发展,进而引起Web领域颠覆性的革命,彻底淘汰以AJAX为主的Web2.0,引领新的Web发展趋势。

参考文献

[1] 李玉珠,吴敏,徐福仓.基于Web的炼焦实时监视系统设计与实现[J].自动化与仪表,2009(4):1-4.

[2] PARVIAINEN T.Real-time Web application development using Vert.x 2.0[M]. Birmingham-Mumbai: Packt Publishing,2013.

[3] Vert.x[EB/OL]. http://vertx.io/.

[4] 潜立标,杨马英,俞立,等.基于Web和S72300 PLC的远程控制实验室系统[J].浙江工业大学学报,2007(2):73-77.

[5] 陈群.基于ASP.NET AJAX新型Web Scada的设计与实现[J].工业控制计算机,2009(6):42-44.

[6] 赵佳宝,付羽.基于SVG的实时监控流程图实现技术[J].工业控制计算机,2009(6):10-12.