IT运维管理,创造商业价值!
中国IT运维网首页 | 资讯中心 | 运维管理 | 信息安全 | CIO视界 | 云计算 | 最佳案例 | 运维资源 | 专题策划 | 知识库 | 论坛

使用日志作为应用程序的架构(2)

2008年07月16日
IBM中国/

一个日志客户端发送一条日志消息给 Web 服务, Web 服务接收到日志消息后,如果有必要的话除去重复的消息,然后对消息进行处理。一旦处理完毕,它将发送一条确认消息给客户端。

由于这篇文章不是用来专门讨论 WS-Reliability 标准,因此,我们不会讨论整个标准,但将会讨论其中的几个关键元素,特别是与可靠日志服务相关的特性元素。

首先,日志请求消息中包含的关键元素如下所示:

  • Message-ID: 这是在消息发送前被指派的序号。通过这种方式, Web 服务在一条消息被重复提交多次的情况下能够避免重复处理,同时还能够保证消息之间正确的次序。
  • Ack-Requested: 这一元素允许客户端来决定对于发送的消息是否需要确认。对于一个可靠的日志 Web 服务,这一属性标志必须为真。
  • Duplicate-Elimination: 根据这一属性,客户端可以决定服务器是否需要进行去除重复消息的处理。对于一个可靠的日志 Web 服务,这一属性标志必须为真。

确认消息中唯一一个重要的元素是字段 Ref-To-Message-ID 。 这一字段包含了确认消息所回应的日志消息的序号(Message-ID)。

从上面列出的几个元素你可以看到, WS-Reliability 规范覆盖了 “可靠日志的需求”一节中提出的 3 个需求。上述特性提供了可靠日志在协议层的解决方案,但并没有提供应用层的解决方案,如可靠日志第 4 个需求,但它为解决应用层的问题提供了基础。

在下面一节,我们列出了在应用层可能发生的错误,并提出了一个可以解决这些错误问题的解决方案。

日志在应用层的可靠性问题
为举出应用层的可靠性问题,让我们重温回顾一下 图 3中的日志场景:

  1. 客户端对服务器发出日志请求
  2. 服务器接受到日志请求
  3. 服务器序列化日志请求
  4. 服务器发送确认给客户端
  5. 客户端接收到服务器发送的请求信息

上面的流程整体上提供了一种可靠消息传递机制:一个客户端发送一条日志请求,服务器在完成消息存储之后发送一条确认信息。但上述流程并不是意外安全的,因为在下述情形下上述流程将被打破,随之而来的便是没有确认消息返回到客户端:

  • 如果客户机无法定位服务器怎么办?
  • 如果请求消息丢失怎么办?
  • 在存储或尚未存储日志信息的情形下,服务器崩溃怎么办?
  • 如果确认消息丢失怎么办?
  • 如果客户机崩溃怎么办?

在上述每一种情况下,你都必须保证日志消息被存储且客户端接收到确认消息。在某些条件下要确保这一点可能会很困难。下面我们将对上述情况进行详细讨论

客户机无法定位服务器
如果客户端不能够定位服务器,则将导致日志服务失败。但这个问题客户端可以进行控制,因此,服务器端或协议层不需要特别的机制来处理这一状况。

如上所述,日志信息在被日志客户端提交到服务器端后绝不能够丢失。如果客户端不能够定位服务器,将出现下面两种情形:

  1. 服务器暂时无法连接。
  2. 服务器永久无法连接,或至少看起来如此。

设计一个基本的假设是:服务器的连接状况对于业务应用程序尽可能透明。

在第一种情形下,日志客户端能够针对服务器无效的状况对业务应用程序保持透明。日志客户端将从业务应用程序接收的日志信息重复(使用同一个序号)发送,如果客户端遇到的是服务器的瞬间故障,一旦服务器功能回复,它将马上处理日志信息。

如果在 n 次尝试后仍无法连接服务器,客户端有理由认为服务器永久无法连接,因此需要将这一状况报告给调用日志客户端的业务应用程序。

请求信息丢失
在某些情形下客户端和服务器之间的消息可能会丢失,如传输层上的包或当一个消息在一个跳转链上进行传输时,其中的一个跳转突然崩溃。

做为一个设计特色,消息确认使得客户端能够确定请求信息是否丢失。如果请求信息在发送到服务器的途中丢失,或者服务器在处理请求信息之前崩溃,那么客户端不会接收到请求消息。

为了避免客户端与服务器间的临时连接超时的影响,客户端将重复发送 n 次消息,如果这种连接超时依旧存在,客户端在重复发送了 n 次后将停止重复发送日志信息并向调用客户端的业务应用程序报告这一错误。

服务器故障
如果服务器发生故障,客户端将从服务器得不到确认信息,将有可能发生两种情形:

  • 服务器在接收到信息之后但在存储信息之前崩溃。
  • 服务器在存储信息之后但在发送响应信息之前崩溃。

在上述两种情形下,你都希望客户端能够重新发送日志信息给服务器而且这些信息不会被服务器多次处理。就像你希望任何服务器上的故障对客户端都是透明的一样。

在第一种情况下,由于消息尚未被处理,客户端只需要简单的提交信息,而服务器端不需要采取任何特殊行为。

下面考虑第二种情形,你会注意到当第一次发送的消息被再次提交,则日志消息将会被处理 2 次,因为这条日志信息已经被记录了。因此,客户端必须能够保证在服务器不会第二次处理消息的前提下重复提交信息。为解决这个问题,服务器必须包含一个状态变量来标识提交的消息已经被处理但确认消息尚未发出这一状态。

在协议层,架构方案为解决这一问题提出消息序号,或在 WS-Reliability 被称为的 Message-ID ,根据消息序号和服务器端的存储日志,服务器能够鉴别处重复提交的日志消息。

根据这个架构,你可以看出日志 Web 服务根据需要进行工作,不会将已经提交的信息进行重复处理。一个日志客户端提交信息给服务器。服务器接收到信息,然后检查存储日志来判断这条信息是否在之前已被处理。如果尚未被处理,换句话说,存储日志中不存在对应的条目,服务器将处理日志信息,如果处理成功,在返回确认消息之前,将在存储日志中创建一个条目。如果消息已经被处理,换句话说,存储日志中存在对应的条目,则服务器将不会处理消息而是立即返回确认信息。

需要注意是,要使架构能够正确工作,包含存储日志的文件系统绝对不能够溢出。

确认消息丢失
像日志消息一样,确认消息由于某些原因也会丢失,同样,客户端无法确切知道哪里发生了错误。然而,像上面提到的,通过使得服务器具有容错性,客户端可以简单的重新发送日志消息来等待确认信息的到达。

为将暂时错误与永久错误区分开,客户端可以采用与上面所述的同样的策略。客户端发送 n 次日志信息。如果在发送 n 次信息后仍旧没有接收到确认消息,客户端有理由认为系统遇到永久性故障,它可将这一故障信息返回给调用者或业务应用程序。

客户端崩溃
对于可靠日志来说,日志客户端将是一个业务应用程序的主要组成部分。业务应用程序的许多操作或任意操作都伴随着日志操作。由于日志客户端的同步特性,如果日志应用程序运行失败则业务应用程序同样也会失败。

提出的架构

组件
根据上节中讨论的内容,我们提出如 图 4 所示的架构.

图 4: 日志客户端和服务器架构
日志客户端和服务器架构

客户端提供了一组 API,业务应用程序通过它能够访问日志客户端。控制器包含日志客户端的业务逻辑。在客户端的底层,你将发现客户端使用的实现了传输协议的通信 API。

服务器包含一组通信 API 用来与客户端进行通信,一个存储日志用来保存状态,还有一个日志消息仓库。为实现上一节所讲的业务规则,通过一个控制器组件将服务器内的所有组件紧紧联系在一起。

日志需求与体系结构的关系
在对本节进行总结之前,让我们看一下体系架构是如何满足前面所述的日志需求的

  • 实现可靠的消息传递:请求/确认协议使得客户端能够判断消息是否传递到客户端。
  • 除去重复消息:由于服务器包含一个状态变量,因此重复的日志消息能够被除去。
  • 确保消息次序:由于日志客户端的同步特性,如果没有接收到前一条日志消息的确认信息,日志客户端将不会发送新的日志消息,日志消息将按照正确的顺序依次处理。

消息编号
在所提出的架构中还有一个重要但尚未进行讨论的设计特征,那就是消息编号。对于所提出的架构来讲,实现消息编号的一个最佳方法便是将 HTTP 会话 ID 与发送消息的时间戳进行组合。时间戳的保证了不同的日志消息具有唯一的序号。根据 HTTP 会话 ID ,服务器能够区分出哪一条消息是来自哪一个客户端,这一点对于重复消息的去除和并发的客户端间的区别至关重要。

事务语义支持的日志
一个事务性的运行环境确保一个应用程序的原子性、一致性、孤立性和持久性。这使得并行运行的应用程序在访问共享资源时得到保护,避免由于资源冲突而产生的资源冲突甚至崩溃。如果一个应用程序发生崩溃,那么他的所有操作将会被回退(原子性),如果一个应用程序成功,那么他的所有操作将被保证成功(持久性)。事务系统能够确保资源保持一致性,即使资源被同时访问(一致性)。事务系统同样能够保证应用程序的运行可以不管其它应用程序的运行情况,就像它自己在单独运行一样(独立性)。

日志对许多应用程序来说是都是一个重要的组成部分,至少存在两种类型的日志。 一般信息日志主要用来跟踪应用程序的步骤和操作。根据日志信息的用途,它对应用程序的操作有着或轻或重的影响。例如, 如果日志记录只是用来进行统计分析,少数几次失败的日志操作将是可以接受的。然而,如果日志是用来审计, 那么遗失日志记录将是不可接受的。

另外一种日志称为关键业务日志。它将影响到应用程序中与业务相关的其它部分。其它应用程序将读取关键业务日志并应用到它们的商业逻辑中。这种类型的日志将像其它的一些业务操作一样来被谨慎处理。例如一个财务日志记录,里面记录财务转帐信息,而且这一日志被用来进行投资兴趣分析或纳税凭证。

在本文中,我们定义了一个事务语法支持的日志服务,重点解决原子性语法。者并不意味者我们强制所有的日志行为做作为原子事务的一部分,而是根据日志信息是否事务敏感,我们可以给应用程序提供相应的事务语法支持。

事务性执行
如果有几个应用程序在并行运行,它们中的每一个都要执行一系列连续的操作,那么整个系统的执行过程就包括按照一定次序执行的、来自不同应用程序的不同操作。如果这些应用程序访问共享数据,它们就将导致破坏一致性的潜在冲突的产生。数据库系统中的一致性概念和预测锁定(请参阅 参考资料)对并发环境中的一致性问题给出了明确定义。数据库系统的并发控制和复原(请参阅 参考资料)给出了防止系统产生不一致问题的正确操作的属性。

原子性
原子性可能是一个成功事务执行的最基本属性。一个事务执行被称为一个原子是指它的所有更新操作要么全部成功,要么全部失败,这一点通常被称为 all-or-nothing 属性。如果你假设一个事务总是一个一致性的工作单元,整个系统的所有更新都被执行,很显然系统仍能够保持一致性。当一个事务执行已经开始执行但尚未完成,只有一部分更新操作被实际执行,你就不能假定整个系统的状态仍旧是一致的。你只有在系统的所有操作都被执行或都不被执行时,才能假设整个系统是一致的。

作为事务的基本属性,原子性被各种系统实现。在分布式系统中,原子性还表明一个事务应该在参与事务的所有节点中全部执行成功或全部失败。为确保这一点,两步提交协议(请参阅 参考资料中的 分布式数据库原理)被提出且在各种系统中实现。

发表评论请到:http://bbs.cnitom.com

相关阅读

图文热点

如何在交付周期中保护Web应用程序安全性
如何在交付周期中保护Web应用程序安全性Web应用程序是当今多数企业应用的前沿阵地。Web应用程序在一个复杂的混合性架构中...
微软加强Hotmail安全 加密通信介入
微软加强Hotmail安全 加密通信介入微软周一表示,他们计划在Hotmail中部署增强后的安全功能,确保攻击者无法实现非...

本类热点