销售热线:

4000-900-632
科创致远软件 > 新闻中心 > 行业新闻 >

Java NIO通信框架在电信领域的实践

1. 华为电信软件技术架构演进

1.1. 电信软件

从广义上看电信软件的范围非常广,细分实际可以分为两大类:系统软件和业务应用软件。

系统软件包括路由器底层的信令机软件、手机操作系统等,业务应用软件主要包括客户关系管理CRM、网上营业厅、融合计费OCS和各类消息网关,例如短信网关、彩信网关等。

本文重点介绍电信业务应用软件的技术变迁历史,以及华为电信软件架构演进和Java NIO框架在技术变迁中起到的关键作用。

1.2. 华为电信软件的技术演进史

1.2.1. C和C++主导的第一代架构

 

在2005年之前,华为软件公司的核心系统主要以C和C++进行开发,由于C和C++开源框架非常少,加之那个时代开源社区并不成熟,大部分的系统都采用自研开发,包括协议栈、系统调度、数据访问层和日志。

大多数的软件都运行在服务端,对外提供高性能、低时延和高并发的系统调用,协议栈大多数都采用电信私有协议栈,对于部分有前台管理Portal的系统,往往基于原生的HTML或者Struts等WEB框架开发,通过HTTP协议与后端进行交互,它的逻辑架构图如下:

 

图1-1 华为电信软件V1版逻辑架构图

在那个时代,电信软件绝大多数都部署在高性能的小机中,处理各种信令、电信私有协议的接入和解析、复杂业务逻辑处理,系统对处理性能、时延、多核处理的要求非常高。当时Java主流版本还是JDK 1.4.2(1.4.X),它在传统的Web应用、电子商务网站和政企系统中得到了比较广泛的应用,但是在电信领域并没有大的应用,主要原因如下:

1) 在JDK1.5之前的早期版本中,Java在多线程编程、并行处理等方面能力很差,无法在电信软件服务器端使用;

2) JDK 1.4.X对非阻塞I/O的支持并不好,相关NIO编程的可参考资料和开源框架很少,传统的阻塞I/O模型在电信高性能、高可靠场景中力不从心;

3) 业界很少有Java高性能服务端处理成功的案例,大家普遍对Java 支持电信级应用场景持怀疑态度;

4) 那个时代电信领域的开发者都是C/C++出身,大家对新技术和语言有种天生的排斥。

2005年之后,随着Java在各领域的快速普及和应用,以及基于Java的各种开源框架井喷式增长,华为越来越多的产品开始尝试切换到Java进行开发,主流架构随即演进到了以Java为主的V2版本。

1.2.2. Spring + Struts + Tomcat 的第二代架构

2005年-2008年间,华为电信软件大多数产品线都切换到Java语言进行新产品的设计和开发,当时随着Struts的MVC模式以及Spring对J2EE复杂企业应用对象生命周期的配置式管理的流行,华为电信软件绝大多数产品采用基于Spring + Struts + Tomcat模式进行开发,数据访问中间件主要采用iBatis和Hibernate,它的逻辑架构如下所示: 

图1-2 华为电信软件V2 MVC版逻辑架构图

切换到以Spring + J2EE容器为基础技术框架之后,应用开发的难度迅速降低,开发效率获得了极大提升。短短1-2年时间,公司大多数以C/C++的项目切换到了Java语言和V2 架构上。

1.2.3. 以SOA为中心的第三代架构

当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。

随着电信业务的快速发展,电信原有系统和新建设系统之间存在语言、协议、运行环境等诸多差异。如何整合异构系统,实现高效企业集成,也是一个巨大的挑战,此时,企业服务总线(ESB)是个不错的选择。

为了满足电信业务的需求,华为软件研发了SOA中间件,它的逻辑架构图如下:

图1-3 以SOA服务化为核心的V3架构

SOA是一种粗粒度、松耦合的以服务为中心的架构,接口之间通过定义明确的协议和接口进行通信。SOA帮助工程师们站在一个新的高度理解企业级架构中各种组件的开发和部署形式,它可以帮助企业系统架构师以更迅速、可靠和可重用的形式规划整个业务系统。相比于传统的垂直架构,SOA能够更加从容的应对复杂企业系统集成和需求的快速变化。

1.2.4. 以分布式、云化为核心的第四代架构

随着业务的不断发展,硬件成本的下降,基于X86架构的廉价硬件 + 分布式软件的模式在互联网行业得到了大规模应用,分布式架构日趋成熟。

从运营商业务看,尽管高性能的小机仍然是标配,但是运营商业务向数字化转型和云化降成本逐渐成为一种趋势。

传统SOA架构中的一些缺陷逐步暴露,例如企业集成总线ESB是实体总线,性能线性扩展能力有限;硬件负载均衡器的压力越来越大,不断扩容导致硬件成本增加;随着业务规模的不断增长,传统的数据库、配置中心等逐渐成为单点瓶颈等。

我们需要通过新的分布式架构来解决电信软件面临的成本高、性能无法线性增长等问题,以分布式技术为核心构建的华为分布式中间件应用而生,它主要包括如下组件:

1) 高性能、低时延的分布式服务框架;

2) 分布式消息队列MQ;

3) 分布式缓存;

4) 分布式数据库访问中间件,支持跨库操作,支持异构数据库;

5) 软负载SLB;

6) 分布式日志采集和检索(Flume + ELK);

7) 分布式实时流式计算框架;

8) 分布式消息跟踪系统;

9) 其它......

自从亚马逊的云计算服务面世以来,云计算技术作为应对笨重的传统IT架构的战略,已经成为越来越多的政府和企业的选择, “云”已经成为ICT技术和服务领域的“常态”。

运营商基础设施云化的主要原因如下:

1) IT资源规模比较大,如何高效的使用这些设备,提升效率,虚拟化是个不错的选择;

2) 资源的孤岛现象是比较严重,大部分IT系统,依然采用传统的竖井式的建设模式,IT系统的资源无法在跨系统间进行共享,同时因为各系统建各系统的特点,使得资源的利用率非常低,各个业务有峰值的时候,虽然业务之间峰值不在一块,但是依然起不到消峰的作用,占用的资源比较大;

3) 系统的压力也是不均衡,资源由于没法共享,只能采用被动的采购,使得更大容量的设备采购,来应付电信业务增长所需要的扩容;

4) 系统部署的周期长、运维也比较难。

为了满足运营商云化的需求,华为相继研发了IaaS、PaaS等用于支撑运营商IT和基础设施云化,下面让我们一起看下华为软件云化后的逻辑架构:

图1-4 以分布式、云化为核心的V4架构

第四代技术架构以分布式、云化为核心,相比于前三代架构,它的核心特性如下:

1) 采用分布式技术构建,所有的中间件都没有单点,支持线性增长和弹性伸缩;

2) 以微服务架构为核心,打造电信领域的DevOps(结合华为PaaS平台);

3) 由传统的SOA Governance 向微服务治理和自治演进,提升服务治理效能;

4) 分布式日志采集 + 实时流式计算框架,更快的故障定界,提升大规模、分布式系统中的运维效率;

5) 业务和数据的拆分,分而治之,通过分布式中间件服务向业务屏蔽拆分细节;

6) 架构云化带来的巨大优势:资源池提升硬件利用率、DevOps提升开发和运维效率、应用和服务的自动弹性伸缩、应用和服务故障自动恢复、高HA、自动化运维等。

1.3. 架构演进中的技术

随着架构的演进,Java的版本也在不断升级,技术堆栈不断更新,EJB、Spring、RMI、MQ、Node.js、NIO、Hadoop等。在众多技术堆栈中,我印象最深的就是Java的NIO类库以及业界成熟NIO框架的使用,它在华为软件架构演进中发挥了重大作用,曾立下了汗马功劳。现在,以Netty为代表的NIO框架已经在华为平台产品和业务产品中得到了广泛的应用。

作为华为软件公司最早使用Java NIO技术进行平台开发、2009年即在全球商用成功的亲历者和实践者,我想跟大家分享下Java NIO框架在华为软件以及电信领域的应用和实践。

2. Java NIO 技术的引入

2.1. BIO带给我们深深伤痛

在2008年的时候,我参与设计和开发的一个电信系统在月初出帐期,总是发生大量的连接超时和读写超时异常,业务的失败率相比于平时高了很多,报表中的很多指标都差强人意。后来经过排查,发现问题的主要原因出现在下游网元的处理性能上,月初的时候BSS出帐,在出帐期间BSS系统运行缓慢,由于双方采用了同步阻塞式的HTTP+XML进行通信,导致任何一方处理缓慢都会影响对方的处理性能。按照故障隔离的设计原则,对方处理速度慢或者不回应答,不应该影响系统的其他功能模块或者协议栈,但是在同步阻塞I/O通信模型下,这种故障传播和相互影响是不可避免的,很难通过业务层面解决。

受限于当时Tomcat和Servlet的同步阻塞I/O模型,以及在Java领域异步HTTP协议栈的技术积累不足,当时我们并没有办法完全解决这个问题,只能通过调整线程池策略和HTTP超时时间来从业务层面做规避。由于我们的系统是一个全国级的一级系统,需要对接周边各个网元,同时服务器资源十分有限,即便采用了高峰期间动态修改超时时间、优化线程池模型等多种措施,效果依然差强人意。

每当跟客户开会的时候,客户总会提起这个话题:别人响应慢,为啥会导致你的系统阻塞呢,可以返回处理其它消息啊?!我无法跟客户解释技术细节,因为同步阻塞I/O仅仅是Java I/O的一种实现,操作系统支持非阻塞I/O和异步I/O。

站在技术的角度,客户的需求是合理并且也是可以实现的,当时受限于经验以及其它技术原因,我们无法从根本上解决客户提出的问题,团队有种深深的挫败感,Java BIO同步阻塞通信导致的各种问题给我留下了一些心理阴影,一直挥之不去。

2.2. BIO模型存在的问题

传统同步阻塞通信面临的主要问题如下:

1) 性能问题:一连接一线程模型导致服务端的并发接入数和系统吞吐量受到极大限制;

2) 可靠性问题:由于I/O操作采用同步阻塞模式,当网络拥塞或者通信对端处理缓慢会导致I/O线程被挂住,阻塞时间无法预测;

3) 可维护性问题:I/O线程数无法有效控制、资源无法有效共享(多线程并发问题),系统可维护性差

传统同步阻塞通信的处理模型图如下:

图2-1 同步阻塞通信模型处理模型图

从上图我们可以看出,每当有一个新的客户端接入,服务端就需要创建一个新的线程(或者重用线程池中的可用线程),每个客户端链路对应一个线程。当客户端处理缓慢或者网络有拥塞时,服务端的链路线程就会被同步阻塞,也就是说所有的I/O操作都可能被挂住,这会导致线程利用率非常低,同时随着客户端接入数的不断增加,服务端的I/O线程不断膨胀,直到无法创建新的线程。

同步阻塞I/O导致的问题无法在业务层规避,必须改变I/O模型,才能从根本上解决这个问题。

2.3. 历史性的引入Java NIO

2.3.1. Java NIO被冷落的原因

从2004年JDK1.4首次提供NIO 1.0类库到现在,已经过去了整整10年。JSR 51的设计初衷就是让Java能够提供非阻塞、具有弹性伸缩能力的异步I/O类库,从而结束Java在高性能服务器领域的不利地位。然而,在相当长的一段时间里,Java的NIO编程并没有流行起来,究其原因如下。

  1. 大多数高性能服务器,被C和C++语言盘踞,由于它们可以直接使用操作系统的异步I/O能力,所以对JDK的NIO并不关心;
  2. 移动互联网尚未兴起,基于Java的大规模分布式系统极少,很多中小型应用服务对于异步I/O的诉求不是很强烈;
  3. 高性能、高可靠性领域,例如银行、证券、电信等依然以C++为主导,Java充当打杂的角色,NIO暂时没有用武之地;
  4. 当时主流的J2EE服务器,几乎全部基于同步阻塞I/O构建,例如Servlet、Tomcat等,由于它们应用广泛,如果这些容器不支持NIO,用户很难具备独立构建异步协议栈的能力;
  5. 异步NIO编程门槛比较高,开发和维护一款基于NIO的协议栈对很多中小型公司来说像是一场噩梦;
  6. 业界NIO框架不成熟,很难商用;
  7. 国内研发界对NIO的陌生和认识不足,没有充分重视。

基于上述几种原因,NIO编程的推广和发展长期滞后,特别是国内,在2009年的时候,几乎无法搜到国内企业成功使用NIO技术的案例。

2.3.2. 华为软件引入Java NIO的原因

从2008年开始,华为软件研发了Java版的业务网关,并迅速占领国内外市场。随着产品的推广,在一些高并发、大业务量的局点相继出现了几起事故,质量回溯的结果都指向了Java BIO通信模型,包括Servlet 2.X的同步阻塞I/O、Tomcat 5.X(当时没使用5.5)的同步I/O、以及其它的同步I/O协议栈。

问题根因已经很清楚,如果不改变同步I/O通信模型,问题会继续发生,对于运营商而言,这是不可能接受的事情。自古华山一条路,即然业界没有成熟的异步I/O协议栈,那我们就自研。

2009年初,由于对技术的热爱,我作为业务骨干被领导派去参加异步高性能网关平台的研发工作,与两位资深的架构师(其中一位工作20年,做华为交换机出身)一起合作。这是我第一次全面接触异步I/O编程和高性能电信级协议栈的开发,眼界大开——异步高性能内部协议栈、异步HTTP、异步SOAP、异步SMPP……所有的协议栈都是异步非阻塞模式。

后来的性能测试表明:基于Reactor模型统一调度的长连接和短连接协议栈,无论是性能、可靠性还是可维护性,都可以“秒杀”传统基于BIO开发的应用服务器和各种协议栈,这种指标差异本质上是一种技术代差。

2009年底,基于异步网关平台研发的XX业务产品在海外某运营商成功上线,它的高性能、低时延和高HA令局方惊叹不已,原来准备的20多台小机最后只使用了3台,为客户节省了一大把$。

2.3.3. 那些年我们踩过的NIO “坑”

在我从事异步NIO编程的2009年,业界还没有成熟的NIO框架,那个时候Mina刚刚开始起步,功能和性能都达不到商用标准。最困难的是,国内Java领域的异步通信还没有流行,整个业界的积累都非常少。那个时候资料匮乏,能够交流和探讨的圈内人很少,一旦踩住“地雷”,就需要夜以继日地维护。在随后2年多的时间里,经历了10多次的在通宵、凌晨被一线的运维人员电话吵醒等种种磨难之后,我们自研的NIO框架才逐渐稳定和成熟。期间,解决的BUG总计20~30个。

为了解决这些Bug,2年中我经历了10几个通宵,现在回想起来仍历历在目,特别是JDK epoll 空轮询导致的 CPU 100%,更是坑中之坑(JDK NIO类库的Bug),曾令多少产品中招,包括Mina、Netty、Jetty等著名开源框架。

产品方案 预约演示 价格咨询