下载本文的PDF版本 PDF

ASPs:集成挑战

LEN TAKEUCHI,SALESCENTRIX

随着许多ASP(应用服务提供商)的出现,软件即服务的承诺正逐渐成为现实。使用ASP和为ASP提供增值产品的第三方供应商的组织需要与它们集成。ASP通过提供基于Web服务的API来实现这种集成。通过互联网与ASP集成和与本地应用程序集成之间存在显著差异。在与ASP集成时,用户必须考虑许多问题,包括延迟、不可用性、升级、性能、负载限制和缺乏事务支持。

Web 服务 API

ASP提供的集成 API 通常基于 Web 服务。ASP 提供 API 的文档和 WSDL(Web 服务描述语言)文件。API 的用户使用 WSDL 文件,利用 Web 服务工具包(例如,Apache Axis)生成 Web 服务客户端。ASP 可能会在其软件中提供一项功能,为各种实体创建自定义字段。例如,CRM(客户关系管理)系统很可能在客户帐户等实体上提供自定义字段,因为组织希望跟踪关于客户的特定信息。如果 ASP 支持自定义字段,它通常会提供两个单独的 WSDL 文件:一个基于该组织定义的自定义字段专门为该组织生成,另一个是通用的。

专门为组织生成的 WSDL 允许组织以与标准字段相同的方式访问自定义字段,这使得开发人员无需了解给定字段是自定义字段还是标准字段。通用 WSDL 提供了一种访问自定义字段的通用方法,将由不为特定客户开发其产品的第三方供应商使用,因此不需要任何特定的自定义字段集。即使是开发与自身系统集成的组织,也可能最好使用通用版本,特别是如果它预计会添加更多自定义字段,并且不想不断检索组织特定的 WSDL 并重新生成其 Web 服务客户端。

本文基于与三个 ASP 的经验

服务提供问题

对于大多数 ASP,任何给定时间只有一个版本的软件在生产环境中运行。这意味着当 ASP 发布新版本时,所有客户都将升级到最新版本。ASP 会提前几个月在新版本的软件在预发布环境中提供,以便集成应用程序可以在新版本投入生产之前针对新版本进行测试。

ASP 为其 API 的每个版本提供不同的 URL。理论上,现有版本的 API 不应受到软件新版本发布的影响;但是,由于实施中所做的更改,行为可能会发生意外变化。例如,Salesforce.com 有一个行项目实体,您可以在其中指定价格、数量和金额这三个字段中的任意两个,然后计算第三个字段(价格 x 数量 = 金额)。在特定升级版本之前,您可以不为要计算的字段指定值,也可以将该字段设置为 null。一旦升级发生,将字段设置为 null 会导致报告错误,这破坏了我们的集成。

因此,必须在预发布期间针对新版本执行完整的回归测试,并将问题报告给 ASP 和/或进行更改,以确保集成在新版本发布后继续工作。ASP 会定期发布新版本的 API,通常与新版本的软件同时发布,但它们将在一段时间内继续支持旧版本的 API。

ASP 可能提供或不提供关于其可用性和性能的 SLA(服务级别协议)。有些 ASP 只为其最大的客户提供 SLA,但它们始终会提前通知计划内的停机时间。一些 ASP 根据位置(例如,美洲、亚洲、欧洲)对其客户进行分区,并将每组分配给不同的服务器集群。这使他们能够在大多数客户的营业时间之外安排停机时间。尽管这些 ASP 试图通过在其托管基础设施中进行冗余来避免停机,但不可避免地会出现一些计划外的停机时间,可能持续几个小时甚至几天。因此,与 ASP 集成的应用程序需要进行设计,以便即使 ASP 不可用,也能提供尽可能多的功能。这可能需要在系统之间复制某些信息。

ASP 为最大化可用性所做的努力包括在其 ISP 源中进行冗余。如果 ASP 使用其备用 ISP 或对其托管环境进行更改(例如,移动到不同的数据中心),则服务提供商的互联网地址可能会更改。因此,与 ASP 集成的应用程序不应在其 TTL(生存时间)值之外缓存对 ASP 访问点的 DNS 查找结果。Java 默认行为是永久缓存成功的 DNS 查找。如果您的应用程序或 Web 服务器是 Java 应用程序,则必须将缓存周期调整为更合适的值,以确保应用程序在 ASP 的 IP 地址更改后继续工作。

ASP 在任何给定时间只有一个版本的软件在生产环境中运行,但它们可能拥有不同版本的软件,这些软件具有略微不同的功能集。这意味着并非所有 API 功能都适用于所有客户。与 ASP 集成的应用程序要么必须直接获取版本信息(如果可通过 API 获取),要么确定启用了哪些功能并采取适当的行为。

ASP 的共享租户模型使其必须保护自己免受特定组织过度使用其资源的影响。在 API 使用的情况下,它们通过限制以下方面来保护自己:

应用程序如何处理这些限制取决于正在执行的操作是否涉及交互式用户(有人值守的操作),或者应用程序是否正在执行后台任务(无人值守的操作)。当有人值守的操作超出会话限制和请求速率限制时,应用程序可以告诉用户稍后重试。如果无人值守的操作超出限制,则需要使用某种通知机制报告错误,或者需要重试机制。

请求大小、查询大小以及对调用输入或从调用返回的实例数量的限制在 API 文档中发布。开发人员有责任了解这些限制并设计他们的代码,使其不会超出限制。例如,如果开发人员正在基于从先前查询返回的数据集构建请求,则开发人员必须了解大小限制并设计代码,以便将数据集划分为多个请求;否则,构建的请求可能会超出限制。开发人员还必须了解执行时间限制,并以避免超出限制的方式编写代码——例如,通过降低查询的复杂性。在开发和 QA 周期中,必须使用大型数据集进行充分的测试,以确保在实际情况下不会超出执行时间限制。这种测试可以防止在应用程序发布后不得不进行修补。

安全

通过互联网调用 API 的安全性是通过使用 HTTPS(安全 HTTP)实现的。身份验证通常通过登录调用完成,其中传递凭据(用户 ID 和密码)。登录建立一个会话,可以在其中进行 API 调用。会话将在登录后的一定时间或不活动的一定时间后过期,具体取决于 ASP。集成应用程序要么必须保持连接活动状态(只有在超时基于不活动时才有可能),要么在过期之前抢先重新登录,要么在事后检测到过期并重新登录。

使用带有客户端证书的双向身份验证相当不常见。Salesforce.com 和 CRM OnDemand 使用用户 ID 和密码作为凭据。如果访问 API 的应用程序本身是服务器应用程序(基于 Web 的),但如果是桌面应用程序,则 QuickBooks Online Edition 需要使用客户端证书。这种区别可能是对客户端证书在桌面应用程序中相当不常见的让步。

WS-Security 等安全标准似乎在本文讨论的特定 ASP 的优先级列表中并不高。这很可能是因为它们 API 的大多数用户可能直接调用它们;因此,传输级安全(SSL)就足够了。在这种情况下,不需要消息级安全,因为不涉及中介。

另一方面,单点登录在 ASP 的优先级列表中很高。例如,Salesforce.com 支持委托身份验证协议,其中它对由客户定义的端点进行安全的 Web 服务调用,以提供支持单点登录的灵活机制。

一些 ASP 提供了一种将交互式登录会话传播到应用程序的方法。Salesforce.com 支持在其网站上的交互式会话与 Web 应用程序的 API 访问之间共享登录会话。这是通过 Web 链接功能完成的,该功能允许配置 Salesforce.com 以显示链接,这些链接在被调用时将导致 Web 浏览器转到为 Web 链接配置的 URL。可以配置 Web 链接以在浏览器重定向到 URL 时将会话 ID 作为参数传递,以便当 Web 应用程序接收到对 URL 的重定向时,它可以使用会话 ID 通过其 API 回调 Salesforce.com(无需通过 API 再次登录)。

可靠性

在使用基于 Web 服务的 API 通过互联网与 ASP 集成时,存在可靠性问题:由不可靠的通信、ASP 不可用性和 ASP 施加的资源使用限制引起的故障。

与 ASP 集成的应用程序必须能够处理这些故障。如果正在执行的操作是有人值守的,则应用程序应向用户传达适当的错误消息。如果应用程序正在执行无人值守的操作,则应用程序需要具有用于报告故障的通知机制或确保可靠性的重试机制。对于应用程序来说,根据报告的故障类型区分错误处理非常重要。例如,如果查询执行时间限制被超出,则重试没有任何意义,因为对于特定请求,错误每次都会发生,直到应用程序更新以重新制定查询。

通信问题,例如断开连接或等待来自 ASP 的响应超时,尤其成问题,因为应用程序不确定操作是否已成功完成。如果 API 提供某种方式来提供调用者提供的请求 ID,随后允许调用者使用 ID 查询结果,这将很有帮助,但这种类型的机制通常在 API 是同步的情况下不提供。如果请求是幂等的,则应用程序可以在结果未知时重试请求。这些 API 中的大多数修改操作往往是非幂等的,因此在这些情况下,应用程序将尽最大努力在事后确定请求是否已成功处理。

一种事后确定更新请求是否已成功处理的方法是在更新期间在实体的自定义字段中记录唯一的请求 ID,以便可以随后查询实体并检查此字段,以查看是否确实已执行修改。由于对该实体以及因此对保存请求 ID 的字段的更新可能在发出查询之前由其他人完成,因此请求 ID 将必须附加到此字段而不是覆盖它。如果我们只是读取字段,将请求 ID 附加到字段值,然后进行更新,则我们可能会最终清除其他人记录的请求 ID,如果它是在我们读取字段和我们写回字段之间完成的。显然,只有当我们可以在读取字段和写回字段之间锁定实体时,此方案才能可靠地工作。使用此方案,请求 ID 将会累积(因为它们是附加的),因此必须有一些策略来消除较早的请求 ID。

有一些新兴的 Web 服务事务支持标准5,但本文讨论的 ASP 不支持它们。事实上,它们根本不提供对事务处理或锁定的任何支持,并且这种支持在不久的将来不太可能出现。这意味着没有提供事务划分和提交或回滚事务的功能。如果应用程序必须以全有或全无的方式执行一组更新,则如果最初尝试的一组更新只是部分成功,则应用程序可以尝试撤消成功的更新或重做不成功的更新。这些方法并非总是有效,因为随后的补偿操作也可能失败。此外,由于集合中的每次更改都会立即公开,因此即使补偿操作成功,其他人也会看到中间状态。请注意,即使集合中的所有操作都成功,中间状态也是公开的(尽管时间很短)。

以一个具体的例子来说明,CRM 系统中的主要实体之一是商机。商机是对客户的潜在销售,并且可以具有与之关联的行项目。这些行项目记录了客户感兴趣的商品和数量。商机及其行项目在性质上类似于销售订单及其行项目。在 Salesforce.com 和 CRM OnDemand 中,商机及其行项目不在 API 的单个调用中更新。事实上,每个行项目的更新都是单独的更新。如果对商机进行了更改,例如第一个行项目的数量增加 1,第二个行项目的数量减少 1,但对第二个行项目的更新失败,那么我们最终会得到部分更新的商机。在缺乏事务支持的情况下,最佳策略可能只是重试对第二行的更新,如果再次失败,则尝试回滚对第一行的更改。如果这两者都不成功,那么将必须报告错误并留给用户来纠正这种情况。在这种情况下,稍后重试不一定是好的选择,因为其他人可能会在重试发生之前更新相同的商机;我们不希望重试清除这些更改。

ASP 提供的交互式应用程序的行为可能会导致应用程序看到部分更新状态的问题。例如,对于 Salesforce.com 和 CRM OnDemand,与商机关联的行项目由用户一次一个地更新。如果用户正在对行项目进行一组更改,而正在集成的应用程序恰好查询商机的行项目,则应用程序将看到部分更新的状态(即,对行项目的更新尚未完成)。应用程序将必须提出一些策略来最大限度地减少看到这些中间状态的机会。

应用程序可以采取的一种方法是检查查询中返回的行项目的修改时间。如果它们是最近的(在某个阈值内),则应用程序可以等待并在稍后重试。这不一定保证用户已完成一组更改,因为用户进行更改没有固定的时间范围,但此方法将减少看到中间状态的机会。如果在定期从 CRM 系统中提取商机的系统中使用此方案,则可能在一个轮询周期中看到中间状态,但在下一个周期中得到纠正。如果绝对不能看到中间状态,则必须制定一个方案,用户在该方案中显式地划分编辑会话的开始和结束。一种原始的方法是在自定义字段中记录商机是否正在被编辑,并让用户在编辑商机之前和之后手动更新此字段值。

性能

使用 ASP 提供的 API 时,性能的主要问题是每次调用的开销。开销来自互联网上的延迟、传输时间、客户端请求和 ASP 端响应的编组 (xml/SOAP)、ASP 端请求和客户端响应的解组 (xml/SOAP),以及 ASP 端的身份验证/授权检查和其他开销。

在访问 Salesforce.com 和 CRM OnDemand(这两个 ASP 都位于北美,我们也一样)时,我们观察到往返延迟为 25 到 50 毫秒。为了估计每次调用的开销量,我们使用 Salesforce.com 进行了一些测试,方法是发出一个 API 调用,该调用返回 GMT(格林威治标准时间)的服务器时间。我们完成此调用所获得的最快时间为 150 毫秒。由于此特定调用的请求和响应非常简单(小),因此传输时间和编组和解组时间对总调用时间的贡献非常小。此外,实际处理时间也应该非常小,因为这是返回 GMT 的服务器时间(因此可能没有进行时区转换)。这意味着每次调用的开销高达 150 毫秒,包括延迟。因此,对于 Salesforce.com 来说,150 毫秒是任何调用的绝对下限——任何调用都将花费 150 毫秒加上传输时间、编组和解组时间以及请求逻辑的实际处理时间。

如果 ASP 支持压缩(Salesforce.com 支持)并且客户端环境支持压缩,则应使用压缩来最大限度地减少传输时间。启用压缩通常通过将 AcceptEncoding 和 ContentEncoding HTTP 标头字段设置为压缩格式来完成。

鉴于每次调用的开销很大,如果向 ASP 发送许多单独的请求,应用程序的性能将很差。应用程序需要尽一切努力通过在适当的地方缓存数据、使用 API 提供的机制将一组修改一起发送、以组而不是单独检索信息以及避免不必要的(冗余)请求来最大限度地减少单独调用的数量。

在使用互联网上的 API 时提高性能的策略不一定是新颖的,但它们在每次调用开销非常高的环境中尤为重要。

尽可能多地缓存数据非常重要。应用程序应该具有缓存数据的框架,以便在操作上下文中不会多次检索相同的信息。对于变化缓慢的设置数据,还应考虑在操作之间进行缓存。为此,监控在运行系统中对 ASP 进行的调用有助于定位正在执行冗余检索的位置。此处涵盖的 ASP 不提供任何缓存失效协议。对缓存的唯一支持是能够根据对象的修改时间检索对象。任何缓存方案都必须在战略时间使用基于修改时间的查询来刷新缓存的数据。

API 将提供在对 ASP 的单个调用中对操作进行分组或批处理的某些方法。(但请注意,对于本文涵盖的 ASP,批处理没有事务语义。)利用分组/批处理非常重要,尤其是在应用程序本身正在处理批处理类型操作的情况下。应用程序不应通过单独处理批处理中的每个项目来执行此操作,因为这几乎总是会导致错过对发送到 ASP 的操作进行分组以及以组而不是单独从 ASP 检索信息的机会。

在一个批处理类型操作中,将请求分组到一个调用中如何节省大量时间的一个示例是将产品推送到 CRM 系统的操作。此操作从源批量接收产品信息,并在 CRM 系统中创建产品。如果为批处理中的每个产品单独调用 CRM 系统,那么我们将为每个产品产生每次调用的开销。当我们通过单个调用将批处理中的产品组发送到 CRM 系统时,我们发现节省了大量时间,从而减轻了每次调用的巨大开销。表 1 中描述了在单个调用中为不同数量的产品在 Salesforce.com 中创建产品的结果。

利用 API 提供的任何功能来最大限度地减少发送到服务器的请求非常重要。Salesforce.com 的 upsert 命令就是这样一个功能的示例,其中如果对象不存在将执行插入,但如果对象存在将执行更新。这节省了首先执行查询以确定是否需要执行更新或插入的步骤。

应用程序应尽可能尝试确定正在进行的修改是否是冗余的。如果应用程序碰巧获取了对象的当前内容,则应将此状态与对象的新状态进行比较,并确保在向服务器发送修改请求之前存在更改。

与任何 API 一样,API 中操作的性能也会有所不同。识别缓慢的操作并谨慎使用它们非常重要。向 ASP 报告缓慢的操作非常重要,因为它们通常会尝试提高这些操作的性能,或尝试通过引入操作的替代形式来减轻影响。例如,ASP 可能会对特定类型的操作进行分组,至少可以最大限度地减少每次调用开销的贡献。

对于应用程序来说,设置对 ASP 进行调用的各种超时值非常重要。这些超时的设置可能在通信级别或 Web 服务客户端级别。对于交互式操作,应用程序应将连接建立超时设置为一个相当小的值;在应用程序声明由于无法与 ASP 建立连接而导致失败之前,用户不应承受长时间的等待。应用程序应设置足够大的响应超时,以便发送到 ASP 的操作避免 Web 服务客户端过早放弃。

由于这些 API 是基于 Web 服务的,因此应用程序使用的 XML 解析器的性能,特别是 Web 服务客户端,尤为重要。在我们的案例中,客户端本身是一个 Web 应用程序。当我们更改 Web 服务器版本时,我们遇到了 Web 服务器提供的默认 XML 解析器的 XML 解析器内存使用问题。我们改为专门为我们的 Web 应用程序使用解析器,并且我们选择了我们在旧 Web 服务器上使用过的解析器的新版本。内存利用率特性有所改善,但我们遇到了性能(CPU 利用率)问题。我们最终回到了我们在使用旧版本 Web 服务器时使用的 XML 解析器。

结论

开发使用 API 通过互联网与 ASP 集成的应用程序需要使用策略和技术来克服某些障碍。应用程序必须处理不可靠且具有高延迟的通信介质、并非始终可用的 ASP 以及不提供事务支持的 API。这是一个挑战,但软件即服务的承诺可能使这种努力值得。

参考文献

  1. Salesforce AppExchange API—AppExchange Web 服务开发人员指南; http://www.sforce.com/us/docs/sforce70/wwhelp/wwhimpl/js/html/wwhelp.htm
  2. Siebel Web Services CRM OnDemand 指南,版本 5。
  3. QuickBooks SDK 程序员指南,版本 5.0。
  4. WS-Security 标准; http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wss
  5. Web 服务事务规范; http://www-128.ibm.com/developerworks/library/specification/ws-tx/

Len Takeuchi 是 Salescentrix 的高级软件工程师,他在那里参与 AccountDynamics 的设计和开发,AccountDynamics 是一种托管服务,可将按需 CRM 解决方案链接到按需和基于场所的会计解决方案。他拥有不列颠哥伦比亚大学计算机工程硕士学位。

acmqueue

最初发表于 Queue vol. 4, no. 5
数字图书馆 中评论本文





更多相关文章

Satnam Singh - 使用容器进行容器的集群级日志记录
本文展示了如何使用开源工具实现集群级日志记录基础设施,并使用与组合和管理正在记录的软件系统相同的抽象来部署该基础设施。收集和分析日志信息是运行生产系统以确保其可靠性并提供重要审计信息的必要方面。已经开发了许多工具来帮助聚合和收集特定软件组件(例如,Apache Web 服务器)在特定服务器(例如,Fluentd 和 Logstash)上运行的日志。(Fluentd 和 Logstash。)


Peter Kriens - OSGi 如何改变了我的生活
在 20 世纪 80 年代早期,我发现了 OOP(面向对象编程),并深深地爱上了它。像往常一样,这种爱意味着说服管理层投资这项新技术,最重要的是,送我去参加酷炫的会议。所以我向我的经理推销了这项技术。我向他描绘了美好的未来,有一天我们将从现成的类中创建应用程序。我们将从存储库中获取这些类,将它们放在一起,瞧,一个新的应用程序就诞生了。今天我们或多或少地认为对象是理所当然的,但如果我说实话,我在 1985 年向我的经理提出的建议从未真正实现。


Chris Richardson - 解开企业 Java 的难题
关注点分离是计算机科学中最古老的概念之一。这个术语是 Dijkstra 在 1974 年创造的。1 它很重要,因为它简化了软件,使其更易于开发和维护。关注点分离通常通过将应用程序分解为组件来实现。然而,存在跨领域关注点,这些关注点跨越(或横跨)多个组件。这些类型的关注点无法通过传统的模块化形式来处理,并且会使应用程序更复杂且难以维护。


Michi Henning - CORBA 的兴衰
如果确切地计算 CORBA 的历史,它大约有 10-15 年的历史。在其生命周期中,CORBA 经历了从早期采用者的前沿技术,到流行的中间件,再到相对默默无闻的利基技术的转变。研究为何 CORBA——尽管曾经被誉为“下一代电子商务技术”——遭遇这种命运,是很有启发意义的。CORBA 的历史是计算机行业多次上演的历史,而且似乎当前的中间件努力,特别是 Web 服务,很可能会重演类似的历史。





© 保留所有权利。

© . All rights reserved.