65.9K
CodeProject 正在变化。 阅读更多。
Home

二进制 XML 的性能困境

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (16投票s)

2008年2月23日

CPOL

8分钟阅读

viewsIcon

85768

分析为什么二进制 XML 无法解决 XML 性能的真正问题。

引言

自 XML 问世以来,它因给企业基础设施带来的开销而受到批评。以 XML 编码的业务数据在网络传输时需要 5 到 10 倍的带宽,存储时也需要相应的更多磁盘空间。虽然大多数人都同意冗长是 XML 编码信息的固有特性(例如,大量使用标签和尖括号),但对 XML 性能问题的解释仍然没有定论。一种流行的看法是,由于 XML 是人类可读的文本,因此它必然速度慢且效率低下。同样,二进制 XML 的支持者似乎认为,紧凑的编码格式,尤其是二进制 XML,将自动带来更好的处理性能。

医生在没有诊断的情况下开药是否合理?无论这些看法和信念是否有道理,有一点是肯定的:如果不深入了解 XML 的性能问题,就很难(甚至不可能)制定有意义的解决方案。因此,在本文中,我将尝试通过关注以下三个关键问题来剖析 XML 的性能问题:

  1. XML 是否存在性能问题?
  2. 造成 XML 性能缓慢的真正罪魁祸首是什么?
  3. 二进制 XML 能从根本上解决问题吗?

性能本身并非 XML 的问题

在网络系统设计中,OSI(开放系统互连)模型是标准模型,它将网络的功能划分为七层。每一层只使用下一层的功能,并且只向上一层导出功能。与整体方法相比,OSI 的分层方法的优势在于,面对快速的技术演进,网络系统的健壮性、弹性以及可扩展性。例如,任何 IP 语音应用都可以正常工作,而无需了解网络的物理层(例如,使用铜缆、光纤或 Wi-Fi)或数据链路层(例如,以太网、帧中继或 ATM)。

同样,我们可以采用类似的分层方法来模拟基于 XML 的应用程序。图 1 是这个“XML 协议栈”的简化视图,它由三层组成:XML 数据层、XML 解析层和应用程序层。应用程序层仅使用 XML 解析层导出的功能,XML 解析层将数据从其物理表示(XML)转换为逻辑表示(infoset)。

Figure1.jpg

图 1. XML 应用程序栈

关于 XML 的性能问题,可以做出几点观察。首先也是最重要的一点是,由于 XML 应用程序的速度只能跟上 XML 解析器处理 XML 消息的速度,因此性能实际上不是 XML 本身的问题,而是 XML 解析层的问题。如果一个 XML 路由应用程序(假设应用程序层的开销最小)无法跟上每秒千兆比特的传入 XML 消息,那很可能是因为 XML 解析的吞吐量低于网络的吞吐量。因此,提高应用程序性能的正确方法是优化 XML 解析层。就像调整任何软件应用程序一样,最好的方法是发现并设法减少或消除 XML 解析器中的开销。

对象分配——真正的罪魁祸首

为了感受当前 XML 解析技术提供的性能,我对两种广泛使用的 XML 解析器(Xerces DOM 和 Xerces SAX)的解析吞吐量进行了基准测试。基准测试应用程序非常简单。它们首先将 XML 文档读入内存,然后调用解析器例程来解析文档,重复大量次数。解析吞吐量通过将文件大小除以每次解析迭代的平均延迟来计算。对于 SAX 解析,内容处理程序设置为 NULL。选择了几种不同大小、标签复杂度和结构复杂度的 XML 文档进行基准测试。这些结果由一台两年前的 1.7GHz Pentium M 笔记本电脑生成,总结在图 2 中。完整的报告——包括测试设置、方法和代码——可以在网上 这里 找到。

Figure2.jpg

图 2. DOM、SAX、Pull 和 VTD-XML 之间的解析性能比较

基准测试结果与 DOM 和 SAX 的性能特征非常一致。首先,SAX 的原始解析吞吐量(20MB/秒~30MB/秒)实际上相当可观。然而,由于不公开固有的结构信息,SAX essentially 将 XML 视为带有“尖括号”的 CSV,这通常使其难以使用,不适合作为通用 XML 解析器。另一方面,DOM 允许开发人员导航内存中的树形结构。然而,基准测试结果也表明,除了非常小的文件之外,DOM 通常比 SAX 慢三到五倍。由于 DOM 解析器通常在内部使用 SAX 对 XML 进行分词,因此通过比较性能差异,很明显构建内存树结构是瓶颈所在。换句话说,分配所有对象并将它们连接在一起会极大地减慢所有速度。下一步,我运行了 JProfiler(来自 ej-Ttechnologies)来识别 DOM 和 SAX 解析将所有 CPU 周期花在了哪里。结果证实了我早前的猜测,即对象分配的开销压倒性地限制了 DOM 解析,并且(尽管程度较小但仍然显著)也限制了 SAX 解析。

一些读者可能会争辩说,DOM——仅仅是一个 API 规范——并不排除高效、不那么依赖对象的实现。并非如此。DOM 规范实际上完全基于这样一个假设,即层次结构完全由暴露 Node 接口 的对象组成。任何 DOM 实现所能做的最好的就是改变 Node 接口 后面的对象的实现,而不可能完全摆脱对象。因此,如果对象创建是主要原因,那么 DOM 规范本身就是使任何面向性能的优化变得极其困难的帮凶。这就是为什么,在过去八年里,所有主要 IT 公司付出了无数努力,每种 DOM 实现的性能改进都只是微小的。

二进制 XML 解决了错误的问题

二进制 XML 能从根本上解决 XML 的性能问题吗?嗯,既然性能问题属于 XML 解析器,一个更好的问题是二进制 XML 能否帮助提高解析效率。答案有两个部分:一个用于 SAX,另一个用于 DOM。

二进制 XML 可以提高原始 SAX 解析速度。有很多 XML 特有的语法特性是二进制 XML 可以选择不继承的。例如,二进制 XML 可以用更有效率的东西替换结束标签,完全避免属性,这样 SAX 解析就不再进行唯一性检查,或者找到其他方法来表示文档结构。有很多方法可以从 SAX 的分词成本中削减 CPU 周期。二进制 XML 的支持者通常声称,二进制 XML 版本的 SAX 比文本 XML 的速度快 10 倍。

然而,他们忽略了一个简单的事实:SAX 存在严重的可用性问题。SAX 解析笨拙的前向特性不仅需要额外的实现工作,而且当文档结构稍有复杂时,还会带来性能损失。如果开发人员选择不多次扫描文档,他们将不得不缓冲文档或构建自定义对象模型。此外,SAX 与 XPath 配合不佳,而且通常无法驱动 XSLT 处理(二进制 XML 也需要转换,对吧?)。因此,指出二进制 XML 的 SAX 原始性能作为二进制 XML 优点的证明既不公平也不具误导性。底线是:为了使 XML 处理模型具有广泛的可用性,API 必须公开 XML 的固有结构。

不幸的是,二进制 XML 对改进 DOM 解析不会有太大影响。原因很简单,DOM 解析通常将大部分 CPU 周期花在构建内存树结构上,而不是分词上。因此,由于 SAX 解析速度加快,DOM 的速度提升非常有限。换句话说,二进制 XML 的 DOM 解析速度也会很慢。更进一步说,基于对象图的解析器对于几乎任何数据格式(如 DCOM、RMI 或 CORBA)都将具有相同的性能问题。XML 仅仅是替罪羊。

减少对象创建——正确的方法

从我的基准测试和性能分析结果来看,很容易看出消除 XML 解析性能瓶颈的最佳方法是降低构建内存分层结构的对象的创建成本。实际上,可能性是无穷无尽的,只受限于想象力。好的解决方案可以而且将会出现,其中之一就是 VTD-XML。为了实现高性能,VTD-XML 通过两个无对象步骤来处理 XML 解析:

  1. 非提取式分词,以及
  2. 基于分层目录的随机访问

结果:VTD-XML 大大减少了对象的数量,同时仍然将分层结构导出给应用程序开发人员,并且性能远超 SAX。(参见图 3。)

Figure3.jpg

图 3:DOM 和 VTD-XML 之间的内存使用量比较

结论

总而言之,正确的方法是找到优于 DOM 和 SAX 的更好解析技术,以显著降低构建 XML 树结构对象的创建成本。二进制 XML 无法从根本上解决 XML 的性能问题,因为问题属于 XML 解析器,而不是 XML 本身。

历史

  • 2008 年 2 月 23 日——发布原始版本。
  • 2008 年 3 月 4 日——更新了文章内容。
  • 2008 年 3 月 18 日——更新了文章内容。
  • 2008 年 4 月 9 日——更新了文章内容。
© . All rights reserved.