Python Web 服务开发者: 消息传递技术比较
时间:2007-07-31 来源:pascal4123
Python Web 服务开发者: 消息传递技术比较为手头的任务选择最佳工具 |
级别: 初级
Mike Olson ([email protected]), 首席顾问, Fourthought, Inc. 2002 年 7 月 01 日 在 各种技术之间进行选择总要涉及到得失的权衡;您经常牺牲性能来获取轻松编程。消息传递技术可能是 Web 开发者最感兴趣的领域。您如何能平衡高速性能和人类可读性?Mike Olson 和 Uche Ogbuji 并不声称拥有这个问题的答案,但是他们确实提供一些硬数据(hard data)以帮助您作出最适合您需要的决定。在本文中,他们帮助您在一些可用的不同的消息传递协议之间进行比较。您将为每个协议编写一个简单的应用程序, 并比较速度、消息开销和相对开发时间等各项衡量指标。 Web 服务开发者可以使用的消息传递技术有很多;一些技术提供高性能,其他技术则提供易用性和人类可读性。在 Python Web 服务开发者的 这篇文章中,您将考察四项不同的消息传递技术并为每项技术编写一个简单的基准测试程序。当您做完这些工作后,您将从每个应用程序收集到一些基本的统计信 息,以便在各项技术之间进行简单的比较。在本专栏中,您将要探讨的四项技术是 SOAP、CORBA、XML-RPC 和优秀的、传统的、低级别的套接字。 在本文中,我们将阐述一个简单的客户机-服务器应用程序,它发送三条不同的消 息。第一条消息以字符串形式从客户机发往服务器;在这个过程中,您可以收集到有关时间开销和消息开销的信息。您创建的第二条消息与第一条消息相反:您从服 务器接收一个字符串。最后,您将向服务器发送一个整数。这将使我们能够收集到关于二进制消息的时间开销信息以及消息开销信息。 请 注意不要从本文所提供的分析中得出太一般的结论。我们将探讨的四项技术尽管都适合基于消息的客户机-服务器应用程序,但是它们的优缺点却有很大差别。要选 择一项适合您的消息传递技术,您需要做的不仅仅是直接比较消息传递开销。随着我们更详细地考察每项技术,我们将尝试揭示它们的一些重要差异,从而使开发者 对于要使用的技术能作出更全面的选择。 要收集时间开销信息,您只需使用 Python 提供的 time.time() 函数调用即可。当您分析生成的统计数据时,请牢记 time.time() 的准确度与平台有关,并且在某些情况下精度可能几乎等于一秒。 当您使用每一项不同的技术执行应用程序时,您将需要一种标准方法以了解通过您的 TCP 连接实际发送了多少信息。为此,您将使用一个名为 tcpdump 的工具(请参阅下面的 参考资料部分以获得一个链接)。下载和安装 tcpdump 的过程将根据您的操作系统有所不同,所以我们在此不作介绍。这个站点上的文档还不错,无论如何,您都不需要让 tcpdump 实际运行示例代码,只需要用它通过收集发送给特定的 TCP 连接的消息来测试消息开销。 当您测试应用程序时,您将使用下列 tcpdump 选项将消息抽取出来保存到临时文件中。
还有许多其他您可以使用的选项(例如,您可以用端口或主机名进行过滤),但是对于这种简单的情况,这些选项就足够了。 -i lo 选项告诉 tcpdump 要侦听哪个接口(在这个例子中要侦听回送设备)。 a 选项试着将地址转换成名称。 e 选项表示在输出中要包含链路层头信息。 s 0 告诉 tcpdump 您想得到每个数据包主体中的所有数据。(如果您想让 tcpdump 只保持每个数据包一定数量的字节,请输入所期望的字节数来代替此处的零。)最后一个选项告诉 tcpdump 将机器检查到的所有数据包复制到一个名为 /tmp/packets.txt 的文件中。请注意,上面的命令行适用于 Linux 机器,并且您可能需要拥有 root 权限或管理员权限才能运行 tcpdump 。
在您可以运行测试套件前,您需要在您的系统上运行几个第三方软件包。我们将对每个软件包进行简要介绍;如果您已经安装了这些软件包,您可以跳过以下几个部分。 您将要使用的 CORBA ORB 名为 omniORB(请参阅 参考资料以获得一个链接,您可以从该处下载 omniORB)。对于这个示例,您将使用 omniORB 版本 3.04 和 omniORBPy 版本 1.4。对于非 Unix 平台和某些版本的 Unix,有可用的二进制文件。如果您正在从源文件开始构建,那么适当的 自述文件将会有所帮助;下面是基本步骤。请注意,如果您正在从二进制文件安装,那么您将仍需要按照第 7 步和第 8 步中所示来更新您的 PYTHONPATH 环境变量和 PATH 环境变量。
安装了 omniORB 之后,您需要为示例生成存根(stub)文件和骨架(skeleton)文件。请从 此处下载示例并对其进行解压缩。然后转到 src/omni 目录并执行:
如果您正在使用 Python 版本 2.1 或更高版本,那么您可以跳过这一部分。但是,如果您正在使用较早版本的 Python,或者您只是想要获取最新的 xmlrpclib ,那么您应该下载那个软件包;请参阅 参考资料以获得一个链接。安装很简单:就是创建一个目录,然后将压缩文档解压缩(unzip)到您的 Python 路径上的一个位置中。不要忘记向新目录中添加一个 __init__.py ,以便可以将它作为一个 Python 模块导入。
您将需要的最后一个第三方库是一个 SOAP 实现。为了进行您的基准测试,您将使用 ZSI;请参阅 参考资料以获得到最新版本的链接。您一旦已经下载了最新版本的 ZSI,请对其进行解压缩并执行 python setup.py install ,然后您就可以使用它了。
既然您的系统已经准备好了,您就可以使用您的基准测试程序来依次测试每项技术了。 让我们先来考察一下原始 Python 套接字。因为没有协议开销(除了您自己添加的东西外),所以您可以认为这在您的控制下。这是有关原始套接字编程的优点;缺点是您将需要担心许多其他重要的问题,例如:
那么,让我们来看看应用程序吧。这个应用程序的所有示例代码都可以在 此处获得。您在下载了压缩文档并对其进行解压缩后,您将拥有四个子目录。我们要看的第一个子目录名为 python 。为 TCP 通信编写您自己的协议的好处之一就是,您无需安装额外的第三方库。这可以最大限度地降低分发包给您带来的困扰。 在示例分发包中,文件 python/server.py 是您将用来接收原始 TCP 请求的服务器。它建立在 Python 自带的标准的 SocketServer 模块的基础上。在您考察代码时,要注意几件事情。第一件事情是要进行绝对无错检查。对于每种消息类型(以及对于不存在的消息类型),客户机都需要彻底检查 从服务器接收的每个字节。第二件要注意的事情是处理程序被设计成处理单个请求。当您开始非常快速地发送许多整数时,因为客户机将不得不为它发送的每个整数 创建一个新的连接,所以这样的设计将使您的小套接字服务器处于不利的境地。您本来可以将这台服务器编写成在单个连接中处理多个请求,但是那样您将不得不以 start 消息和 stop 消息的形式向您的服务器添加额外的消息类型支持,以便服务器知道何时停止侦听连接。对于这个服务器文件最后一件要注意的事情就是没有任何形式的连接超时。 按照这台服务器配置的方式,一台恶意的客户机可以连接到这台服务器上,并且可以发送一个非常大的字符串,结果将使整个服务器瘫痪。 要启动服务器,只需在一个窗口中执行 server.py 脚本即可,然后立即执行名为 time-client.py 的测试客户机。这将把时间开销信息打印到执行了客户机脚本的终端。客户机完成任务后,您就可以按 Ctrl-C 停止服务器。要测试消息开销,您要使用 tcpdump ;在第三个窗口中运行它,然后运行脚本 size-client.py (此时服务器仍在运行中)。这两个脚本的运行结果如下面的表 1 所示。 我们要考察的第二项技术是 SOAP,这对于本专栏的读者来说应该是最熟悉的。不过,SOAP 却是这组技术中的新来者,只是近几年才出现的。SOAP(通常)用 HTTP 进行传输,创建基于 XML 的消息,这些消息被作为 HTTP 主体发送。从一开始,您可能就已经看出在 SOAP 消息中将有一些开销,来自 HTTP 和 XML 的都有。不过,这不应该总是被看作一件坏事,因为它有助于使消息具有更好的人类可读性。 在示例分发包中,有一个 soap 子目录。这个子目录包含文件 server.py 、 time-client.py 和 size-client.py 。这些文件的执行方法与原始套接字应用程序中的对应文件的执行方法完全一样。同样地,您将在 表 1中看到结果。 公共对象请求代理体系结构(Common Object Request Broker Architecture,CORBA) 在 SOAP、CORBA 和 XML-RPC 中,CORBA 大约是出现时间最长的一个,并且解决了一些较难的分布式编程问题:并发、事务、安全性和认证。SOAP 已经开始着手解决这些问题了,而 XML-RPC 则要求您(程序员)处理这些问题。(实际上,CORBA 本身并不提供这些功能;不过,这个协议被设计成支持这些功能,而且大多数 ORB 将提供这些功能(按照 CORBA 服务规范实现的)中的一些或全部。)CORBA 的第二个优点(相对于 SOAP 或 XML-RPC)是,它的消息是二进制格式的,虽然在某些方面来说这也是一个缺点。CORBA 之所以好,因为 CORBA 消息比 SOAP 消息或 XML-RPC 消息小得多,且开销也小得多。不好的方面是,如果您需要调试一条 CORBA 消息,您就会碰到麻烦:只有一台 GIOP 服务器能理解 CORBA 消息。 在示例分发包中有一个 CORBA 子目录。在这里,请像您在前面的两个示例中执行这些脚本的对应脚本一样执行它们。结果已经列在下面的表 1 中。 XML 远程过程调用(XML Remote Procedure Call,XML-RPC) 最后,让我们考察一下 XML-RPC 协议。许多人已经向我们说过 XML-RPC 可以胜任 SOAP 能胜任的大多数角色。但是,我们认为它在几个方面(包括 Unicode 支持和数据类型的灵活性)还存在着不足。XML-RPC 是一个比 SOAP 要简单得多的协议,这使得它更易于使用;不过,SOAP 正致力于解决 CORBA 已经解决的许多问题(并发、事务等),而 XML-RPC 似乎满足于它的现状,因为大多数 XML-RPC 开发者现在都在做有关 SOAP 的工作。 在示例分发包中有一个 xml-rpc 子目录;示例的运行方法跟前面一样,所有结果都列在下一部分中。
表 1汇总了您测试所有四项消息传递技术所得到的数据。
哇!人类可读性当然要以昂贵的代价来换取。SOAP 消息和 XML-RPC 消息的长度是二进制 CORBA 消息的 14 倍还 多。这并不是说在现今世界中大消息很可怕,在现今的世界中,T1s 连接了大多数企业,而 256 Kbps DSL 连接则连接了许多家庭;不过,如同您从向服务器发送 5,000 个整数的那个测试中看到的一样,在同一台机器上,SOAP 和 XML-RPC 所花的时间分别比 CORBA 长 882 倍和 66 倍。 起初令人惊讶的一个统计信息是,CORBA 服务器比原始套接字实现具有更小的消息且速度更快。其原因(早些时候曾经提到过)是,用原始套接字,您需要为您向服务器作的每个请求建立一个新连接。当通 过 TCP 连接到一台服务器时,需要来回发送几条消息以创建连接。从客户机向服务器发出三条消息请求连接,然后从服务器发送回三条确认消息。当您重复这样做 5,000 次时,这些小消息加在一起就可观了。CORBA(以及大多数当前的 HTTP 服务器)通过使用连接池来解决这个问题。 还 要考虑到其他一些难于在统计分析中量化的注意事项。每项消息传递技术都有一些与之相关的不同属性,这些属性使得该项消息传递技术更适合于某些情况而不适合 于其他情况。以原始套接字为例。一般来说,原始套接字要求程序员在通信代码的创建、调试和维护中做最多的工作。但是,如果您正在创建的应用程序对开销非常 敏感,或者如果您不愿让通信层的实现处于第三方的掌握中(通过使用一个消息传递技术库),那么创建和维护一个定制通信层所需的工作量就会越来越不成为障 碍。 尽 管 CORBA 是您在本专栏中所看到的协议中速度最快的一个,但是它的学习曲线也是最陡峭的,并且很有可能内存占用量(当然,这取决于您使用的 CORBA 实现)也是最大的。而且,虽然有许多 CORBA 规范的开放源代码实现,但要获得 CORBA 的许多必备功能(如 CosTransactions、CosSecurity 和 CosConcurrency),您还是必须自己实现这些功能,或者购买一个商业 CORBA 实现;后者可能要花费数万或数十万美元。 XML-RPC 和 SOAP 大致属于同一个类别。两个协议的特点都是需要大量的消息开销,它们的性能要比 CORBA 的性能慢得多;不过,对于许多应用程序而言,您实际上并不关心这些因素。随着带宽、处理器、内存和磁盘空间成本的日渐下降,很容易证明在额外的设备上花 5 千到 1 万美元来补偿性能方面的任何下降是正确的。您在此过程中的花费将比在商业 ORB 上的花费要少,但是仍具有人类可读的消息的优点。关于 SOAP 和 XML-RPC 要注意的最后一件事情就是,它们都建立在纯 XML 的基础上。这意味着,如果您在应用程序中支持入站/出站的基于 XML 的消息结构,无论该技术将来怎么发展,您都可以非常容易地将您的通信基础结构转换成另一种格式,因为只要稍稍使用 XSLT 就可以将 XML 转换成任何格式。
在本专栏的下一篇文章中,我们将更详细地考察在 Python 2.2 中成为标准的 XML-RPC 库。我们将编写一个简单的客户机和服务器应用程序来向您展示如何使用这个库,并且将 XML-RPC 的一些功能与 SOAP 中类似的功能进行比较。
|