Vert.x入坑须知(1) - DTeam的团队日志 - SegmentFault 思否

标签: | 发表时间:2018-09-26 14:11 | 作者:
出处:https://segmentfault.com

一直以来早有将这些年用 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<Map> verticles, Closure completeHandler = null) {
    AtomicInteger count = new AtomicInteger(0)
    verticles.each { verticle ->
        vertx.deployVerticle(verticle.name, verticle.option ?: [:]) { result ->
            if (result.succeeded()) {
                if (count.incrementAndGet() == verticles.size()) {
                    if (completeHandler) {
                        completeHandler.call()
                    }
                }
            } else {
                exit(verticle.name, result.cause())
            }
        }
    }
}

看到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的操作,都请考虑一下。

EventBus

EventBus相当于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 name="map_name">
  <map-store enabled="true">
    <class-name>xxxLoader</class-name>
  </map-store>
</map>

在从未给集群Map赋过值且第一次运行下列代码时,注意两个名字要相同,则触发ReadThrough:

      vertx.sharedData().getClusterWideMap("map_name") {……}

如果想在Vert.x中获得Hazelcast实例,则可以直接使用下面代码:

      Set<HazelcastInstance> instances = 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,以调用顺序为准。故,想先处理的,如验证,往前放。

至于其他,没啥可说的,都很简单。

写在最后

最后,来句鸡汤:遇坑不可怕,还得勇于尝试方能有所收获,希望对各位有帮助!

相关 [vert dteam 团队] 推荐:

Vert.x入坑须知(1) - DTeam的团队日志 - SegmentFault 思否

- -
Vert.x的经验整理一下的想法,奈何天生不是勤快人,直到最近扶墙老师问起,遂成此文. 现在想想,我们应该算是国内用Vert.x的最早一批人,版本大概是1.2.x吧,当时Vert.x内置了一个比较坑爹的模块系统,看似不错,但其实很坑爹. 但即使这样,我们当时还是在技术选型上采用了它. 性能,它的底层是netty,并且编程模型跟node.js如出一辙,可算得上是“node on JVM”.

团队

- Lorna - 坏脾气的小肥
我最近心情起落比较大,如果把时间线再拉长一点,则是去年多自负,今年多自责. 冷静下来的时候也会想,我能不能做得更好. 每一个团队都有它的长处,有它的短处,对于团队的缺陷首先要问自己几个问题:. 1、有没有激励大家全心全意地认同和投入这个项目. 2、有没有分工合理,使每个人认同和投入自己的任务. 3、他的缺陷是否可以通过工作指导、严格督促,在半年或一年时间里自我完善.

团队管理101招

- 狂之想 - C++博客-牵着老婆满街逛
转载自:http://www.iteer.net/modules/doc/article.php?storyid=1402. 无论你是新手还是资深管理人,对你而言,管理好团队都是重要且具激励性的挑战. 切记:每位成员都能为团队作出一些贡献. 谨慎地设定团队目标,且认真严肃地对待它们. 尽早决定何种形态的团队适合你的目标.

DBA团队的使命

- 2sin18 - Alibaba DBA Team
DBA团队的使命:提供高可用、高性能、可扩展的数据存储服务. 高可用:可用性是运维的根本,我们不管做什么事情,都要把可用性放在第一位. 高性能:对性能的关注是我们一直坚持、做的最好的一面,仍需要继续做到极致. 可扩展:也就是最适合的,易部署,可线形透明伸缩. 数据存储:不只是关注某个数据库本身,是基于对各种最先进的数据存储技术的精深理解,提供最专业的服务.

谈团队知识管理

- - 人月神话的BLOG
如果要谈学习型团队,那么团队知识管理就相当重要,团队知识管理介于企业知识管理和个人知识管理之间,核心是知识能够成为整个团队的资产,并为团队创造价值. 今年在团队知识管理上,重点就是按照cmmi的一些思路,形成指导书,规范流程,工具模板,培训教材,检查单的完整知识库积累. 明确各个岗位职责和分工边界,能够按着规范流程做事情,大量前期积累的知识库又能够帮助团队成员快速的学习和解决问题.

谈技术团队目标

- - Tim[后端技术]
技术主管新年想得最多的一件事必定是如何比上一年做得更好. 宏大的目标设定每个团队都会做,谈几个不引人注意的小问题. 见过一些技术团队将计划定义为“按时完成需求”,需求驱动并没有什么不对,但是研发工作仅考虑被动需求的话是很难做好. 之前完成的许多需求有什么共性. 经常出问题/bug/故障的项目/功能/模块是哪些.

团队沟通杂感

- - 人月神话的BLOG
随时随地的短时间的,快速迭代的培训和教练作用远远大于正规的系统培训. 系统性培训一个是针对性往往弱,另外一个就是对团队成员有较高的要求,即自我强烈的系统性学习欲望. 走动时管理目的是及时的发现各种问题和团队技能之欠缺点,有针对性的进行沟通和经验传递,这需要团队管理者有敏锐的洞察力,不能脱离到团队工作事务之外.

某种理想的团队

- - 博客园_知识库
  (这篇文字灵感缘起于昨天发的一条半开玩笑半自嘲的 微博,由于设置了IFTTT被同步到我的 Twitter上,又被欢乐地转发了很多,估计是触发了某种有趣的共鸣). 现在我招聘已经被逼成这样了:先发自己和团队成员的简历给候选人,看你有没有兴趣跟一群这样水准的人一起做事,然后我争取到“面试你的机会”.

敏捷团队工作流

- - IT瘾-dev
站会中的内容是每天工作的开始,也是对昨天工作的回顾. 一般会由团队的某位成员主持,这位主持人有责任让电子系统上的story卡片和看板上的保持一致. 站会上,大家依看板从右至左依次更新自己负责story的状态,如果遇到阻碍,应该在站会上及时提出,团队之中的成员如果能提供帮助,应该在站会之后,组织解决方案的讨论.

【ifanRank】2011 年度最佳团队:微信团队

- 【虎.无名】 - 爱范儿 · Beats of Bits
2011 年,移动互联网的风行涌现出了如 Color 般疯狂的点子,也有像 Flipboard 那样细心耕耘的产品. 当好主意付诸于现实,市场会做出最冷静的判断. 但是它也仅仅只是公众视野中的表象. 一个新产品的成功,不能脱离眼界宽广、长袖善舞的核心团队. 2011年,我们关注了不少出色的团队,Google+ 团队颠覆了人们对 Google “社交无能”的认知,并用精巧地整合了大量自有产品;小米团队用它的市场触觉及侵略性,搅动了国内移动市场;唐茶在电子阅读市场精益求精,走出了内容发布的新模式;知乎用做媒体及点对点的邀请的方式运营精品社区,实现真实沟通的价值;Square 用完美的软硬件设计,用小额支付的切入点实现技术与商业的结合.