果您最近使用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。問題是,這個驅動程序阻塞了。它在套接字級別阻塞。一個線程總會卡在那里,直到它返回一個響應。
毋庸置疑,驅動程序一直是實現完全無阻塞應用程序的瓶頸。幸運的是,在具有多個活動分叉的異步驅動程序上取得了進展(盡管是非官方的),其中包括:
黃金法則
使用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”結構中協調執行。
這種安排不僅提供從開始到結束的異步流程,還提供處理錯誤的干凈方法。由于它是跨處理程序的簡化,我們可以專注于重要的事情,如數據庫查詢。
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 框架的有力競爭對手。
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 開發的方方面面。
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 并啟用相關設置,方便許多。
Vertx 官方庫 vertx-web-graphql 提供了對 GraphQL 技術的支持,依賴 graphql-java 和 reactive-streams 實現,開發非常方便。GraphQL 被認為是接棒 Restful 的下一代技術,已被許多的公司( Facebook、Twitter、Github 等)大規模用于生產環境,相信其未來還有很大的發展前景。
官方模塊 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.
*請認真填寫需求信息,我們會在24小時內與您取得聯系。