Python 是 Rackspace 的核心技术
简介
要成为托管服务行业的领导者,您必须快速且灵活。通过使用 Python 来实现我们的企业数据系统,Rackspace 可以快速有效地更改其内部系统,以跟上行业和我们自身业务流程的变化。我们通过一个名为“CORE”的中央客户信息系统来实现这一点,该系统同时用于客户关系管理 (CRM) 和企业资源规划 (ERP)。Python 和 CORE 是使 Rackspace 能够提供我们狂热支持 (Fanatical Support™) 和更快客户服务的关键因素。
背景
Rackspace 的中央客户数据库最初是一个简单的 ERP 系统,用于配置和跟踪托管服务器。它最初只是一个小的 PHP 页面集合,这些页面对于 Rackspace 客户群开始时数百台服务器来说做得很好。
随着 Rackspace 的发展,这个小的 PHP 系统成为了 Rackspace 的业务中心。每次出现自动化流程的机会时,它都会被纳入该系统。
几年后,结果是一个由数千个 PHP 页面和模块组成的庞大且无法维护的混乱局面,这些页面和模块主要由一个人编写和维护。PHP(当时的版本 3)的限制被拉得很薄,该系统对于一个人来说维护量太大,而且很难引入新人来帮助它。

Rackspace 托管服务在最先进的数据中心中提供定制服务器 放大
我们第一次尝试更新系统是在 PHP 版本 4 发布时。此版本承诺提供更好的面向对象功能,而现在正是 Rackspace 为该项目投入更多人员的时候。
该系统从头开始进行了完全重新设计,包括新的数据库架构和应用程序设计策略。此时,我们将该项目重新命名为“CORE”,它是 Core Objects Reused Everywhere 的首字母缩写,以反映 CORE 的总体设计目标:在公司的所有系统中实现模块化和可重用性。考虑到这个目标,我们的团队开始使用 PHP 的面向对象功能进行工作。
虽然我们能够重新调整应用程序并增加功能,但该项目最终还是失败了,这主要是由于在使用 PHP 提供的对象框架时遇到的问题。
内存泄漏、不一致的接口、不一致的内部数据模型、随机释放的对象、尽管明确使用引用但仍有多个对象副本、内部 PHP 错误以及无法追踪的代码故障几乎使在 PHP 中完成此任务变得不可能。
即使在我们获得了相对稳定的代码库之后,我们仍然远未达到 Core Objects Reused Everywhere 的目标,因为我们不得不偏离纯粹的面向对象方法,只是为了解决 PHP 中固有的问题。很明显,PHP 不适合我们的大规模、任务关键型项目。必须找到新的解决方案。
CORE 中的 Python
我们一直认为 Python 是实现我们企业系统的绝佳候选者,但最初它被放弃了,转而基于我们已经拥有的 PHP 中的现有(庞大)代码库进行构建。当时,我们认为可以通过引入更好的结构化系统设计在 CORE 中成功使用 PHP。
不幸的是,这不足以克服我们在 PHP 中遇到的其他问题,因此我们重新评估了我们的情况。Python 2.2 的第一个 alpha 版本最近发布,我们决定开始使用该版本中可用的新功能开发新的 CORE 框架。
内省的力量
编写新框架的首要任务之一是构建其数据库接口。
Python 的内省模型随着 Python 2.2 的发布而得到了显著增强。我们决定使用它来构建基于符合 DBI 2.0 标准的数据库连接器的通用数据库接口类。在这种方法中,元类将所有数据库查询抽象为单个干净的 API,而不是手动编写查询或特定于表的包装器。
我们创建此元类的后代,为每个表创建一个 API。每个表的类都包含一些描述数据库中列的类常量。这样,我们可以快速简单地将新表添加到整体 API,而无需担心任何特定表的实现细节。
该 API 还使用元数据来自动验证和转换传递给数据库的值。这是通过“规范化器”函数完成的,该函数将通过 API 传递的 Python 数据类型转换为有效的 SQL 值。该函数还验证数据库或 Python 不一定检查的类型和格式,例如电话号码和邮政编码。
在任何地方重用对象
数据库 API 完成后,我们在其之上创建了第二层类。这个更高级别的 API 实现了特定应用程序的业务逻辑,例如联系人管理或故障单处理。它还防止用户执行与 Rackspace 的业务实践不一致的操作,或分配会导致数据库中其他类型的高级数据损坏的数据。
通过创建第二层,我们实现了最初的 Core Objects Reused Everywhere 目标。整个公司的程序员开始使用此 API 来实现应用程序功能的接口。这不需要与我们的 API 开发团队进行太多交互,并且可以在不必担心误用 API 的情况下完成。
虽然我们主要为中央企业应用程序 CORE 设计了该 API,但它在 Rackspace 的许多其他系统中得到了重用。例如,一个小组在该 API 之上构建了一个 SOAP 服务器,以便从他们的 PHP 应用程序访问它。其他应用程序直接使用该 API,看到我们的工作如此轻松地与其他系统重用和集成,这令人非常欣慰。
将 Python 与 Apache 集成
在 API 就位后,我们开发 CORE 的下一个任务是找到一个有用的模板模块,将我们的 Python 代码与在 Apache Web 服务器上运行的 HTML 页面集成在一起。
在查看了许多可用的基于 Python 的模板模块后,我们选择创建自己的简单解析器。我们的方法是将服务器端模板页面转换为 Python servlet,其输出由 HTTP 服务器发送到用户的浏览器。
虽然这是一个相当简单的练习,但我们确实遇到了一些源于 CORE 数据库元类设计的问题。我们发现,像元类所做的那样在运行时更改类和模块违反了 Python 可选的受限执行环境施加的指南。由于我们认为受限执行是支持持久 Web 模块的必要组件,因此我们选择使用 CGI 而不是 mod_python 或类似的持久解决方案来部署 CORE。
由于快速硬件和多台服务器很容易获得,并且由于我们的模板解析器预编译并缓存其生成的 Python servlet 代码,因此 CGI 解决方案足以满足我们的需求。它还允许我们解决诸如数据库连接池和在 Python 之外限制执行环境之类的问题。
单元测试
得益于 Python 附带的单元测试模块,我们的项目在投入生产时出现的错误比我们使用 PHP 时想象的要少得多。在使用 PHP 进行维护期间,总是存在一个问题,即一个地方的更改是否会破坏应用程序另一部分中的其他内容。
现在,我们在设计每个 API 时都会为每个 API 编写单元测试。这意味着我们可以通过运行整个 API 的单元测试来验证一个模块中的更改以及它对所有其他模块的影响。
自从引入 Python 和单元测试以来,我们在已部署的应用程序中看到的错误的性质已转变为主要包括用户界面中的错误,例如布局问题或错误的事件处理。
现在,很少有错误来自 API 本身,即使有,通常也是由于应用程序部署期间糟糕的版本管理或 DBA 协调造成的。Python 无法解决开发过程中的 _所有_ 问题,但它确实为我们减少了关键系统缺陷的数量。
文档
缺乏文档是我们之前开发工作中的一个主要问题。我们尝试了几种工具和策略来记录我们的 PHP 工作,但最终都失败了。代码变化太快,而当时可用于 PHP 的代码级文档工具又过于繁琐,难以证明为使文档正确解析所需付出的努力是值得的。此外,尽管经过仔细的规划和编码策略,PHP 和 HTML 的混合使用使得代码的解读和理解更加困难。
幸运的是,Python 在设计时就考虑到了文档,它为模块、类和方法使用了“文档字符串”。由于文档实际上是语言本身的一部分,并且 pydoc 是 Python 发行版中的一个标准模块,因此很容易将 API 文档提取为 HTML 和其他格式。
随着时间的推移,我们发现 Python 的语法结构使得代码非常易读,这本身就对文档化和维护代码的整体任务有所帮助。
结论
Python 极大地改进了 CORE 项目的开发流程,并加快了开发速度和发布速度,这使我们能够跟上 Rackspace 不断变化的业务流程。
Python 使我们能够创建一个复杂的动态数据模型,该模型灵活且易于使用,用于抽象数据库操作。有了它,我们实现了“核心对象在任何地方重用”的目标。
Python 集成的单元测试和文档工具极大地增强了我们部署和维护更稳定、无错误产品的能力。
最终,我们成功开发了一款企业应用程序,该应用程序在交付 Rackspace Managed Hosting 的 “狂热支持、无与伦比的速度和托管行业无限的灵活性” 的承诺中发挥着重要作用。
关于作者
Nick Borko 是内部应用程序开发总监,也是 Rackspace 企业数据库应用程序 CORE 的项目经理。 Rackspace Managed Hosting 是为中小型企业提供托管服务的领导者。 所有客户平台都包括最先进的数据中心、定制服务器、可突发连接、99.999% 的正常运行时间 SLA、专职客户经理、即时紧急响应以及全天候 24 小时访问现场专家技术人员,以支持所有硬件和核心软件。 Rackspace 成立于 1998 年,总部位于德克萨斯州圣安东尼奥,为 80 多个国家/地区的客户管理服务器。