摘要:轻量级,部署简单。此外,本文也不是入门文档,而是为了预防陷坑而给出的指导意见,故在阅读本文之前还请先仔细阅读的文档。可视作的一个最小部署和运行单元,简单的说,可类比为。,主,负责部署程序中其他的。严格来讲,之后,上述第一点并不完全正确。
一直以来早有将这些年用Vert.x的经验整理一下的想法,奈何天生不是勤快人,直到最近扶墙老师问起,遂成此文。
选择理由现在想想,我们应该算是国内用Vert.x的最早一批人,版本大概是1.2.x吧,当时Vert.x内置了一个比较坑爹的模块系统,看似不错,但其实很坑爹。但即使这样,我们当时还是在技术选型上采用了它。理由大致如下:
性能,它的底层是netty,并且编程模型跟node.js如出一辙,可算得上是“node on JVM”。同时,性能评测上比node还高出不少。
简单,它比netty更简单,而且可以轻易的支持cluster。
Actor模型,Verticle + Eventbus,降低了并发编程的难度。
WebSocket,恰好当时的项目需要这样的方案,服务器主动向前台推。并且Vert.x提供的EventbusBridge让前端js的组织更好。
支持Groovy,用过的都知道,这里就不展开了。
轻量级,部署简单。
于是乎,它顺利成章地成为了我们当时系统接入层的中流砥柱,在实践中也确实发挥了很好的作用。
踩坑指南鉴于Vert.x当前的版本是3.3.3,因此本文的内容也主要针对这个版本而言,一些我们遇到并且已经修复的bug,也就不会也没有必要在此啰嗦了。
此外,本文也不是入门文档,而是为了预防陷坑而给出的指导意见,故在阅读本文之前还请先仔细阅读Vert.x的文档。
编程语言虽然Vert.x的一大亮点号称是支持“多语言”,即同一个工程内可以同时用Java、Groovy、Javascript等不同语言编写Verticle,但我还是建议采用Java为主,最多辅以Groovy。原因是:我发现很多新出的Vert.x模块还是对Java支持最好,对于其他的则就相当一般了,起码不会让你感觉特意针对这个语言而开发的。加上本来Java 8之后支持lambda,Java程序员的苦逼生活其实已经改善不少。
在dgate中,我主要采用Java + Groovy的方式,两者分工也很明确:前者用于数据处理,后者则用于DSL和数据类。
此时,由于混用了两者,并且可能会出现Groovy类要用到程序中Java类的情况,那么就要用到joint compile。在build.gradle中需要配置如下:
sourceSets.main.java.srcDirs = [] sourceSets.main.groovy.srcDirs += ["src/main/java"]
即,将Java类也交由Groovy编译器来编译。
工程结构虽然Vert.x可以内嵌到其他框架中,但在实际项目上我还是偏爱多带带部署,项目的构建方式则为:gradle + fatjar。具体例子,可以参见这个build.gradle文件。
我在Vert.x邮件组中经常看到有新人问关于Vert.x的组织方式,其实这是没有理解Vert.x的本质:Verticle。Verticle可视作Vert.x的一个最小部署和运行单元,简单的说,可类比为Servlet。因此,整个应用可以这样来划分:
Launcher,程序入口,负责调起Vert.x的环境。
MainVerticle,主Verticle,负责部署程序中其他的Verticle。
Verticle,程序处理逻辑,调用其他POJO/POGO。
POJO/POGO,普通类,供Verticle使用。
前两者负责初始化,Verticle则类似Servlet一样等待被触发(来自TCP/Eventbus/HTTP的Request),在实际处理时会调用到其他类。
这也就是为何在上面的build.gradle中有这样关键的两行的原因:
manifest { attributes "Main-Class": "……" attributes "Main-Verticle": "……" }Logging
Vert.x默认支持JUL,对于其他Logging框架也有支持。但我嫌每次运行要敲那么多命令很烦,那么可以在Launcher中强制设置环境变量:
System.setProperty("vertx.logger-delegate-factory-class-name", "io.vertx.core.logging.SLF4JLogDelegateFactory");
可参见dgate的Launcher代码。
部署Verticle跟Servlet类似,多个Verticle之间也会有依赖关系,存在先后部署的需要。
对于单个Verticle之间的依赖,如A依赖B,很简单,利用deployVerticle的回调就很好解决。因为代码简单,这里就不再多带带列出,还是那句话,看文档。
对于依赖多个Verticle,如A依赖B和C,则需要有点技巧了:
第一也是最差的方式,就是采用callback hell方式,层层递进。
第二种方法采用rxJava,利用Observable的运算来完成。
第三种方式,利用Java的Atom对象,示例代码(Groovy)如下:
private void deployVerties(List
看到Atom对象,你是否觉得也可以采用CountDownLatch对象?很不幸,不行。我当时做过尝试,整个代码立马被Block住,直到我按了Ctrl-C。原因在于:Block住了EventLoop。
至于deployVerticle(),它可以接受字符串和类实例。当使用字符串时,若是非Java类,如Groovy,需要采用这样的格式:"语言前缀:类全限定名"。如:
"groovy:hawkeyes.rtds.processor.MailMan"
此外,部署的Verticle实例并非越多越好,还跟CPU的核数相关。
Block操作Vert.x应用最忌讳Blocking操作,对此有多种处理:
采用Worker Verticle
使用executeBlocking函数
凡是涉及IO的操作,都请考虑一下。
EventBusEventBus相当于Vert.x应用的神经系统,但有几点需要注意:
若想给部署在另一台机器上的Verticle发消息,这两个Verticle必需是在一个集群中。
拦截EventBus的消息需要注意一下这个小地方。
严格来讲,3.2之后,上述第一点并不完全正确。这两个Verticle之间可以采用TCP EventBusBridge来进行通信,具体参见这篇文章。
Cluster和内存计算Cluster是当时我选择Vert.x的一个重要考量,而且将Vert.x应用多带带打成fatjar还有一个附带好处就是Vert.x的cli都可以直接使用,其中就包括cluster命令。
Vert.x的集群建立在Hazelcast之上,除了集群调度,它本身还能做内存存储,即具备了Redis的主要功能。并且查询语法也比Redis(2.x)的要灵活,支持类SQL语法。更重要的是,其ReadThrough特性让人欲罢不能,简化了编程。当然,还包括其他如分布式锁、队列、任务等等。
所谓ReadThrough,即“若内存中没有,则查询将下传到下一级(通常是DB)”。Hazelcast的ReadThrough可通过实现MapLoader接口来实现。这个例子很简单,故可查看Hazelcast的文档了解。这里重点讲一下如何在Vert.x中去配置,因为Vert.x没有对此提供直接支持。
首先,cluster.xml即为一个标准的Hazelcast配置文件,故可在此配置相应的MapLoader即可:
在从未给集群Map赋过值且第一次运行下列代码时,注意两个名字要相同,则触发ReadThrough:
vertx.sharedData().getClusterWideMap("map_name") {……}
如果想在Vert.x中获得Hazelcast实例,则可以直接使用下面代码:
Setinstances = Hazelcast.getAllHazelcastInstances() hz = instances.first()
这样便可利用Hazelcast的其他功能。在3.3.3之后,Vert.x集群支持Ignite,它是比Hazelcast更强大的内存计算工具。而且,在Vert.x 3.4-beta1中已经不再是技术预览版,日后我肯定会全面拥抱它。
Ignite/Hazelcast不像Redis那样曝光率那么高,但鉴于其本身都是老牌内存计算软件,且在开源之前都在高强度生产环境(没记错的话是银行系统)实战演练过,同时对比一下两者之间的功能列表,你会发现这些工具其实更强大,尤其是Ignite。它们的文档都不错,值得一看。
Handler最后说一说Handler中需要注意的地方,它非常适合写Restful API。
之前用Vert.x写接入层代码,主要集中在Core、Groovy和Shell部分。这次写dgate,算是扎扎实实用了一下Web部分。至于历史,我就不详细说了,总之一句话:哥是看着它长大的,;)。
Handler其实很简单,只需要注意几点:
Vert.x request Handler除了处理功能,还兼具Filter的功能。若处理完毕,请求不想让下一个request handler处理,则直接返回即可;否则,需要调用:routingContext.next()。
对于同一个URL可以注册多个handler,以调用顺序为准。故,想先处理的,如验证,往前放。
至于其他,没啥可说的,都很简单。
写在最后最后,来句鸡汤:遇坑不可怕,还得勇于尝试方能有所收获,希望对各位有帮助!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/66686.html
摘要:主要是避免引入太多的复杂性,并且出于灵活部署的需要。以应用为例,由于实际上是在上执行,若它被阻塞,即导致后续请求全部无法得到处理。因此,最合适的做法就是对于简单业务,采用异步库。本系列其他文章入坑须知入坑须知入坑须知 最开始觉得这个系列也就最多3篇了不起了(因为事不过三嘛),没曾想居然迎来了第四篇! Kotlin 由于最近决定投身到区块链的学习当中的缘故,出于更好的理解它的基本概念,自...
摘要:对于集成测试,直接模拟实际的环境,再加上合适的,目前看来也还不错。这里给出两个例子集成测试单元测试都是基于写的,各位可以体验其酸爽度。好啦,本期内容就此结束,请保持关注,期待下期继续本系列其他文章入坑须知入坑须知 随着Vert.x进化到3.5.0,本系列也迎来了新篇章。 CORS的新变化 对于CORS,搞Web开发(不论你是前端,还是后端)的同志应该不陌生,尤其是如今微服务盛行的时代,...
摘要:这一点其实是非常不妥的,有潜在的安全问题。这次,在项目中终于采用了以它为基础的集群方案。相反,使用一个周期,但针对每个生成一个一次性的,模拟随机发送。同时,要记得用完之后立即释放。 当初创建简书账号的时候曾立下宏愿,希望保持周更,无奈现实残酷,整个5月都处于忙忙碌碌的状态,居然令这个本来并不算太宏伟的目标难以为继,最终导致5月份交了白卷!【好吧,我承认,是我意志不够坚定,太懒了,;)】...
摘要:之前写了一篇没有加入的的小博文。一拆分结构根据自己的习惯和固定套路,拆分目录结构和组件结构。把的导航组件集中放在纯粹是个人习惯。二代码实现入口文件是用来做的数据持久化。添加事项后要通知其他组件更新数据。 读前须知 这个项目是第一次使用Redux的实例,并不具有专业性的理论知识。纯粹分享一次开发过程与心得。之前写了一篇没有加入Redux的React Native ToDoList的小博文...
摘要:而不是开始,将服务使用多线程的请求重量级的容器。是启动多个轻便单线程的服务器和流量路由到他们。亮点应用程序是事件驱动,异步和单线程的。通过使用事件总线传递消息通信。为了建立一个消息系统,则需要获得该事件总线。 摘要 如果你对Node.js感兴趣,Vert.x可能是你的下一个大事件:一个建立在JVM上一个类似的架构企业制度。 这一部分介绍Vert.x是通过两个动手的例子(基于Vert.x...
阅读 2862·2021-11-15 11:39
阅读 1495·2021-08-19 10:56
阅读 1074·2019-08-30 14:12
阅读 3669·2019-08-29 17:29
阅读 660·2019-08-29 16:21
阅读 3402·2019-08-26 12:22
阅读 1496·2019-08-23 16:30
阅读 991·2019-08-23 15:25