新的一年中间件技术展望

25 December 2016

新的一年中间件技术展望

Java语言

2017年是Java语言技术大年。

  1. Java 9会在7月份发布,其中包含了推迟了若干年的模块化特性,这个会对未来的架构设计和开发方法产生深远的影响。HTTP/2,jShell,Flow API,Unified Log, Multi-Release JAR,jlink以及很多安全方面的改进和增强令人期待。

  2. SpringFramework5会发布,Reactor3成为异步框架的关键。这个新的框架将进一步提升通用Java应用的移动设备和网络应用的吞吐能力。

  3. MicroProfile已经被Eclipse组织接纳成为孵化项目,JavaEE在社区领域,出现了一个独立的开发规范集合,一大批开源框架和服务器正在不断成熟中,今后将会是Java微服务开发的主力。

  4. 如果顺利的话,JavaEE8会在四季度发布,尽管除了Servlet4之外,没有其他大的改进。但各个规范会进一步适应目前的异步化,服务化的开发需求,EE8还是非常值得期待的。

应用服务器

与Java语言傲居开发语言之首形成鲜明对比的是,JavaEE应用服务器市场规模依然在下滑,前不久Gartner Group还专门发了市场分析报告来唱衰这个市场,并预言微服务框架和PAAS平台会占据更大的份额。我基本同意应用服务器市场会从原先中间件开发平台垄断位置减少很大的市场份额,而且中间件基础软件会延续Linux的市场发展轨迹,走产品免费而订阅服务的商业模式。微服务框架产品目前已经成快速增长趋势,PAAS平台也开始被更多的企业所接纳。

然而我相信,应用服务器(或者说是整体交付的独立运行应用程序的服务器)还是有大片的市场需求的,尤其是在国内,目前各行业中企业软件还几乎全部是部署在应用服务器上。虽然各个企业都在寻求可能的服务化改进,并盯着一线互联网公司学习经验,但毫无疑问想要改变企业应用基础架构的技术路线,这个过程会非常漫长。

而且,应用服务器的市场还是会一直存在的。一个例子就是SAP的Hana服务器,近来会推出HANA2。这是一个内存杀手,把整个商业系统容纳在一个庞大的业务服务器中。给企业内部使用的,采用交付软件的方式,系统整体效率非常高,软件经过广泛的测试,成熟度和稳定性很好。

应用服务器的市场就是面向广大的企业应用,不需要很大的并发访问量(如果需要暴露数据到互联网上可以采用同步数据方式),功能特性非常丰富,需要有很强的事务处理能力,最终用户的开发力量不是很强,主要以业务用户和运营为主。在这个场景下,带有集群能力的应用服务器还是首选,使用目前较轻量级的应用服务器,可以做到快速开发部署,解开压缩包即用,几秒内迅速启动,配套的监控运维平台。在当前主流服务器硬件能力下,个位节点数组成的服务器集群,支撑上百万的并发访问不会有问题,足以满足绝大多数企业应用和中小网站的需求。

那么,为什么唱衰应用服务器呢?原因是过去它承担了太多的期望,各种应用,不论架构设计的合适还是不合适,都在应用服务器上开发和部署。各个厂商的产品都做成了大而全的大杂烩,动则500M以上,厚重而运行缓慢。Spring框架首先质疑并通过敏捷而优秀改进占领了Java服务器Web开发的大部分份额。后来OSGi技术也曾经发起过挑战,但由于自身也很复杂,学习曲线陡峭,除了集成,工控等领域,并没有被广泛运用于企业软件中。

从2014年开始,容器和微服务成为技术的热点词汇,可以说它们是相辅相成的,微服务需要一个能被管控的载体,恰好容器技术开始成熟并广泛应用。而容器技术也是一个筐,需要有具体的应用来完成技术的演进。

那么,容器和微服务真的是“新”技术么?首先容器一词,早在J2EE出现时就有了Web容器和EJB容器的说法,顾名思义,就是容纳应用的载体,开发者编写的程序通过API/插件/Addon等扩展机制,部署/运行在一个环境之中,而这个环境提供通用的技术设施和数据等服务。而微服务,Corba时代的进程,和后来的SOA,都是如假包换的服务程序。只不过如今的容器和微服务都有了更多的特点和更清晰的定义。

服务化

从技术的角度来看,JavaEE应用服务器的架构,从开始就是可以服务化的,比如Servlet通过远程调用EJB接口,只不过在规范中被定义成需要RMI/IIOP协议。这些看似“过时”的定义,其实在企业应用中可以工作的很好,如EJB3.1定义的异步接口能力,就可以大大的提高系统整体吞吐能力。而且如果能有效的进行改进,比如说未来的EE9,可以支持如gRPC等远程调用协议,将会唤回新的技术活力。

JavaEE的最大问题就是整体过于庞大,有33个子规范,而在面对某个类型应用时,绝大多数规范运用不上,能用上的呢,又定义的不是那么的细致全面,还比不上Spring框架或者第三方库等实务者。所以我们在具体技术选型时,可以忘掉JavaEE大而全,而要选择合适的,小而美的具体子规范,搭配使用来满足应用需要。

MicroProfile就是面向微服务而由社区形成的一个JavaEE子规范集,已经推出的1.0只包含三个JaxRS/CDI/JSONP,通过这三个现有的EE7子规范组合,就可以满足微服务开发的很多需求。目前Wildfly-swarm, Payara micro等已经完整支持。使用这个技术集的一个红利是:开发的产品,即可以部署在应用服务器中,也可以作为微服务程序开箱即用。

从具体的软件架构来说,传统的三层结构已经不能满足当前的互联网应用需求,分布式已经是必然要考虑的属性。而矛盾点就是,以事务为核心的企业应用,设计的一个原则就是避免分布!所以对于有扩展需求的应用,适当的软件架构非常重要。我的观点是,采纳DDD设计思路中的CQRS原则,在设计时就考虑,这样无论是在一个JVM,还是分布式架构,API是统一的,体系变得非常清晰。应用实体的修改,用事件存储机制和消息队列,数据的查询则采用类似RxJava这样的异步数据访问接口,数据直接通过中间件进行高效同步复制,并使用分布式缓存来优化存储和数据访问速度。

这样的体系架构,可以横跨应用服务器/微服务框架/PAAS运行平台,在一定程度上做到架构设计的可扩展性。从执行效率来讲,无论是命令模式API,还是消息队列,Rx式数据访问,都可以本地执行实现极速访问,也可以远程调用便于动态扩展。

新的一年,应用服务器,微服务平台,应用基础架构,中间件领域,新的机遇新的挑战。

Netflix OSS, Spring Cloud 以及 Kubernetes?关于它们的种种!

12 June 2016

说明

本文是一篇 翻译文章,来自于前同事,红帽中间件架构师 Christian Posta @christianposta 。

当我第一次读到时,就知道是一篇好文,详尽的解释了Spring Cloud 中 Netflix OSS组件在Kubernetes容器管理场景下,最优实践是怎样的。 之前的 微服务知识体系,有一些相似的想法和技术方案,也借鉴一些观点和技术方案,如采用Turbine来统一输出断路器信息。

经过Christian的授权,我翻译了这篇文章为中文供国内Java微服务开发者作为参考,有不通顺的地方请见谅。

以下译文(采用第一人称)

本文以下的内容,在我的新书"面向Java开发者的微服务“中也涉及到一些,该书由OReilly出版社在2016年6月即将出版发行。我想在这里给出一些更明确的说明,因为很多人问到了关于Netflix OSS和如何在Kubernetes上运行的的问题(这些项目都是非常棒的!),以及这些组件完成的功能是重叠的,我会试着解释一些原因。

Netflix OSS是一组开源的框架和组件库,Netflix公司开发出来解决分布式系统的一些有趣的可扩展问题。如今对于Java开发者来说,它们是在云端环境中开发微服务的非常棒的工具代名词。在服务发现,负载均衡,容错等模式方面,都给出了非常重要的概念,并带来了漂亮的解决方案。

Netflix决定把这些项目贡献给开源社区,促进了其他互联网公司也这样做,我们要说声“谢谢”。而有些大型的互联网公司专利化它们的技术,保持闭源,比起来实在是太糟糕了。

Netflix OSS

总的来说,在多数Netflix的开源项目开发的时期,只有AWS公有云可以选择而没有其他的替代。这个因素导致这些库并不是直接为今天采用的运行环境(如Linux上的容器)开发的。采用了Linux容器,Docker,容器管理系统等基础环境后,我们看到了大量的运行在Linux容器上的微服务,它们可能运行在公有云,私有云或者都有。另外,因为容器是服务不透明的包装,我们往往不关心容器里究竟运行什么技术方案(Java/Node.js/Go)。Netflix OSS基本上是Java开发,它们是一组组件库/框架/配置项,可以包含在你的Java应用/服务器代码中运行。

所以我们有了观点#1:

微服务可以由多种框架/语言来实现,但服务发现,负载均衡,容错等这类服务是非常重要的。

如果我们运行在容器中这些服务,我们可以利用强大的与语言无关基础设施的优势,做这些事情:构建,打包,部署,健康检查,滚动升级,蓝绿部署,安全性,和其他。例如,OpenShift(基于Kubernetes构建的企业开发部署方案),可以做所有这些事情:而不需要开发者必须知道或者关心基础设施的这些事情。而集中精力来保持你的应用程序和服务简单。

为什么基础设施可以帮助做服务发现,负载平衡和容错这些服务,难道不应该是应用层的事情么? 如果使用Kubernetes或者其衍生项目,那么答案是可以在基础设施实现这些服务。

Kubernetes中服务发现的方式

使用Netflix OSS,通常需要设置一个服务发现服务器,作为客户端可以发现的服务端点注册表。比如,你可能使用Netflix Ribbon来与其他服务通信,并需要发现服务在哪里运行。服务可以自行停止,也可以在集群中加入更多的服务来实现扩展。这个中心服务发现注册表跟踪什么服务在集群中是可用的。

一个问题是:你作为一个开发者需要做这些事情:

  • 决定是使用一个AP系统(consul, eureka等)还是CP系统(zookeeper, etcd等)

  • 弄清楚如何运行,管理和监视这些大规模系统(而不是小型的练手项目)

此外,你需要了解客户端使用什么编程语言和服务发现通信。前面提到过,微服务可以由许多不同类型的语言实现,Java客户端是没有问题的,但如果没有Go或者NodeJS客户端,就需要自己开发了。每种语言和开发者都有可能用自己的想法来实现客户端,你会面临维护多个客户端,它们试图做相同的事情,却在语义上有不同的方式。或者每种语言都有自己的服务发现服务器,以及自己的客户端程序呢?你要管理和维护这么多的服务发现实现么,想想就头疼。

如果我们仅用DNS呢?

好吧,这个算是解决了客户端库的问题。DNS是每个操作系统都有的基础服务,利用TCP/UDP协议,在私有云,公有云,容器,Windows,Solaris等都有。客户端只需要指向域名就可以了,基础服务可以路由到服务上,可以采用多个轮转DNS配置来实现均衡负载。好处是客户端都不需要知道服务发现服务器,而使用TCP客户端就可以了。而且也不用管理DNS集群,网络路由器支持负载均衡特性,而且这些都很简单容易被理解。

但对于弹性发现,DNS方案就做的很差了。DNS不适合做弹性的,动态的服务集群。当服务加入到集群或者移除时,系统做了什么?服务的IP地址可能还在DNS服务器或者路由器(甚至有些不是你能掌控的),或者你自己的IP堆栈上进行了缓存。另外,如果你的应用侦听的是非80端口,而要DNS保存非标准的端口信息,需要使用DNS SRV记录,而这样你又需要使用特定的应用层客户端来发现这些记录了。

Kubernetes服务

让我们只使用Kubernetes,在docker/linux容器上运行程序,而kubernetes是最合适的运行docker容器的场所,或者Rocket容器,Hyper.sh容器。

(我偏爱简单的技术,或者看起来是简单的,因为你不可能用复杂的零件构建出复杂的系统,人人都渴望简单,最好的是内在复杂而外在简单,google和红帽都对于kubernetes做了大量工作,使得它对于分布式系统的部署和管理部分看起来都很简单。)

使用kubernetes,我们建立一个kubernetes的服务,大功告成了!我们不用浪费时间建立一个发现服务器,编写定制的客户端,使用DNS等,已经可以工作的很好了。我们转而看下一部分,微服务提供的商业价值。

是如何工作的?

以下是kubernetes的一些抽象概念:

  • Pods

  • Labels / Label Selectors

  • Services

Pod很简单,就是Linux容器。Label也很简单,它们是键-值字符串,用于标记 Pod。比如 Pod A可以标记为app=cassandra, tier-backend, version=1.0, language=java,这些标记可以表示任何你的意图。

最后一个概念是服务,也很简单。服务是一个固定的群集IP地址。该IP地址是一个虚拟IP地址,可用于发现/调用在Pod/容器中的实际端点地址。实际的IP地址是如何被发现的?服务使用了label selector来选取你定义过的标签Pod。举例,使用选择器“app=cassandra AND tier=backend”,就得到一个虚拟的IP地址,访问所有具备上述标记的Pod,这个选择器是即时生效的,所以任何离开集群的pod或者加入到集群中的都可以自动被启动并参与到服务发现中。

Kubernetes Simple Services

另一个使用kubernetes服务的好处是,智能的选取Pod来加入到服务中,根据它们的存活和健康信息。Kubernetes使用内建的存活和健康检查方法,来确定一个Pod是否包含在一个特定服务之中,如果不满足条件,Pod会被驱逐出去。

注意Kubernetes服务不是一个“东西”,一个设施或者docker容器等,它就是一个虚拟表示,所以没有单独故障点,是一个IP地址,由kubernetes来路由消息。

这个概念难以置信的强大,对于开发者来说很简单,现在一个应用想用cassadra作为后端数据库,只需要用一个固定IP地址对应的一组cassadra数据库。然而硬编码固定IP地址不是好的主意,因为可以迁移应用到不同的环境下(QA/PROD),需要更改IP(或者注入一些配置信息),这时我们使用DNS。

使用Kubernetes的DNS集群方案是正确答案。因为对于给定的环境,IP是固定的,我们不用考虑其缓存,它们不会变化。我们使用DNS服务。比如应用配置使用http://awesomefooservice,当我们从Dev换到QA以及Prod环境时,配置相应的kubernetes服务,我们的应用不需要改变。

Kubernetes Services

我们不需要额外的配置,我们并不需要担心的DNS缓存/SRV记录,自定义库的客户端和管理额外的服务发现的基础设施。Pod可以被加入到集群中,标签选择器积极的选取符合标记的Pod,应用可以是Java, Python, Node.js, Perl, Go, .NET, Ruby, C++, Scala, Groovy等任何语言开发的。服务发现机制不关心特定的客户端而只是使用它。

那么客户端均衡负载的情况呢?

很有趣的是,Netflix编写了Eureka和Ribbon,组合使用它们,可以用来客户端的负载均衡。一般来说,服务注册器管理和跟踪集群中存在哪些服务,并且把这些数据发送给感兴趣的客户端。这样,客户端知道了集群中节点的信息,它可以选择一个(随机,粘滞或者自定义的算法),然后调用它。下一次调用时,又可以选择集群中另外的一个服务。

另一个重要的方面是:由于客户端知道服务在哪里,客户端可以直接联系服务端,而不用经过中途的跳转。

在我看来,客户端的负载均衡大概占据5%的用例。原因解释一下: 我们要的是一种方法,可以理想的做可扩展的负载均衡,而不需要任何额外的设施和客户端库。在大多数情况下,我们并不关心是否有中间的负载均衡器额外的跳转(大概你99%的应用情景是这样的)。我们遇到的情景是,服务A调用服务B,需要调用服务C,D,E,这样才能获得图片信息。这种情况下,很多的跳转带来更多的延时。所以可能的方案是“移除多余的跳转”,而不是均衡负载的跳转,调用下游服务的次数是必须的。我的博客中有关于事件驱动系统的文章,以及自治管理相关的讨论,可以关注。

使用Kubernetes的服务,我们完成了适度的负载均衡(没有服务注册,定制的客户端,DNS缺陷等的开销)。当我们通过DNS和一个Kubernetes服务进行交互时,将使用集群中的Pod进行负载均衡操作(使用标签选择器)。如果你不希望在负载均衡处有额外的跳转,请不要担心,虚拟IP直接路由到Pod,并不涉及到物理的网络。

好极了,95%的用例都变得很简单!因为应用情景总是在95%的场景中,所以不用过度设计,让事情越简单越好。

那么对于剩下的5%的用例呢?有时你会遇到这样的情况,需要根据业务决策来决定使用具体集群中哪一个后端服务。一般情况下,使用一些特定的算法,而比像“轮询”,“随机”,“会话粘滞”要复杂的自定义算法,根据具体的应用程序。这时使用客户端的均衡负载。在这种模式下,依然可以使用kubernetes的服务发现来找到是在哪个Pod集群,然后用客户端代码直接调用其中的Pod。fabric8.io社区的kubeflix项目,就使用Robbon作为发现插件,来使用REST API获得服务对应的所有Pod列表,然后客户端的代码决定调用哪一个pod。其他语言使用kubernetes的REST API也可以做类似的工作。可以投入做一些客户端发现库来简化这个操作。更确切的说,是把这样的业务逻辑,从应用程序中分离出来作为独立的中间件。通过使用kubernetes,你可以部署这样的模块,作为应用的独立部分,并把自定义的均衡负载逻辑定义在那儿。

Client load balance

重申一次,以上只是用在5%的用例中,有更多的复杂性。对于95%用例,就用内建的和特定语言的客户端无关的方式就好。

关于容错

依赖相关的系统,构建时应当总是要记住承诺性。这意味着,应用总是要时刻注意它的依赖系统是否处在不可用或者崩溃的状态下。问题是kubernetes是否有容错方面的考虑?

kubernetes的确有自愈的能力,如果一个pod或者pod中的一个容器停止了,可以将它重新启动,并保持ReplicaSet保持不变(比如,如果需要有10个“foo” pods,那么kubernetes总是保持有10个,如果有停掉的,会再次启动pod)

自愈设施是非常棒,而且是自带的服务。但我们需要讨论的是,当应用对应的依赖(如数据库或者其他服务)停止时,会发生什么?这取决于应用程序如何与之交互。例如,在Netflix,如果你尝试观看特定电影时,要调用“授权”服务,来知道你什么特权,是否可以看电影。如果该服务停止,我们应该阻止观看该影片的用户?还是显示异常堆栈信息? Netflix的做法是让用户观看电影。这是更好的方案,订阅者应当观看,一个服务依存关系在一段时间出现错误时,不应当影响到用户享受一次电影。

我们需要的是一种正常的降级方案,或者寻找一种替换的方法来保持服务承诺。Netflix的Hystrix项目就是给Java开发者一个非常棒的方案。它实现了方法来做到"bulkheading","circuit breaking", "fallbacks"。每种对应一个应用相关的实现,也有不同语言的客户端库。

Hystrix

这里kubernetes也能帮上忙么?是的!

我们再看看很棒的kubeflix项目,你可以使用Netflix Turbine项目来聚集和可视化集群中所有的运行中的断路器。Hystrix可以用SSE暴露信息送到Turbine中。然而Turbine如何发现哪些Pod中包含了Hystrix?可以使用kubernetes的标签。如果我们标记所有使用hystrix的pod,"hystrix.enable=true",那么Kubeflix Turbine引擎自动发现每个断路器,获得SSE流并且显示到Turbine页面上。这点感谢Kubernetes。

Turbine Hystrix

关于配置

Netflix Archaius用来处理云端的分布式配置管理服务。可以设置一个配置服务器,使用Java库来查找配置项。还支持动态配置改变。

这里又有95%用例情景。我们希望让环境特定的配置(这是一个重要的区别,不是每一个环境特定的配置需要根据运行环境而改变)存储在应用程序之外,并且基于运行的环境(DEV,QA,PROD)来注入这些配置项。但我们真的想要一个与语言无关的方式来查找配置,而不是使用Java库,或者使用classpath等使得配置复杂化。

在Kubernetes我们使用三个结构来注入基于环境的配置:

  1. Environment Variables 环境变量

  2. GitRepo Volume git仓库作为文件卷

  3. ConfigMap

通常我们可以设置环境变量,注入配置数据到Linux容器中,大多数语言都可以轻松读取到这些信息。 我们可以存储这些配置到git中,然后绑定配置仓库到我们的pod上(作为文件系统的文件),这样可以用任何框架来获取配置文件信息了。 最后,我们可以使用Kubernetes的ConfigMap来存储配置版本信息,作为文件系统mount到Pod上,同样的,可以用任何语言和框架来处理配置文件。

5%的用例情况呢?

在5%的使用情况,你可能希望在运行时动态更改配置。Kubernetes帮助做到了这一点。您可以更改配置文件,通过ConfigMap这些变化动态地传播到了mount的pod。在这种情况下,你需要有一个客户端库,能够检测这些配置的变化并通知你的应用程序。Netflix的Archais有一个客户端可以做到这一点。Spring Cloud Kubernetes的Java项目使这个更容易(使用ConfigMaps)。

关于Spring Cloud

使用Spring开发Java微服务,往往使用Spring Cloud中的Netflix项目,基本就是Netflix OSS项目。fabric8.io社区也有很多好用的项目,比如spring-cloud-kubernetes,大多数模式(包括配置,跟踪等)可以无须额外的,复杂的基础设施(如服务发现引擎,配置引擎等)而直接运行在kubernetes之上。

总结

如果你开始构建微服务的方法,你肯定已经被Netflix OSS/Java/Spring/SpringCloud所吸引。但是要知道你不是Netflix,也不需要直接使用AWS EC2,使得应用程序变得很复杂。如今使用docker和采用kubernetes是明智之举,它们已经具备大量的分布式系统特性。在应用层进行分层,是因为netflix5年前面临的问题,而不得不这样做(打赌说如果那时有了kubernetes,netflix OSS栈会大不相同)。避免应用程序复杂是一个明智的选择。

微服务技术体系

31 May 2016

微服务技术体系材料发布

近一年的技术考察和积累,我们总结出一套比较完善的微服务技术和开源产品框架。

经过一个月的材料收集和撰写,永源中间件的微服务技术体系演讲材料发布了。

包含一下五个大部分:

  1. 微服务技术

  2. SpringBoot开发框架

  3. Vertx异步框架

  4. 容器技术和配套服务

  5. 和原有JavaEE技术的对比和结合使用

从当前活跃开发的开源项目中,选取可靠稳定的产品进行组合,构建出一套完善的,开箱即用的微服务技术框架。

涉及到的项目有:

  • 容器相关技术:docker, kubernetes

  • JavaEE开发框架: SpringBoot, Wildfly-swarm

  • 异步开发工具:Vertx

  • SpringCloud以及配套项目

  • Nginx

  • 微服务管理:API Gateway, 分布式跟踪和性能监控, SSO Server, 统一日志管理

  • JavaEE应用服务器的应用思考

微服务知识体系大纲

微服务概述

  • 和单块应用的区别

  • 海量用户互联网

  • 应用设计的12要素

SpringBoot应用设计

  • 配置项定义

  • 通过Rest或者Websocket提供服务

  • 各种组件通过maven组合构成

  • JavaEE技术栈的选用

  • 配合SpringCloud,保存配置,注册服务,路由管理,断路控制等

  • 系统自治,日志输出,安全设置等

  • Wildfly-Swarm类似的设计思路

Vertx异步框架

  • 基于Netty,内部Json格式

  • 和Nodejs类似的循环执行线程,但有独立执行线程的扩展

  • Socket和HTTP服务

  • Vertx-Web处理Web应用请求

  • 异步调用方式处理,RxJava数据处理

  • 支持集群,多节点数据共享

容器技术和服务管理工具

  • Docker容器运行微服务

  • 使用Kubernetes来管理应用容器

  • Nginx或者Undertow提供Web层反向代理

  • Keycloak安全权限管理

  • Api Gateway提供服务注册和消费,版本升级管理,服务限流,安全防护等

  • APM应用管理,检测服务调用路径

  • ELK集中管理日志

  • 服务治理的需求和实现思路

JavaEE应用服务器回顾

  • Corba时代的微服务

  • 企业应用对事务的需求

  • EJB的灵活设计,

  • 远程EJB能力,其他RPC选择,如Dubbo,gRPC

  • Servlet和EJB支持非阻塞调用

  • 消息机制运用到设计中

  • Spring框架和CDI规范

  • JPA和SpringData

  • 数据源和缓存,分布式结构

  • "微"服务同样需要有完整的技术层次,稍复杂的应用打包后也是庞大的

  • 界面技术的选用,浏览器渲染能力,移动设备的考虑

  • 针对不同的应用和系统规模的大小,选用合适的架构

  • 同样是部署应用到容器,微服务是应用服务器整体的分布化。应用从进程内的调用,扩展到跨进程远程调用。

演示文件地址

Spring Boot 和 Wildfly Swarm 的性能基本对比测试

27 May 2016

Wildfly Swarm 1.0.0.CR1 发布

Wildfly-swarm 1.0.0.CR1今天发布了。 http://wildfly-swarm.io/posts/announcement-1-0-0-cr1

Wildfly-swarm是一个基于Wildfly-core的微服务项目,和Wildfly应用服务器共同使用相同的内核组件MSC。

我们可以认为它是和SpringBoot类似的项目,拥有相似的架构和开发/构建方法。基础组件对比如下:

  • 注入服务:SpringFramework和 Weld CDI容器

  • Web容器:嵌入式的Tomcat和嵌入式的Undertow

  • Rest数据:SpringMVC和JaxRS实现RestEasy

  • 持久层:均采用JPA和Hibernate作为实现

  • 嵌入式的数据库:HsqlDB和H2数据库

  • 构建:都采用Maven进行构建,可以选用Gradle

JavaEE原来开发应用的步骤是:1.启动应用服务器,2.进行部署。 微服务时代,JavaEE编程方式需要调整来适应。从部署到服务器中改造为直接启动应用进程,内嵌一个web容器。 把所需要的jar和应用代码全部打包到一个jar或者war中,通过

java -jar example.war

的方式来启动服务。

这个项目从启动到现在过去了一年多,如今进入到候选发布版本时期,也意味者整体架构和API不会再有大的变化,功能和性能都已经比较稳定了。

与此同时, SpringBoot毫无疑问是过去的一年中的明星项目,下载量节节升高,越来越多的项目采用SpringBoot来开发。Docker和微服务的各种技术大会上也都能听到开发者热烈讨论和学习。

Wildfly-swarm一直作为SpringBoot的一个潜在对手项目在努力开发中,如今发布了CR版本,我们希望通过简单的性能对比测试来得到一手的数据。

测试方法介绍

我们选用两个项目中现成的有代表性的例子作为测试用例。两个例子的架构基本相同:

  • 内嵌Web容器

  • 使用MVC或者JaxRS来表现Rest文本数据

  • 利用Spring框架或者CDI框架,注入beans

  • 持久层使用JPA,Hibernate 5作为实现

  • 使用嵌入式数据库,启动时加载少量测试数据

  • mvn构建打包好的war,可以直接用java执行

测试机器为 Linux Ubuntu 14.04.3, 8 Core, 8G Mem

Linux useopen-w5 3.16.0-33-generic #44~14.04.1-Ubuntu SMP Fri Mar 13 10:33:29 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

Java虚拟机为Oracle JDK:

java version "1.8.0_74"
Java(TM) SE Runtime Environment (build 1.8.0_74-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)

使用Apache-jmeter来进行简单的性能测试,版本为2.13。

创建一个线程组:十个并发线程,每个运行5000次,每一轮测试运行50000次访问(thread 10, Rarm-up: 1sec, loop count: 5000)。

创建一个HTTP Request来访问本地8080 web端口,并建立一个Generate Summary Result来输出测试的结果。

另外启动一个jconsole,挂到服务进程上查看资源的占用情况。

每个项目用例都运行两轮,方法是启动后先跑一次warm-up测试,记录相关数据后,连续跑三轮正常的应用测试。关闭并重启应用服务进程后,再做一遍第二轮的测试。

SpringBoot 测试

获取SpringBoot 1.4.0.M2版本,编译例子/spring-boot/spring-boot-samples/spring-boot-sample-jpa/,在target目录下有 spring-boot-sample-jpa-1.4.0.M2.jar文件,大小26.2M,解压后在三方包目录下有48个jar。

关键的组件版本如下:

  • tomcat-embed 8.0.33

  • spring 4.3.0.RC1

  • Jackson 2.7.3

  • hsqldb 2.3.3

  • hibernate 5.1.0

使用java启动进程,启动时间为 6.0秒 左右。

用浏览器访问http://localhost:8080,得到数据

Title	Body	Tags
Spring Boot	Takes an opinionated view of building production-ready Spring applications.
Spring Framework	Core support for dependency injection, transaction management, web applications, data access, messaging, testing and more.
Spring Integration	Extends the Spring programming model to support the well-known Enterprise Integration Patterns.
Tomcat	Apache Tomcat is an open source software implementation of the Java Servlet and JavaServer Pages technologies.

启动后的堆,活跃线程,加载的类数目分别为:

  • heap: 121M

  • live threads: 19

  • current classes loaded: 8649

使用jmeter压测一边,50000次访问后的两轮的结果为:

R1: Generate Summary Results =  50000 in    18s = 2841.4/s
R2: Generate Summary Results =  50000 in    19s = 2681.3/s

经过几秒等稳定后,观察jconsole中的系统状态,堆的大小两轮不太一致:

  • heap: 105-212M

  • live threads: 27

  • current classes loaded: 9411

分别记录两轮压测性能数据:

Generate Summary Results =  50000 in   7.3s = 6832.5/s
Generate Summary Results =  50000 in   7.4s = 6721.3/s
Generate Summary Results =  50000 in   7.5s = 6709.6/s

Generate Summary Results =  50000 in     8s = 6323.5/s
Generate Summary Results =  50000 in     8s = 6596.3/s
Generate Summary Results =  50000 in     8s = 6544.5/s

在测试过程中,Heap的变化曲线:

Heap - SpringBoot

手工GC后

  • heap: 37M

  • live threads: 27

  • current classes loaded: 9407

Wildfly-swarm 测试

获取Wildfly-swarm 1.0.0.CR1版本,编译例子/wildfly-swarm/wildfly-swarm-examples/jpa-jaxrs-cdi/jpa-jaxrs-cdi-war,在target目录下有 example-jpa-jaxrs-cdi-war-swarm.jar文件,大小88.2M,解压后在三方包目录下有325个jar。

不得不说这个包实在是太大了,里面基本包含wildlfy应用服务器的全部组件。具体的分析我会再写一篇分析文章。

关键的组件版本如下:

  • wildfly-core 2.0.12

  • undertow 1.3.15

  • resteasy 3.0.14

  • jackson 2.5.4

  • hibernate 5.0.7

  • weld 2.3.2

  • h2 1.4

使用java启动进程,启动时间为 3.4秒 左右。

用浏览器访问http://localhost:8080,得到数据

[{"id":1,"name":"Penny"},{"id":2,"name":"Sheldon"},{"id":3,"name":"Amy"},{"id":4,"name":"Leonard"},{"id":5,"name":"Bernadette"},{"id":6,"name":"Raj"},{"id":7,"name":"Howard"},{"id":8,"name":"Priya"}]

使用jmeter压测一边,50000次访问后的两轮的结果为:

R1: Generate Summary Results =  50000 in    10s = 5008.0/s
R2: Generate Summary Results =  50000 in    11s = 4754.7/s

经过几秒等稳定后,观察jconsole中的系统状态:

  • heap: 115M

  • live threads: 184

  • current classes loaded: 14114

分别记录两轮压测性能数据:

Generate Summary Results =  50000 in     4s = 13661.2/s
Generate Summary Results =  50000 in   3.5s = 14476.0/s
Generate Summary Results =  50000 in   3.3s = 14970.1

Generate Summary Results =  50000 in     4s = 13931.5/s
Generate Summary Results =  50000 in     4s = 13954.8/s
Generate Summary Results =  50000 in     4s = 14064.7/s

每次测试heap都会明显增加,在测试过程中,Heap的变化曲线:

Heap - WildflySwarm

手工GC后

  • heap: 29M

  • live threads: 185

  • current classes loaded: 14110

总结

SpringBoot和Widfly-swarm都是极为优秀的项目,在微服务时代来临时,它们让Java程序员利用已有的JavaEE编程知识,快捷高效的开发出健壮稳定的应用。

两个项目的启动时间都在几秒种,而且在普通的笔记本上,能用未经过调优的普通应用环境完成每秒上万个服务请求,性能已经很不错了。而且是较为完整的技术栈,包含页面数据,服务和数据库持久等层。

wildfly-swarm作为后来者,表现令人侧目!

  • 启动时间,

  • 热身测试

  • 正式的应用测试

都比SpringBoot差不多快了一倍。直观的比较图形:

Spring VS WildflySwarm

性能优异的原因我只能从架构上先简单猜测下,等进一步研究后再给出具体分析:

  1. wildfly-core内部MSC内核是异步注入容器,性能非常强劲。

  2. undertow的网络层使用XNIO框架,采用和Netty类似的原理,可能比Tomcat的网络层要高效一些?

  3. 不太确认两者分别在web/服务/JPA等层次是否有缓存,以及缓存的策略。因为我们的测试是不变数据,所以不能反应真实应用场景。

需要说明的是Wildfly-swarm应用的打包文件实在是太大,有些范例要超过150M,微服务不“微”。当然,打包中的jar存放在树形目录module中,也许可以利用docker的文件层次堆叠特性来做一个微服务jar公有仓库,这样每个包就可以很小了。

Java应用占用的内存也较大,不过都在可接受范围之内。需要针对具体的应用进行调优。

非常感谢Wildfly-swarm团队带给我们如此优秀的开源项目! Awesome wildfly-swarm!

JBoss开源应用服务器的最新培训资料

12 May 2016

Wildfly 10 and EAP 7

今天 JBoss EAP 7 正式发布了,这是在今年一月份JBoss Wildfly 10发布之后,红帽软件基于Wildfly10正式发布的商业支持的应用服务器产品。

Wildfly 10/EAP 7是同源的实现了JavaEE完整规范的应用服务器,和5年前的JBossAS7/EAP6相比,在性能,可靠性,安全性都有进一步的巨大提升。

以下为一些特色亮点:

  1. Web服务器基于Undertow,是借鉴了Nginx的设计思路,用Java实现的事件驱动的Web引擎。采用NIO为网络底层实现机制,同时支持非阻塞和阻塞IO模型,目前已经对Websocket和HTTP/2都有优秀支持。

  2. 基于Wildfly-core核心服务器,JavaEE规范实现代码和应用服务器核心代码很好的分离,对于其他项目,wildfly-core提供了一个坚实的基础服务器架构。

  3. 提供servlet容器的发布包,方便开发人员开发和部署基于Servlet的应用,而不需要部署在完整的JavaEE应用服务器之上。

  4. 重新构建安全基础架构,使用Wildfly-elytron作为核心。

  5. 服务器挂起和优雅停机方案,极大的改进了可用性。

  6. 基本安装对外端口减少为两个:应用端口和管理端口,适应云端的需求。

  7. 管理界面,cli控制台的加强和改进。

  8. 集群能力的提升

培训课程

庆祝JBoss应用服务器新版本的诞生,我们的应用服务器培训课程也进行了范围扩展和内容更新,主要分为以下几大部分:

1. JavaEE规范(I)

  • 1.1 整体综述

  • 1.2 Servlet/JSP/MVC

  • 1.3 JaxRS

  • 1.4 JaxWS

  • 1.5 Websocket

  • 1.6 JPA/JDBC

  • 1.7 事务

  • 1.8 JMS

  • 1.9 BV

2. JavaEE规范(II)

  • 2.1 EJB

  • 2.2 CDI

  • 2.3 JNDI

  • 2.4 安全

  • 2.5 JSF

  • 2.6 Concurrency和规范中的异步改进

  • 2.7 JCA和集成

  • 2.8 JCache

  • 2.9 JBatch

3. Wildfly-core核心部分

  • 3.1 JBossModule

  • 3.2 MSC

  • 3.3 控制器和管理接口

  • 3.4 Server以及服务器启动过程分析

  • 3.5 部署框架以及war/ear部署过程

  • 3.6 子系统,挂接到服务器上和开发自己的子系统

  • 3.7 域模式

  • 3.8 WebConsole开发原理和扩展方式

  • 3.9 JBossThread,线程池调优

  • 3.10 XNIO和JBossRemoting

  • 3.11 安全基础模块

  • 3.12 JBossLogging框架和系统对中文的支持

  • 3.13 服务器调优和GC/Heap分析

4. Wildfly应用服务器实现部分(上游项目和集成)

  • 4.1 服务器整体分析

  • 4.2 数据连接池实现分析和调优,JCA上游项目Ironacamar

  • 4.3 Undertow,Web容器实现,对Websocket和HTTP/2支持

  • 4.4 集群和容错能力分析,上游项目Infinispan和mod_cluster

  • 4.5 NamingServer的实现分析

  • 4.6 Resteasy,Rest实现

  • 4.7 Hibernate,JPA规范实现

  • 4.8 Weld,CDI规范和Spring框架比较性分析

  • 4.9 ActiveMQ,JMS实现

  • 4.10 CXF,Webservice实现

  • 4.11 EJB3规范的实现分析

  • 4.12 Narayana事务能力的支持

  • 4.13 PicketBox和BouncyCastle安全方面的实现

这次更新后的培训内容更加全面的覆盖了基于JavaEE应用服务器的整体架构和各个技术规范的知识点,对于项目的技术选型,设计,开发,部署,都会有极大的参考价值。

JBossAS7时,我们是一个团队,如今虽然有一些成员离开,但有更多开发人员加入。社区依然活跃,开源精神指引着技术前方的道路!

培训材料演示文件地址

如何给Wildfly提交PR

18 July 2015

我经常听到一些朋友说很难给JBoss开源社区提交代码,事实上的确如此,带有redhat或者jboss的邮件地址的贡献者会有优势,但代码质量和补丁描述才是最关键的。开源社区也有不同的文化,JBoss属于相对紧凑型的,简单来说开源贡献者需要适应JBoss的一些约定和规则。

这篇文章是前几天David M.Lloyd发到wildfly邮件列表的。原文在此 http://lists.jboss.org/pipermail/wildfly-dev/2015-July/004243.html

David目前是wildfly的总架构师,可以说从AS7以后的JBoss应用服务器产品的基本架构是他奠定的。David在多个项目上都体现出超凡的能力,如JBossRemoting, JBossLogging, XNIO, MSC, JBossModule等等。

这篇文章是难得的好文,指点如何给JBoss社区提交PR,包含一些规则和窍门。我把它翻译过来供大家参考。同时也是给其他开源社区贡献的参考资料。

如何给Wildfly提交PR(PullRequest)

自从代码管理迁移到Git以来,以及采用了审查为导向的贡献体系(contribution structure),对于wildfly和相关的开源项目,我们都已经看到了巨大的提高,包括质量和数量方面。然而,尽管我们已经写了很多文档,包括如何获取源码,进行修改,使用git创建分支,提交PR等等。但还没有讨论过如何比较标准的进行实际构建(actually build)和结构化PR请求(structure pull requests),这就是写这篇文章的目的。

有几个做这件事的原因:

首先,审查者人数现在很少。这样有几个不好的效果:

  • PR在审查队列中周期很长

  • 巨型PR获得的审查机会比小的PR还少

  • PR得到的审查质量及其不稳定

其次,我们看到各种有问题的RP请求,比如单一大文件无法审查的PR,成千小文件PR,混合了表单和函数各种功能改进的PR,还有一些隐蔽的情况,你如提交之间让编译失败的PR。

第三,项目已经发展到了一定的规模和范围,我们需要有更多的人手盯紧每一个变化-实际只能做到尽可能多的。

为此,借用Linux内核项目文档[1]中的一些概念,来制定以下的PR标准。 (关于如何开始给wildfly贡献代码,黑客指导(the hacking guide)[2]依然是最好的文档)

Wildfly贡献和提交PR标准

我们为wildfly和相关子项目,制定一些重要git提交的规则和准则。但不是完整的git教程,因为那样会超出本文的范围。

1) 充分的描述PR请求内容 描述应当包括JIRA编号,从而可以找到相关的相关的问题描述。描述语句恰当的,用人类易读的语言总结修改的内容。正确的拼写和语法是加分项。

2) 首先要保证编译和测试通过

当审查者花了大量时间去审查代码,发现其甚至不能编译时,他们会很恼火。经常会看到提交patch来通过checkstyle代码格式检验。 有时我们会依赖自动化的CI/GitHub功能来进行编译和测试。但这样通常会带来麻烦,所以不要这样做!

3) 分解变更内容—​但也不要分的太多

直接引用[1],我百分之百同意:

“将每个变化逻辑(logical change)划分为一个单独的补丁

“例如,如果你的改动是为一个驱动程序所写,包括bug修复和性能增强,那么划分为两个或者以上的补丁。如果改动包括API更新,及使用新API的驱动,划分为两个补丁。

“另一方面,如果你一次修改动了大量的文件,那么把这些改动划分在一起,这样一个补丁中包含逻辑变化所有修改。

“关键要记住,每个补丁应当让审查者很容易理解和验证。每个补丁的作用正当有理。

“一个补丁依赖于另一个补丁来保证完整性是可以的,需要在提交时注明‘这个补丁依赖于补丁X’。

“当你划分修改为一系列补丁,要特别注意确保wildfly可以在每个补丁后可以正确的编译和运行。有时开发者使用’git bisect’来追查问题,到你的一系列提交时没法继续时,他们可能会骂娘。

我想强调区分“功能”和“非功能”的改变非常重要,后一类包括格式化工作(建议没有必要的原因就不要做)

4) 避免大规模的分支和/或意识流"stream of consciousness"分支

我们知道开发是一个反复迭代的过程。尽管如此,我们并不需要记录完整的历史(比如在一次PR中先有"add foobar"紧跟着"remove foobar")。特别是对于大的变化或者大的项目(如wildfly)。一个好的实践是提交者重新审视提交,重新排列和结构化提交改变,只包含对于主干增量变化。

如果PR包含上百个普通提交,那么强烈建议分割成多个PR,每个PR的大小方便进行高效审查。如果太大了,审查者要么是没有进行足够的审查就匆忙合并,要么就忽略掉甚至直接关掉。你可以设想哪种情况更糟糕。

5) 重视和响应审查意见

虽然是我的经验,但wildfly贡献者都赞成这点。我直接引用[1]的内容

“你的补丁几乎肯定能得到来自审查者的意见,告知如何改善,你比如回应这些意见,忽略意见的结果一般就是PR被忽略。

“一定要告诉审查者你做的修改,并感谢他们投入的时间。代码审查是一项累人费时的过程,审查者有时会脾气暴躁。即便如此,也要礼貌和解决他们指出的问题”

此外,当需要进行修改时,正确的方式是修改原始提交,而不是在其之上进行添加。参考(4)内容。

6) 不要气馁

在PR接受前,多次迭代提交是很正常的,它总有机会通过审查。不要气馁—​反而这是好的现象,说明审查者高度关注代码库质量。同时,也要考虑审查者已经一遍遍反复说了同样提交意见,所以也请关怀他们,尽可能高质量提交,参考(5)。

7) 你也可以审查代码!

你不必成为正式的审查者,也可以审查PR。如果看到熟悉的领域,尽管去检验和进行注解来帮助评审。另外,所有的PR都需要进行基本审查保证非机器检验的正确性,如注意到糟糕的代码,NPE风险和运用反模式,还有无聊的拼写,语法和文档。

8) 针对重大重构

当遇到重大和长期重构时,上述限制变得不切实际,尤其是划分变化。这时,你可以使用一个工作分支来应用上述的规则。同时可以也提交给审查者。周期性的一段时间后,合并提交到上游分支上。

运用这种方式,当长期分支准备合并到主干“回家”时,审查者已经对大多数改变进行过评审,从而更容易通过。

北京JBoss User Group活动,JBoss社区迎接微服务

10 June 2015

6月10日晚上,在融科红帽研发中心办公室,举办了JBug 2015年第一次活动。主管JBoss应用服务器部门的Bruno做了主题演讲。Jim Ma 和我分别做了JBoss相关产品和项目在微服务设计的分享。 活动连接

wildfly swarm是一个最新的项目,借鉴了SpringBoot的优秀思路,利用wildfly-core和wildfly,可以快速编写符合微服务思路的应用程序。目前wildfly-swarm还在积极开发中。

这里是演示文档。

永源中间件完整拼图

31 May 2015

永源中间件课程设计的目标是完整的中间件开发体系,以Java为主力语言,配合JavaScript, Go, Ruby等语言发挥各自领域的优势。 目前已经推出四批共25门课程,还有7门正在设计中,欢迎软件领域朋友们参与和帮助完善。

Useopen Training

永源中间件第四批课程

30 May 2015

我们推出了第四批课程。包括:Glassfish应用服务器分析;Vertx3开发框架快速开发异步高并发应用;测试相关开源软件的使用;业务流程管理的定义和开源项目使用;移动后端服务的使用。欢迎大家关注并多提出宝贵意见。

第三批课程共5门:

Glassfish

Glassfish是JavaEE的参考实现,尽管Oracle不再提供商业服务支持,但良好的架构设计值得学习,payara是一个延伸出来有商业支持的产品。深入讲解Glassfish应用服务器核心技术,源码级分析,有助于开发/部署/和从Weblogic进行迁移。
授课时长 1-2天

Vertx3

Vertx 3经过重新设计和开发,利用Java8的函数式能力焕然一新。Vertx借鉴NodeJS的设计思路,充分发挥了Netty网络框架的威力,目前异步高并发,移动应用越来越多,Vertx的能力会得到充分发挥。
授课时长 1-2天

Testing

测试是开发过程中及其重要一环,软件的测试有单元测试,集成测试,回归测试等等。持续测试通过是保证软件质量的重要方法
授课时长 1-2天

BPM

业务流程管理(工作流)系统是企业软件开发过程中经常用到功能。商业过程需要多个业务人员,多种角色协同工作。如果对商业过程进行建模,已经用软件有效管理,成为企业管理软件的重要目标。
授课时长 2-3天

MBaas

移动时代到来,开发手机APP需要和后台服务进行交互,面向移动应用的后端服务可以帮助开发者,快速开发和部署移动应用。
授课时长 1-2天

永源中间件第三批课程

31 March 2015

我们推出了第三批课程。包括一门基础课程:DDD领域驱动设计。以及JavaEE范围内的命名服务和配置服务,安全(主要是认证和授权),以及JSF和GWT的课程。另外有针对日志和搜索的课程,构建和持续交付课程。还有一门是企业应用中经常用到的ESB。欢迎大家关注并多提出宝贵意见。

到现在已经公布了共20门课程,这些课程已经可以较完整覆盖了中间件开发领域技术,特别是和JavaEE相关。接下来我们会深化细化这些课程内容,和广大开源爱好者共同学习和提高。

第三批课程共7门:

Domain Driven Design

讲解领域驱动设计的概念,实现方法。DDD领域驱动设计是目前企业应用设计的最佳方法,经过10多年体系知识的不断完善和编程语言的改进适配,如今已经可以很有效的指导复杂的企业应用的设计开发过程。本课程同时对CQRS(命令查询职责分离模式),DCI(数据Data 场景Context 交互Interactions)等相关知识进行讲述。
授课时长 2-3天

Naming & Configuration

设计简单的应用程序,也需要分析处理配置文件,运行时状态可以注册到命名服务中,供其他程序使用。在当前云计算化趋势下,配置和命名服务的集中管理变得非常重要。本课程就围绕相关概念和开源项目,分析和讲述
授课时长 1-2天

JavaEE Security

安全是企业软件的重要组成部分,尤其在云计算时代,软件系统安全是需要重点关注的问题。认证和授权部分是企业软件开发中最主要的两个部分
授课时长 1-2天

JSF & AngularJS

JSF是目前JavaEE的表示层技术,在企业软件中大量使用,但不被广大开发者熟悉。本课程讲解JSF的内容,并分析如何同其他JavaEE技术如CDI结合使用。
AngularJS是Google出品的基于JavaScript的前端框架。
GWT是Google出品的Java语言转成JavaScript在浏览器展现的优秀项目
授课时长 1.5-2天

Logging & Searching

记录系统日志是企业软件必不可少的功能,是查找问题,分析排错的主要方式,也是大数据信息的主要来源。如何高效的记录和分析日志已经成为企业互联网应用的重点之一。海量信息通过搜索的方式查询,企业数据也有搜索引擎。
授课时长 1-2天

Building & Continuous Delivery

软件应用的设计开发周期越来越紧迫,系统交付需要一种可控的方式管理。软件代码编写后,如何进行构建,测试,发布,业界有一套实践可行的方案。
授课时长 1-2天

ESB

企业在运营中产生各种信息,如何通过软件平台传输,共享这些数据。ESB(Enterprise Service Bus)企业服务总线是一类产品的统称。可以方便的抽取企业信息,进行转换,处理,过滤后发布成webservice,供其他应用使用。
授课时长 1.5-2天

RPC框架性能基本比较测试

21 March 2015

gRPC是Google最近公布的开源软件,基于最新的HTTP2.0协议,并支持常见的众多编程语言。 我们知道HTTP2.0是基于二进制的HTTP协议升级版本,目前各大浏览器都在快马加鞭的加以支持。 我们可以设想一下,未来浏览器支持HTTP2.0,并通过现有开源序列化库比如protobuf等,可以直接和各种语言的服务进行高效交互,这将是多么“美好”的场景!

gPRC的Java实现底层网络库是Netty,而且是用到最新的Netty5.0.0.Alpha3的开发版本,因为最新版本针对HTTP/2做了很多改进。 为了跨语言,gPRC也和其他方案一样,采用了类似古老IDL的接口描述语言,利用自家的Protobuf项目带的protoc编译器来生成框架代码。这和目前最流行的Facebook开源的,现为Apache顶级项目的Thrift原理一致。

我比较好奇,这个新出世的框架的性能怎么样,和现有的RPC开源方案比较如何。就花了一些时间进行简单比较。 我选择了以下五种开源项目进行测试:gRPC, Thrift, Wildfly, Dubbo, JBoss EAP。 为了简化,测试范例都使用项目自带的demo或者sample等进行简单修改,使得跨进程网络调用次数一致。

gRPC https://github.com/grpc/grpc

  1. 从Github master主干上获得最新版本,按照说明文件进行编译。如上所述,网络框架是Netty5,基于最新的HTTP/2.

  2. 测试例子为 RouteGuideClient

  3. IDL为 route_guide.proto

  4. 选择其中getFeature方法,去除不用的语句和屏幕输出,进行10,000次同步调用。

TestClientSync client = new TestClientSync("localhost", 8980);
try {
  final long startTime = System.nanoTime();

  for (int i = 0; i < 10000; i++)
    client.getFeature(409146138, -746188906);

  final long endTime = System.nanoTime();
  info("method 1 : " + (endTime - startTime));
}
public void getFeature(int lat, int lon) {
  try {
    Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build();
    Feature feature = blockingStub.getFeature(request);
  } catch (RuntimeException e) {
    logger.log(Level.WARNING, "RPC failed", e);
    throw e;
  }
}

多次执行,记录需要的时间。

gRPC还有一种非阻塞的调用方法,不过因为时间有限,为了简化测试,我只用标准的server启动的方式,asyncStub在大并发访问时出错,用时也较长,故这次测试没有这种方法的结果数据。

Thrift http://thrift.apache.org

  1. 从Apache网站获得最新的0.9.2版本,本机编译获得C的编译器和Java运行环境。

  2. 测试例子为 JavaClient.java

  3. IDL tutorial.thrift

int diff;
final long startTime = System.nanoTime();
try {
  for (int i = 0; i < 10000; i++)
     diff = client.calculate(1, work);
} catch (InvalidOperation io) {
  System.out.println("Invalid operation: " + io.why);
}
final long endTime = System.nanoTime();
System.out.println("method 1 : " + (endTime - startTime));

Thrift采用经典的基于网络端口的RPC,效率最高,在最后的总结数据可以看到。

Wildfly 8.2.0 http://www.wildfly.org

Wildfly是JBossAS改名后的JBoss应用服务器,实现了完整的JavaEE规范。我们知道JavaEE中远程RPC调用是在EJB规范中定义的。我们这里就是要测试Wildlfy中的远程EJB调用能力,

  1. 选用的Wildfly8.2是目前发布的最新稳定版本。这个版本也支持端口多路服用,也就是EJB远程调用是通过HTTP端口复用来进行的,利用HTTP的Upgrade机制做到二进制运行时刻协商升级。尽管不是纯粹的HTTP/2,但也运行机理也相差无几。

  2. 测试例子选用jboss-eap-quickstarts项目中的远程ejb调用例子 RemoteEJBClient.java

  3. 纯Java的RPC方案好处是不需要再有IDL文件定义和编译生成代码的过程,只要商议好接口就可以了

public interface RemoteCalculator {
    int add(int a, int b);
}
int sum=0;
final long startTime = System.nanoTime();

for (int i = 0; i < 10000; i++) {
         sum = statelessRemoteCalculator.add(a, b);
}

final long endTime = System.nanoTime();
System.out.println("method 1 : " + (endTime - startTime));

调用无状态的SessionBean方法10,000次,对应的远程EJB服务是部署在Wildfly应用服务器中的EJB。

Dubbo 2.5.4-SNAPSHOT https://github.com/alibaba/dubbo

Dubbo是阿里集团开源的一个极为成员的RPC框架,在很多互联网公司和企业应用中广泛使用。协议和序列化框架都可以插拔是及其鲜明的特色。同样的远程接口是基于Java Interface,并且依托于spring框架方便开发。可以方便的打包成单一文件,独立进程运行,和现在的微服务概念一致。

  1. 采用github中master主干,目前版本是 2.5.4-SNAPSHOT

  2. 测试例子选用其中的demo进行修改 DemoAction.java

public interface DemoService {
	String sayHello(String name);
}
final long startTime = System.nanoTime();

for (int i = 0; i < 10000; i ++) {
    try {
    	String hello = demoService.sayHello("world" + i);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
final long endTime = System.nanoTime();
System.out.println("method 1 : " + (endTime - startTime));

调用完毕后查看输入log文件获得运行时间。

EAP是JBossAS的商业版本,实现了完整的JavaEE规范。

  1. EAP6基于AS7.2以后的版本构建,红帽提供商业支持。

  2. AS7在7.2以后,社区版没有再发布,具备能力的企业可以从源码进行编译使用,EAP6.3基于AS7.4分支构建,很快发布的EAP6.4基于AS7.5分支构建,不出意外这个会是最后一个EAP6的minor版本。

  3. AS7还没有像Wildfly完全采用端口复用的方式,短程EJB调用通过独立端口完成,基于JBossRemoting3的网络连接管理能力。

  4. 测试例子依然选用jboss-eap-quickstarts项目中的远程ejb调用例子

public interface RemoteCalculator {
    int add(int a, int b);
}

记录一万次调用后的时长。

数据结果。

最终经过4轮测试,不间断运行10,000次远程RPC调用后的结果如下:

RPC benchmark

我们可以看到Thrift的效率最高,大概领先一个数量级。而其他三个项目的性能数据在同数量级中,由高到低分别为JBossEAP, dubbo, wildfly和gRPC。

需要说明的有以下几点:

  1. 为了简化测试,我并没有选择同样的调用接口,而是顺手用了项目自带的,方便修改的示例程序。其中gRPC和Thrift的接口有对象传递,稍微复杂一些。

  2. 不是严格的性能测试流程,比如没有做预热过程,以及测试都运行在我的桌面用机上,没有完全恢复成“干净”的状态。

  3. 都是简单的服务器单一进程实例,标准示范例子,没有做特别优化和设置多个线程池之类的。而客户端调用也是最简单的阻塞式多次调用压力测试。应该是用多个机器多连接,多个线程,以及异步非阻塞的调用多种环境进行测试更为客观,有机会再继续完善。

  4. 之前没有看到过基于HTTP/2的RPC调用性能比较,理论上是应该低于经典的基于端口的RPC方案的。这个测试结果可以简单印证这个猜想。Thrift的数据遥遥领先.gRPC还在开发之中,基于的Netty还是alpha版本,而且非阻塞的方式还没有最后的数据。我想耐心一些,给gRPC一些时间,它会让我们惊艳的。

  5. Wildfly表现良好,要知道它的服务端可是完整的JavaEE服务器啊。不过有时间的化,我试试看经典RMI连接的效率如何,要是能和thrift一个数量级就更好了。

  6. dubbo性能也很出色,而且协议层可以更换的话,应该还能有更大提升。

  7. 我的测试在一台过时的笔记本上,受条件限制,没有先进的G级网络和多台服务器进行标准化性能测试。如果哪位在互联网或者企业工作的朋友有条件,也愿意充分完成这个测试,请和我联系,我会完整介绍我的测试搭建环境,共享代码,并帮助完成。我想那个结果会更有意义。

补记

  1. 最初四个测试时间为2015-03-11,03-21加入EAP6.3.2的测试,为基于JBossRemoting的EJB远程调用测试,性能良好。和thrift进入一个数量级,EJB功能可是很丰富的,带有事务,安全等高级企业级组件特性。

  2. Wildfly8经过配置后使用和EAP类似的远程调用选项,效率和EAP应该是一致的。

永源中间件第二批课程

18 March 2015

我们推出了第二批课程。包括互联网应用常用的服务:消息中间件和缓存中间件的课程。三门基础课程:线程/集合,NIO,RPC。以及经典的WebService,讲述SOA思想和JaxWS。欢迎大家关注并多提出宝贵意见。

第二批课程共6门:

Message & JMS

讲解消息机制和设计原则,消息提供的排队机制是处理高并发的基本方式。学习JMS规范API接口,并深入分析常见JMS服务器实现HornetQ, ActiveMQ,以及AMQP协议介绍和QPid实现分析。
授课时长 1.5-3天

Cache

讲解缓存机制和设计原则,缓存是解决大容量并发访问的利器。企业开发逐步面向互联网和移动用户,缓存技术成为企业应用开发中重要角色,JCache将成为JavaEE规范成员。
授课时长 1-2天

Thread & Collection

讲解各种集合类型的特点,多线程编程,并发和并行等常见基础问题,为整个中间件体系的学习打下坚实基础。
授课时长 1-2天

Socket & NIO

讲解Java中网络编程的高级知识,各种异步通信框架,为整个中间件体系的学习打下坚实基础。
授课时长 1-2天

RPC

讲解RPC远程调用的编程知识和各种RPC框架,针对不同的应用场景选择适当的技术实现。
授课时长 1-2天

WebService & JaxWS

讲解Webservice的重要知识点和JavaEE中JaxWS规范,并对开源项目CXF进行深入分析。
授课时长 1-2天

你好,永源中间件

08 March 2015

经过多年的软件开发和对软件知识的消化,整理出一套中间件体系课程,和企业软件和互联网应用开发有密切关系。

其中包括:重点基础,JavaEE,Microservice,ApplicationServer,Enterprise,BigData,Cloud,Mobile等多个知识领域,每个领域包含若干门课程。

课程的知识点通过解答技术解决问题的本质提炼得出,辅助以当前最优秀开源软件进行技术讲解。

面向企业技术团队中高级技术人员授课,可以选择某一个领域一门课程,也可以根据企业需求进行定制。希望这套课程经过不断完善演进,成为世界级优秀的中间件技术课程。

目前推出第一批课程共7门:

Servlet & Web Container

讲解Web开发中最经典的Servlet技术,MVC设计模式,并深入分析常用Web容器
授课时长 2-3天

DI/CDI & EJB

开发者需要掌握面向对象开发模式,Ioc框架可以减化编程,便于测试。DI/CDI和EJB都是规范化的技术
授课时长 2-4天

JPA Persistent

讲解持久层常用技术,如何进行对象和关系数据库映射,介绍当前对Nosql的主要技术
授课时长 2-3天

Rest & JaxRS

讲解Restful网络服务接口设计方式,Java JaxRS规范内容,以及实现项目代码分析
授课时长 1.5-3天

SpringFramework

讲解经典Spring框架的设计原理和特性分析,SpringMVC是目前最有代表性的MVC框架
授课时长 2-3天

SpringBoot & SpringCloud

适应微服务时代,优秀项目SpringBoot和SpringCloud的组合使用,更适应云计算平台和互联网应用
授课时长 1-2天

JBossAS & Wildfly

深入讲解JBoss应用服务器核心技术,源码级分析,无论针对AS7,Wildfly和JBossEAP6都适用。帮助企业更好的理解JBoss开源应用服务器的特性,有助于开发/部署/迁移过程。
授课时长 2-3天