我有一个习惯,接触到新概念、新技术出现后,就会探究他的前世今生、来龙去脉,正所谓“太阳底下没有新鲜事”,喜欢从对比中找到价值点,不如此就觉得理解不透彻,就觉得少了点什么。微服务的概念出现后,由于又有了服务这个词,大家往往和面向服务架构做对比,类似文章即便不是汗牛充栋,也可算作车载斗量。但由于SOA 架构是企业架构层面的一种方法,视角比较宏观(例如建设银行新一代系统就是采用SOA架构),再者SOA涉及的标准规范例如XML、SOAP、WSDL、UDDI、SCA/SDO等又偏重在互联互通的协议上,这种对比总觉得不对等,二义性很强。
我喜欢拿J2EE和微服务做对比,因为J2EE有一系列明确的规范,可以互相印证。J2EE出现在1998年(参见https://zh.wikipedia.org/wiki/Java_EE,维基百科的描写比百度百科准确很多),2006年以后改名为JavaEE,是Java企业版的意思,目前是JavaEE 7,明年应该有JavaEE 8,可惜现在关注的越来越少了。JavaEE既然是企业版(Enterprise这个词翻译成企业不一定合适,我觉得在英文里是一个组织的意思,政府机构也是Enterprise,是不是翻译成“单位”,哈哈),就必然支持分布式系统,很多微服务架构的要求,在JavaEE规范中都有涉及,参考JavaEE规范可以更容易的理解如何实现微服务架构。
让我们看一下JavaEE规范,和微服务架构做一个比较:
(为了写这篇文章,我第一次翻出了JavaEE 7规范,看着这些名词,唏嘘不已,不免感叹又一个时代过去了。)JavaEE规范涉及的内容很多,这里只对EJB、JNDI、Servlet、JSP、JMS、JTA等规范做一个对比说明。
1、从EJB这个失败的规范理解微服务的后端服务
说起JavaEE规范,要先从EJB(Enterprise Java Bean),他是一种用Java实现后端服务的规范。本来EJB是JavaEE中最重要的规范,但EJB出现后,人们一直诟病他过于复杂的使用方式,在Spring出现后,大家其实抛弃了EJB,虽然他自身做了很多改革,以至于EJB 3.0 后和Spring非常类似,然并卵… … 其实,EJB的设想还是很好的,他把后端服务分为会话Bean(Session Beans)、实体Bean(Entity Beans)、消息驱动Bean(Message Driven Beans)三种模式,前者又分为 无状态会话Bean(Stateless Session Beans)、有状态会话Bean(Stateful Session Beans),最初EJB完全是使用远程调用的,后来由于性能的原因,又加上了本地模式,上述四种EJB 都可以采用本地调用。结合微服务架构,我们来回顾一下:
EJB规范的目的在于为企业及应用开发人员实现后台业务提供一个标准方式,自动处理了诸如数据持久化、事务处理、并发控制、基于JMS的事件驱动、基于JNDI的名字和空间管理、基于JCE和JAAS的安全管理、应用服务器端的软件组件部署、使用RMI-IIOP协议的远程过程调用、将业务方法暴露为Web服务、以及如何将EJB部署至EJB容器当中,虽然这是一个不成功的尝试,但这些都是微服务架构需要考虑的问题。
2、JNDI:Java版的服务发现
Java命名和目录接口(Java Naming and Directory Interface),是Java的一个目录服务API,它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象,这个规范是JavaSE的一部分,而JavaEE建立在JavaSE之上,JNDI也是JavaEE一个重要的基石。上面的解释比较拗口,其实解决的是服务注册、发现和配置集中管理问题。看看JNDI的示例:
示例:服务查找
Context ctx = ...
Object obj = ctx.lookup("/MyDataSource");
示例:注册监听器,可用于监听配置的改变
NamespaceChangeListener listener = ...;
src.addNamingListener("x", SUBTREE_SCOPE, listener);
示例:监听器被触发,获得变更前状态
evt.getEventContext() == src;
evt.getOldBinding().getName().equals("x/y")
JNDI规范虽好,但我们最常用就是lookup一个DataSource,之所以这样我认为有几个原因:
3、Servlet:Java API网关
Servlet是用Java编写服务端程序的接口,在J2EE出现之前,服务端程序一般都是用CGI实现的, Servlet的出现让Java的服务端程序有了统一的模式。早期我们会把每一个响应请求的类都实现Servlet的接口,后来在很多框架中都把Servlet做成统一的入口,由框架进行分发,编程的时候就看不到Servlet了。Servlet一直在被广泛使用,在微服务架构中也可以被做为前端接入存在。
4、JSP:成功的服务端模板技术
JSP是一种把Java语言嵌入到静态页面,动态生成HTML或其他格式Web网页的技术标准,他解决了Servlet 生成Web网页比较麻烦的问题。JSP促进了很多框架的产生,不过在Ajax模式出现后,JSP的使用方式也发生了很大变化,前端更加趋向于客户端的渲染,而不是在服务端生成全部Web页面。现在用JSP/JSTL实现的越来越少了,但不意味着就退出了历史舞台。
微服务架构下前端有很多实现方式,JSP只是选择之一。我们曾经在全国产平台上做过测试(龙芯、麒麟等组合),由于国产芯片的计算能力不足,造成浏览器上的渲染速度不够,这时候前端动态渲染的效果很不好,反倒是传统JSP 在服务端生成Web页面的模式体验更佳。
5、JTA:分布式事务的尝试
Java事务API(Java Transaction API) 是在Java环境中,允许完成跨越多个XA资源的分布式事务。JTA的接口比较简单,但是实现起来却比较复杂,事实上很少有人尝试使用基于 XA 资源的分布式事务,JTA往往被框架(例如Spring)做为底层的本地事务接口,实现业务逻辑的事务一致性声明。在事务声明方面EJB作出了很大贡献,是他率先将Required、RequiresNew、Mandatory、NotSupported、Supports、Never这样的事务声明引入到Java的体系中,后来在 Spring 中被广泛大家使用了,而JTA正是这一实现的支撑。
在微服务架构中,本地事务还应该是这种方式,麻烦的是远程服务的事务。对分布式事务的实现方式,请参考我的同事田向阳《微服务架构下的数据一致性保证(一)》和刘相《分布式事务:不过是在一致性、吞吐量和复杂度之间,做一个选择》的文章,在此之上,我们也应该参考EJB或者Spring的方式,用事务声明的方式维护数据的一致性,当然这个声明会远远复杂于本地事务。
6、JMS:通过JMS看成功的JavaEE规范
Java消息服务(Java Message Service)是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。应该说JMS规范的使用还是很多的,是JavaEE中比较成功的一个规范,除应用服务器之外的很多消息系统也都支持这个规范(例如kafka)。
既然是一个很受欢迎的规范,对这个技术本身我没什么可说的,继续保持发扬吧,我想说的是,这个规范为什么做的好,受欢迎。究其原因是当时人们对于消息编程的理解比面向对象编程更加深刻,面向批处理编程、面向消息编程是在面向对象编程之前的状态,JavaEE规范的出现正是人们基于Java这样面向对象的语言实现企业应用的过程,这也证明严格的面向对象方式实现企业分布式应用并不是好的选择,在JavaEE规范中使用比较好的JSP、Servlet、JDBC、JMS等都不是面向对象的编程模式,JSP是模板式的、Servlet是请求响应式的、JDBC是面向结果集的、JMS是面向消息的。
7、从JavaEE部署规范看Docker与微服务架构的关系
JavaEE规范中,EAR、WAR、JAR的部署模式是大家最常见的方式,按照JavaEE的设想,每一个模块都是一个独立的可部署单元,前端界面、后端服务都是可以独立部署的,而应用服务器对多个模块进行统一管理。但是,由于JavaSE天然的缺陷,应用之间难以实现隔离,而应用对第三方类库的依赖也让多应用的管理变得难以接受。而Docker的到来既实现了应用的隔离,也加快了应用的部署。所以,我把Docker用在应用的部署上,用于解决JavaEE没有解决好的问题上。在我看来,Docker不是一个轻量级的虚拟机,他不应该仅仅用在替换虚拟机上,而是把他们之间的区分使用,把资源的分配、安全等问题交给虚拟机,而Docker象EAR一样做应用的打包工具,这样,把Docker部署在虚机上就不显的奇怪了,谁会对EAR部署在虚机上感到奇怪呢?
最后,我要说的是JavaEE规范建立在三层/多层应用架构体系之上(如下图左),但在数字化时代应用程序必须支持多个客户端渠道(例如,桌面,移动,社交),并且这些前端应用程序与后端服务交互(如下图右)。未来SOA仍然是企业架构的核心,但SOA的实现将从JavaEE的三层架构向轻量级的微服务架构演进,API是服务的接口,微服务架构则代表了提高敏捷性和可伸缩性的范例。我们提供的微服务应用平台,其实就是实现新一代的应用服务器:将中间件微服务化,将微服务工程化。
在下图上,我把微服务架构中与JavaEE规范对应的部分画出来,供大家在实现微服务时做参考:
关于作者
焦烈焱
EAII-企业架构创新研究院 常务理事
2001年加入普元信息,现任CTO,全面负责普元信息技术与产品的运营工作,公司技术发展战略的重要决策人。焦烈焱在企业技术架构研究方面有二十余年的经验,长期致力于分布式环境的企业计算、 SOA与云计算技术研究与实践。加入普元信息后组织完成一系列核心产品的研发工作,包括SOA应用平台、以BPM &/ESB为核心的业务集成平台、以复杂事件处理/数据治理/作业调度为核心的大数据平台,期间主持了中国工商银行、中国建设银行等多家大型企业技术平台的规划与研发。著有《SOA中国路线图—实施版》一书。