Vertx簡介


        今天看了一篇很不錯的關於Vertx的簡介,轉載下。

        原文鏈接:http://www.csdn.net/article/2015-12-21/2826533?utm_source=tuicool&utm_medium=referral

         

Vert.x的由來

Vert.x誕生於2011年,當時叫node.x,不過后來因為某些原因改名位Vert.x。經過三年多的發展,現在已經到了3.2版本,社區也越來越活躍,在最新的官網Vertx.io上,作者用一句話介紹了它,JVM上的Reative開發套件。Vert.x目前是見過最功能最強大,第三方庫依賴最少的Java框架,它只依賴Netty4以及Jacskon,另外如果你需要建立分布式的Vert.x則再依賴HazelCast這個分布式框架,注意Vert.x3必須基於Java8。由於基於JVM,所以Vert.x可以用其他語言來實現你的業務。默認官方維護的語言是Groovy,JavaScript以及 JRuby。

Vert.x是一個異步無阻塞的網絡框架,其參照物是node.js。基本上node.js能干的事情,Vert.x都能干。Vert.x利用Netty4的EventLoop來做單線程的事件循環,所以跑在Vert.x上的業務不能做CPU密集型的運算,這樣會導致整個線程被阻塞。

圖1是一個簡單的通過Vert.x起HTTP服務的例子(Java實現)。你可以從官方找到其他語言實現。


圖1 Vert.x實現HTTP服務

剛才上面提到了Vert.x的分布式,Vert.x與node.js有一個很大不同點,在於Vert.x支持分布式,與多核利用。通過Hazelcast管理各個Vert.x節點的信息,然后通過EventBus在節點之間互相發消息,於此同時Vert.x還能支持應用的高可用,只需簡單的在啟動時加參數-ha即可。具體的可以去官網查看一下用法。下面是Vert.x提供的核心API。

HTTP/HTTPS Server/Client

Websocket SockJS

TCP/SSL Server/Client

UDP / DNS

Files / Timer

Json / Buffer / Flow Control

EventBus ( 集群 )

Distribution (Lock, Map, Counter)

Vert.x的執行單元叫verticle。即程序的入口,每個語言可能實現的方式不一樣,比如Java需要繼承一個AbstractVerticle抽象類,而javascript則直接require(“vertx”)就可以了。

verticle分兩種,一種是基於EventLoop的適合I/O密集型的,還有一種是適合CPU密集型的worker verticle。而verticle之間相互通信只能通過Eventbus,可以支持point to point 的通信,也可以支持publish & subscribe通信方式。

我們重點說一下基於EventLoop的verticle。這個本質上是跟node.js一樣的。下面的圖其實就是node.js的翻版。


圖2 node.js的翻版

所有業務邏輯其實都會跑在Netty里的EventLoop上,而EventLoop通過循環事件隊列來執行所有的業務邏輯,這樣可以把一些I/O操作頻繁的事件及時從CPU上剝離開來,最后通過注冊一個回調Handler來處理所有的事件回調。

另外一種worker verticle。主要是用來處理同步處理的。比如第三方框架沒有異步接口,最典型就是JDBC。所以可以通過worker verticle來退化到傳統的基於多線程模型的實現。這也是匹配一些原項目的手段。

圖3是Vert.x的內部整體架構


圖3 Vert.x的內部整體架構

大家可以看到,我們的業務邏輯其實都是基於verticle來實現的,然后Vert.x框架會將你的verticle綁定到相關的線程模型上,這里verticle1,verticle2是I/O密集型項目,所有的邏輯都會跑在NIO Worker上。而Verticle3會有一些同步的耗時的請求,則會被綁定到Worker線程模型上。另外兩個Vert.x節點則通過EventBus互相通信,而EventBus通過HazelCast來獲取整個集群里的節點信息。注意這里每一個verticle其實都是一個線程(啟動的時候指定實例數目參數即可),這樣可以充分的利用多核。而node.js其實只能通過Cluster來提升多核利用。

Vert.x的部署場景及開發痛點

圖4是一個典型的Vert.x部署場景。


圖4 Vert.x部署場景

我們會把邏輯拆成小的verticle。這里你可以把這些小的verticle看成是微服務,然后水平擴展這些服務,同時也可以把自己的業務按CPU密集與I/O密集型拆分。服務與服務之間可以通過EventBus互相調用,另外Vert.x的EventBus調用目標verticle的時候會按RoundRobin算法來做balance。

我們來看看Vert.x開發的痛點,這其實是所有異步開發都會遇到的痛點,就是Callback Hell。因為你所有的業務邏輯都會被拆成一個個不連貫的代碼塊,也就是說一個業務邏輯如果涉及到I/O操作你必須要通過回調接口來繼續完成,這樣就丟失了局部變量,而且異常捕獲也會變得非常麻煩。

圖5是一個Callback Hell的例子


圖5 Callback Hell代碼示例

這里代碼的含義是通過EventBus給service-address1發送一個消息,然后等待返回后再把結果發送給service-address2,再等待service-address2的返回結果發送給service-address3。這里形成了調用鏈,即下一步的行為依賴上一步的返回結果。這個在前端用Ajax的同學肯定很熟悉。

那解決辦法呢,node.js里是用promise,而Vert.x可以使用Java8自帶的CompletableFuture來實現同樣的效果。圖6就是用CompletableFuture改寫的例子


圖6 Callback Hell代碼示例

大家可以發現代碼變得更扁平了,沒有那么多的嵌套,然后通過一些介詞比如,then, when等來組合各個異步的業務邏輯,最后在一個地方統一的捕獲異常。

這里大量用了Java8的新功能,比如Lambda表達式,如果覺得奇怪的同學,建議先去熟悉一下Java8的Lambda表達式。


圖7 CompletableFuture代碼示例

那有沒有更好的實現方式了呢,能不能變成同步方式呢。這里Vert.x提供了一個庫vertx-sync可以實現Fiber。通過Fiber來防止線程Block,從而將異步代碼完全的變成同步代碼。

這里代碼瞬間變得非常清晰,完全是同步的樣式。vertx-sync其實是依賴了quasar這個Java庫,它通過修改Java字節碼來實現相關的邏輯,這里其實是在EventLoop線程里又開辟了一個線程池,所有的在EventLoop里的同步的方法會被這個線程池接管,處理完后會再返回給EventLoop線程。這樣可以避免EventLoop線程被阻塞。


圖8 vertx-sync代碼示例

但是個人不推薦在生產環境使用這個庫,因為它畢竟不是語言級別的支持Fiber。需要JVM啟動的時候通過javaAgent來加載相關的quasar庫。

這里還有一個庫,在今天特別的火——RxJava。這個其實是Reactive的Java實現,官方也提供了相關的支持,但是Reactive比較復雜,除非的業務涉及很多的流式操作,否則不建議你使用。下面是官方的一個例子。

簡單說明一下,這里定義了一個EventBus,用來接受發給heat-sensor的消息,然后每隔1秒鍾對累積的消息進行一次批處理,這里通過Java8的Stream接口做了一次求平均值,最后將結果通過EventBus發給news-feed這個verticle做進一步的處理。

這里大家可以發現RxJava可以做更多的事情,前提是大家要對FRP編程思想能夠接受。

Vert.x3常用工具

最后在提一下幾個Vert.x3的一些小工具。

一個是metrics。這個可以用來統計整個Vert.x內部的一些指標信息,比如HTTP請求數,TCP接受或者發送的流量等等,具體可以看官方文檔,通過這個接口我們可以實時的統計Vert.x內部性能信息。

另外Vert.x提供了專門針對異步代碼的單元測試框架vertx-test-unit。

通過redeploy這個參數可以動態的熱部署整個verticle,這個對開發調試時非常有用。

最重要的是Vert.x3內置了EventLoopChecker這個動態監測所有EventLoop線程的工具,默認EventLoop被阻塞了2秒鍾的時候會觸發報警,如果持續阻塞則會直接打印那一塊的異常棧到日志里,非常方便開發者來檢查自己的異步代碼。

Vert.x目前在國內還不是很火,但是在國外已經有很多企業在使用了,比較注明的比如英孚教育、Hulu、以及做JVM監控的一家公司jClarity等。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM