摘要:輕量級(jí),部署簡(jiǎn)單。此外,本文也不是入門文檔,而是為了預(yù)防陷坑而給出的指導(dǎo)意見(jiàn),故在閱讀本文之前還請(qǐng)先仔細(xì)閱讀的文檔。可視作的一個(gè)最小部署和運(yùn)行單元,簡(jiǎn)單的說(shuō),可類比為。,主,負(fù)責(zé)部署程序中其他的。嚴(yán)格來(lái)講,之后,上述第一點(diǎn)并不完全正確。
一直以來(lái)早有將這些年用Vert.x的經(jīng)驗(yàn)整理一下的想法,奈何天生不是勤快人,直到最近扶墻老師問(wèn)起,遂成此文。
選擇理由現(xiàn)在想想,我們應(yīng)該算是國(guó)內(nèi)用Vert.x的最早一批人,版本大概是1.2.x吧,當(dāng)時(shí)Vert.x內(nèi)置了一個(gè)比較坑爹的模塊系統(tǒng),看似不錯(cuò),但其實(shí)很坑爹。但即使這樣,我們當(dāng)時(shí)還是在技術(shù)選型上采用了它。理由大致如下:
性能,它的底層是netty,并且編程模型跟node.js如出一轍,可算得上是“node on JVM”。同時(shí),性能評(píng)測(cè)上比node還高出不少。
簡(jiǎn)單,它比netty更簡(jiǎn)單,而且可以輕易的支持cluster。
Actor模型,Verticle + Eventbus,降低了并發(fā)編程的難度。
WebSocket,恰好當(dāng)時(shí)的項(xiàng)目需要這樣的方案,服務(wù)器主動(dòng)向前臺(tái)推。并且Vert.x提供的EventbusBridge讓前端js的組織更好。
支持Groovy,用過(guò)的都知道,這里就不展開(kāi)了。
輕量級(jí),部署簡(jiǎn)單。
于是乎,它順利成章地成為了我們當(dāng)時(shí)系統(tǒng)接入層的中流砥柱,在實(shí)踐中也確實(shí)發(fā)揮了很好的作用。
踩坑指南鑒于Vert.x當(dāng)前的版本是3.3.3,因此本文的內(nèi)容也主要針對(duì)這個(gè)版本而言,一些我們遇到并且已經(jīng)修復(fù)的bug,也就不會(huì)也沒(méi)有必要在此啰嗦了。
此外,本文也不是入門文檔,而是為了預(yù)防陷坑而給出的指導(dǎo)意見(jiàn),故在閱讀本文之前還請(qǐng)先仔細(xì)閱讀Vert.x的文檔。
編程語(yǔ)言雖然Vert.x的一大亮點(diǎn)號(hào)稱是支持“多語(yǔ)言”,即同一個(gè)工程內(nèi)可以同時(shí)用Java、Groovy、Javascript等不同語(yǔ)言編寫(xiě)Verticle,但我還是建議采用Java為主,最多輔以Groovy。原因是:我發(fā)現(xiàn)很多新出的Vert.x模塊還是對(duì)Java支持最好,對(duì)于其他的則就相當(dāng)一般了,起碼不會(huì)讓你感覺(jué)特意針對(duì)這個(gè)語(yǔ)言而開(kāi)發(fā)的。加上本來(lái)Java 8之后支持lambda,Java程序員的苦逼生活其實(shí)已經(jīng)改善不少。
在dgate中,我主要采用Java + Groovy的方式,兩者分工也很明確:前者用于數(shù)據(jù)處理,后者則用于DSL和數(shù)據(jù)類。
此時(shí),由于混用了兩者,并且可能會(huì)出現(xiàn)Groovy類要用到程序中Java類的情況,那么就要用到j(luò)oint compile。在build.gradle中需要配置如下:
sourceSets.main.java.srcDirs = [] sourceSets.main.groovy.srcDirs += ["src/main/java"]
即,將Java類也交由Groovy編譯器來(lái)編譯。
工程結(jié)構(gòu)雖然Vert.x可以內(nèi)嵌到其他框架中,但在實(shí)際項(xiàng)目上我還是偏愛(ài)多帶帶部署,項(xiàng)目的構(gòu)建方式則為:gradle + fatjar。具體例子,可以參見(jiàn)這個(gè)build.gradle文件。
我在Vert.x郵件組中經(jīng)常看到有新人問(wèn)關(guān)于Vert.x的組織方式,其實(shí)這是沒(méi)有理解Vert.x的本質(zhì):Verticle。Verticle可視作Vert.x的一個(gè)最小部署和運(yùn)行單元,簡(jiǎn)單的說(shuō),可類比為Servlet。因此,整個(gè)應(yīng)用可以這樣來(lái)劃分:
Launcher,程序入口,負(fù)責(zé)調(diào)起Vert.x的環(huán)境。
MainVerticle,主Verticle,負(fù)責(zé)部署程序中其他的Verticle。
Verticle,程序處理邏輯,調(diào)用其他POJO/POGO。
POJO/POGO,普通類,供Verticle使用。
前兩者負(fù)責(zé)初始化,Verticle則類似Servlet一樣等待被觸發(fā)(來(lái)自TCP/Eventbus/HTTP的Request),在實(shí)際處理時(shí)會(huì)調(diào)用到其他類。
這也就是為何在上面的build.gradle中有這樣關(guān)鍵的兩行的原因:
manifest { attributes "Main-Class": "……" attributes "Main-Verticle": "……" }Logging
Vert.x默認(rèn)支持JUL,對(duì)于其他Logging框架也有支持。但我嫌每次運(yùn)行要敲那么多命令很煩,那么可以在Launcher中強(qiáng)制設(shè)置環(huán)境變量:
System.setProperty("vertx.logger-delegate-factory-class-name", "io.vertx.core.logging.SLF4JLogDelegateFactory");
可參見(jiàn)dgate的Launcher代碼。
部署Verticle跟Servlet類似,多個(gè)Verticle之間也會(huì)有依賴關(guān)系,存在先后部署的需要。
對(duì)于單個(gè)Verticle之間的依賴,如A依賴B,很簡(jiǎn)單,利用deployVerticle的回調(diào)就很好解決。因?yàn)榇a簡(jiǎn)單,這里就不再多帶帶列出,還是那句話,看文檔。
對(duì)于依賴多個(gè)Verticle,如A依賴B和C,則需要有點(diǎn)技巧了:
第一也是最差的方式,就是采用callback hell方式,層層遞進(jìn)。
第二種方法采用rxJava,利用Observable的運(yùn)算來(lái)完成。
第三種方式,利用Java的Atom對(duì)象,示例代碼(Groovy)如下:
private void deployVerties(List
看到Atom對(duì)象,你是否覺(jué)得也可以采用CountDownLatch對(duì)象?很不幸,不行。我當(dāng)時(shí)做過(guò)嘗試,整個(gè)代碼立馬被Block住,直到我按了Ctrl-C。原因在于:Block住了EventLoop。
至于deployVerticle(),它可以接受字符串和類實(shí)例。當(dāng)使用字符串時(shí),若是非Java類,如Groovy,需要采用這樣的格式:"語(yǔ)言前綴:類全限定名"。如:
"groovy:hawkeyes.rtds.processor.MailMan"
此外,部署的Verticle實(shí)例并非越多越好,還跟CPU的核數(shù)相關(guān)。
Block操作Vert.x應(yīng)用最忌諱Blocking操作,對(duì)此有多種處理:
采用Worker Verticle
使用executeBlocking函數(shù)
凡是涉及IO的操作,都請(qǐng)考慮一下。
EventBusEventBus相當(dāng)于Vert.x應(yīng)用的神經(jīng)系統(tǒng),但有幾點(diǎn)需要注意:
若想給部署在另一臺(tái)機(jī)器上的Verticle發(fā)消息,這兩個(gè)Verticle必需是在一個(gè)集群中。
攔截EventBus的消息需要注意一下這個(gè)小地方。
嚴(yán)格來(lái)講,3.2之后,上述第一點(diǎn)并不完全正確。這兩個(gè)Verticle之間可以采用TCP EventBusBridge來(lái)進(jìn)行通信,具體參見(jiàn)這篇文章。
Cluster和內(nèi)存計(jì)算Cluster是當(dāng)時(shí)我選擇Vert.x的一個(gè)重要考量,而且將Vert.x應(yīng)用多帶帶打成fatjar還有一個(gè)附帶好處就是Vert.x的cli都可以直接使用,其中就包括cluster命令。
Vert.x的集群建立在Hazelcast之上,除了集群調(diào)度,它本身還能做內(nèi)存存儲(chǔ),即具備了Redis的主要功能。并且查詢語(yǔ)法也比Redis(2.x)的要靈活,支持類SQL語(yǔ)法。更重要的是,其ReadThrough特性讓人欲罷不能,簡(jiǎn)化了編程。當(dāng)然,還包括其他如分布式鎖、隊(duì)列、任務(wù)等等。
所謂ReadThrough,即“若內(nèi)存中沒(méi)有,則查詢將下傳到下一級(jí)(通常是DB)”。Hazelcast的ReadThrough可通過(guò)實(shí)現(xiàn)MapLoader接口來(lái)實(shí)現(xiàn)。這個(gè)例子很簡(jiǎn)單,故可查看Hazelcast的文檔了解。這里重點(diǎn)講一下如何在Vert.x中去配置,因?yàn)閂ert.x沒(méi)有對(duì)此提供直接支持。
首先,cluster.xml即為一個(gè)標(biāo)準(zhǔn)的Hazelcast配置文件,故可在此配置相應(yīng)的MapLoader即可:
在從未給集群Map賦過(guò)值且第一次運(yùn)行下列代碼時(shí),注意兩個(gè)名字要相同,則觸發(fā)ReadThrough:
vertx.sharedData().getClusterWideMap("map_name") {……}
如果想在Vert.x中獲得Hazelcast實(shí)例,則可以直接使用下面代碼:
Setinstances = Hazelcast.getAllHazelcastInstances() hz = instances.first()
這樣便可利用Hazelcast的其他功能。在3.3.3之后,Vert.x集群支持Ignite,它是比Hazelcast更強(qiáng)大的內(nèi)存計(jì)算工具。而且,在Vert.x 3.4-beta1中已經(jīng)不再是技術(shù)預(yù)覽版,日后我肯定會(huì)全面擁抱它。
Ignite/Hazelcast不像Redis那樣曝光率那么高,但鑒于其本身都是老牌內(nèi)存計(jì)算軟件,且在開(kāi)源之前都在高強(qiáng)度生產(chǎn)環(huán)境(沒(méi)記錯(cuò)的話是銀行系統(tǒng))實(shí)戰(zhàn)演練過(guò),同時(shí)對(duì)比一下兩者之間的功能列表,你會(huì)發(fā)現(xiàn)這些工具其實(shí)更強(qiáng)大,尤其是Ignite。它們的文檔都不錯(cuò),值得一看。
Handler最后說(shuō)一說(shuō)Handler中需要注意的地方,它非常適合寫(xiě)Restful API。
之前用Vert.x寫(xiě)接入層代碼,主要集中在Core、Groovy和Shell部分。這次寫(xiě)dgate,算是扎扎實(shí)實(shí)用了一下Web部分。至于歷史,我就不詳細(xì)說(shuō)了,總之一句話:哥是看著它長(zhǎng)大的,;)。
Handler其實(shí)很簡(jiǎn)單,只需要注意幾點(diǎn):
Vert.x request Handler除了處理功能,還兼具Filter的功能。若處理完畢,請(qǐng)求不想讓下一個(gè)request handler處理,則直接返回即可;否則,需要調(diào)用:routingContext.next()。
對(duì)于同一個(gè)URL可以注冊(cè)多個(gè)handler,以調(diào)用順序?yàn)闇?zhǔn)。故,想先處理的,如驗(yàn)證,往前放。
至于其他,沒(méi)啥可說(shuō)的,都很簡(jiǎn)單。
寫(xiě)在最后最后,來(lái)句雞湯:遇坑不可怕,還得勇于嘗試方能有所收獲,希望對(duì)各位有幫助!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/66686.html
摘要:主要是避免引入太多的復(fù)雜性,并且出于靈活部署的需要。以應(yīng)用為例,由于實(shí)際上是在上執(zhí)行,若它被阻塞,即導(dǎo)致后續(xù)請(qǐng)求全部無(wú)法得到處理。因此,最合適的做法就是對(duì)于簡(jiǎn)單業(yè)務(wù),采用異步庫(kù)。本系列其他文章入坑須知入坑須知入坑須知 最開(kāi)始覺(jué)得這個(gè)系列也就最多3篇了不起了(因?yàn)槭虏贿^(guò)三嘛),沒(méi)曾想居然迎來(lái)了第四篇! Kotlin 由于最近決定投身到區(qū)塊鏈的學(xué)習(xí)當(dāng)中的緣故,出于更好的理解它的基本概念,自...
摘要:對(duì)于集成測(cè)試,直接模擬實(shí)際的環(huán)境,再加上合適的,目前看來(lái)也還不錯(cuò)。這里給出兩個(gè)例子集成測(cè)試單元測(cè)試都是基于寫(xiě)的,各位可以體驗(yàn)其酸爽度。好啦,本期內(nèi)容就此結(jié)束,請(qǐng)保持關(guān)注,期待下期繼續(xù)本系列其他文章入坑須知入坑須知 隨著Vert.x進(jìn)化到3.5.0,本系列也迎來(lái)了新篇章。 CORS的新變化 對(duì)于CORS,搞Web開(kāi)發(fā)(不論你是前端,還是后端)的同志應(yīng)該不陌生,尤其是如今微服務(wù)盛行的時(shí)代,...
摘要:這一點(diǎn)其實(shí)是非常不妥的,有潛在的安全問(wèn)題。這次,在項(xiàng)目中終于采用了以它為基礎(chǔ)的集群方案。相反,使用一個(gè)周期,但針對(duì)每個(gè)生成一個(gè)一次性的,模擬隨機(jī)發(fā)送。同時(shí),要記得用完之后立即釋放。 當(dāng)初創(chuàng)建簡(jiǎn)書(shū)賬號(hào)的時(shí)候曾立下宏愿,希望保持周更,無(wú)奈現(xiàn)實(shí)殘酷,整個(gè)5月都處于忙忙碌碌的狀態(tài),居然令這個(gè)本來(lái)并不算太宏偉的目標(biāo)難以為繼,最終導(dǎo)致5月份交了白卷!【好吧,我承認(rèn),是我意志不夠堅(jiān)定,太懶了,;)】...
摘要:之前寫(xiě)了一篇沒(méi)有加入的的小博文。一拆分結(jié)構(gòu)根據(jù)自己的習(xí)慣和固定套路,拆分目錄結(jié)構(gòu)和組件結(jié)構(gòu)。把的導(dǎo)航組件集中放在純粹是個(gè)人習(xí)慣。二代碼實(shí)現(xiàn)入口文件是用來(lái)做的數(shù)據(jù)持久化。添加事項(xiàng)后要通知其他組件更新數(shù)據(jù)。 讀前須知 這個(gè)項(xiàng)目是第一次使用Redux的實(shí)例,并不具有專業(yè)性的理論知識(shí)。純粹分享一次開(kāi)發(fā)過(guò)程與心得。之前寫(xiě)了一篇沒(méi)有加入Redux的React Native ToDoList的小博文...
摘要:而不是開(kāi)始,將服務(wù)使用多線程的請(qǐng)求重量級(jí)的容器。是啟動(dòng)多個(gè)輕便單線程的服務(wù)器和流量路由到他們。亮點(diǎn)應(yīng)用程序是事件驅(qū)動(dòng),異步和單線程的。通過(guò)使用事件總線傳遞消息通信。為了建立一個(gè)消息系統(tǒng),則需要獲得該事件總線。 摘要 如果你對(duì)Node.js感興趣,Vert.x可能是你的下一個(gè)大事件:一個(gè)建立在JVM上一個(gè)類似的架構(gòu)企業(yè)制度。 這一部分介紹Vert.x是通過(guò)兩個(gè)動(dòng)手的例子(基于Vert.x...
閱讀 2887·2021-11-15 11:39
閱讀 1513·2021-08-19 10:56
閱讀 1093·2019-08-30 14:12
閱讀 3730·2019-08-29 17:29
閱讀 719·2019-08-29 16:21
閱讀 3416·2019-08-26 12:22
閱讀 1515·2019-08-23 16:30
閱讀 1015·2019-08-23 15:25