尝试超越xml处理性能的极限

近些年一直工作在电信行业应用集成领域,也有幸参与了国内外几个大型电信运营商的应用集成项目的架构设计工作,比较关注也参与了大部分的性能测试工作。恰巧今天与同事聊起关于EAI/ESB的性能话题,觉得其中有些问题很有趣,分享一下:

 

背景:

目前主流的企业级EAI/ESB(SOA)项目,包括主流厂商相关产品,往往清一色的以xml数据转换为核心。涉及主要技术包括xpath、xquery,及相关的xml解析器,如XmlBean,DOM等。使用xml的好处就不多说了,这已经是事实的标准,咱就谈谈其中的性能问题。

 

性能问题:

这里不讨论EAI/ESB产品功能设计的性能问题,只关注其中更为基础的技术引起的性能问题,因为这些基础操作往往在每次的请求及响应过程中被大量的使用。

 

在使用java构建具有极高性能要求的数据交换系统时(eai也罢,esb也罢),最终的性能瓶颈总会受制于CPU或内存使用率,甚至进行过无数次代码级调优之后(应用及框架代码达到一个极致的水平后,所有能够调整的代码全都调整过之后),性能也会止步于不甚理想的指标。当然,如果你就认为xml处理理应就是这么慢,或者你看到这样的指标还欢呼雀跃极为满意的话,那么你就不用往下看了,后边内容是写给追求极致的架构师或程序员的。

 

如果你仔细思考过高主频cpu的工作能力和最终得到的性能测试结果间的关系,相信你一定会对这个结果感到相当的震惊,这个处理竟是如此之慢,这是必须的!当然,如果你曾经制造过xml解析器或xpath解析器的话,你一定更深有体会。

 

两个现象:

当这类应用性能到达临界点时(这里假设瓶颈不是你应用自己的同步锁或其他外部资源io访问问题造成的),往往会发现cpu会非常高,cpu高其实来源于两个方面:

1. 真实的计算需求,比如xml的解析算法

2. GC相当频繁时,往往也导致cpu高居不下

 

这时候的性能调优,往往也只能针对虚拟机进行调整了,通过更加适当的设置堆结构、线程数和gc算法等,虽然通过jvm调整可以适当改善总体性能,但这时候已经不可能在数量级上有所改变了,其实仅属于微调。所以大部分的性能调整也都只得止步于此。

 

分析:

造成这种结果也是无奈的,由于xml解析及xpath/xquery引擎均依赖于第三方(厂商或开源),集成商几乎不可能也没能力对底层xml库进行修改,所以在进行了所有可能的代码调优、J2EE server调优、jvm调优、OS参数调优等使尽浑身解数后,也不得不接受这个结果。

 

当然这个结果是业界广泛接受的,不会受到争议,而容量扩展可以通过部署更多硬件的方式达成。

 

不过如果你有兴趣最求更高的性能或者更加绿色的方式,其实在底层所使用的xml库的选择问题上还是值得仔细斟酌一下的(当然如果你被锁定在特定厂商产品的技术集上的话那也没办法了,建议你也就从了吧)。

 

经验之谈:

总体来说,xml解析器的总体性能和内存使用率取决于解析算法以及xml的内存数据结构。

 

对于具体的xml解析器来说,最消耗cpu的操作是xml string->dom对象,最消耗内存的操作是dom对象->xml string,当然xml string->dom对象也比较消耗内存。个人测试过大部分主流的dom模型的toString操作,普遍内存消耗比较惊人,没仔细研究过他们的这些算法,但猜想可能主要是toString过程中,拼接操作会产生大量的垃圾对象,即使是使用了StringBuilder或StringBuffer来做,由于变长数据结构容量扩展产生的开销也是不可小视的。所以对应用层代码来说,进行端到端处理时,务必要减少解析次数,否则频繁的在xml string和dom对象间转换,内存消耗绝对是噩梦,好的框架设计及编码规范绝对会在这个问题上有很大的帮助。

 

一点注意事项:有些程序员喜欢通过debug log输出xml string进行调试,代码中经常会见到logger.debug(xmlObj.toString())这类的操作,有这习惯的请千万注意啦,在进行这个debug log输出是,务必要先判断一下logger的级别,如果级别不匹配不要执行这条日志输出,否则即使是不输出,xml对象toString的操作还是会执行的,这个对内存使用是非常非常浪费的

 

xpath/xquery引擎的效率总体来说还是依赖xml的内存数据结构,比如查找指定名称的xml子节点操作:

1)如果父节点保留所有子节点的索引,那么查找起来势必一步到位,但缺点是内存占用率高,另外子节点数量的动态性,也可能造成hashmap动态延展时的内存开销;

2)如果父节点仅保留第一个子节点的引用,所有子节点采用链表方式连接,这种方法节省内存,但搜索起来,性能会依赖子节点的数量,如果子节点数量很大,那么遍历过程会造成cpu开销比较高。

 

另外,xpath引擎的效率,也依赖于xpath表达式的解析算法,及xpath引擎是否会对xpath表达式进行缓存等等。

 

主流的基于java的xml解析器包也用过不少,比如Apache Xerces,jdk内置的W3C DOM,dom4j,xmlBean,vtdXml等,网络上有过一些针对dom解析器性能对比的文章,个人认为对于xml解析器性能好与坏不能一概而论,这些解析器还是都有些各自偏向的特点和适用场合,在全面支持xml标准的同时,也各有所长。所以在选择解析器时,还要结合自己的需求,比如解析出来后用什么方法处理,用哪种xpath/xquery引擎,以及应用自身数据特点等。

 

在选择第三方xml库的时候,实际上是没有主动权的,很少有人仔细查看过库的实现方式,但是,如果能够根据自身应用特点等综合因素,定制xml解析器和xpath引擎(大可不必支持全部xml标准,可以选取标准的子集),那么性能定能大大提高,不过实际操作起来对大部分人来说会比较难,因为从xml解析到xpath引擎,涉及的是一整套xml处理方法可以连贯到一起,似乎只有比较牛的公司才有能力自己做解析器及解析引擎。

 

尝试:

你相信有办法可以使xml处理的综合处理性能(不论xml内容大还是小)可以提高数倍么?答案是可以的,本人曾主导开发了一个xml解析器,一个轻量的树形内存模型(子节点采用链表连接,父节点仅保持第一个子节点的引用),及一个支持xpath1.0的xpath解析器。

 

就性能来讲(以10K大小xml测试):

  • 比基于w3c dom的模型,在处理速度上提高一倍以上,内存使用率相比仅为w3c dom的不到1/2,如果xml更小,性能提升更大。[注:采用自行开发的xpath引擎作用于w3c dom模型上]
  • 比基于dom4j的模型,处理速度上提高5倍,内存使用率仅为dom4j模型30%

另外,对于O字头(原B字头) ESB产品广泛使用的xmlbean,手里没有最新的测试结果,印象中n年前做项目时的测试,大概50K的xml,从xmlObject转xml string时,内存消耗好像在1.5m至2m,其xpath/xquery引擎性能未做过测试,不过自其Integration产品问世以来,从来没敢在本人主导的设计中使用过其所见即所得采用拉拉线方式的转换引擎,尽管本人自03年开始即一直使用weblogic和weblogic integration产品。09年在支持新加坡一个电信运营商BSS项目时倒是领教过,eai项目包含近800个拉线定义的xml转换,那个性能测试结果真是那个。。。。

 

结论和建议:

大可不必迷信那些既成事实或想当然的做法,要敢于想,敢于做,敢于根据系统实际需求,定制核心库及设计数据模型。冲出这个思维禁锢,还是能发现更蓝的天的!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值