简介
高可用性是重要数据库应用程序的关键需求。IBM DB2 9.5 提供了很多特性来满足这一需求。如果您对分布式平台上的 DB2 还不是很了解,或者已经使用过一阵子,您可能会发现这组处理可用性的特性令人困惑。什么时候使用哪个特性,当使用特性时,您希望完成什么目标?
本文的目的就是总结这些特性,并指导您理解如何使用 DB2 技术构建高度可用的数据库系统。此外,发现每种解决方案的成本和优点。
在开始之前,我们先来定义术语高可用性(HA)的意义。HA 是指要求在依赖性应用程序需要数据时能够提供数据。其目的是消除或尽量避免停机。与 HA 相关的一个术语是灾难恢复(Disaster Recovery,DR),DR 与 HA 的不同之处在于,它侧重于保护数据,防止因灾难性故障导致数据丢失。本文只关注 HA。
术语和客户机/服务器数据库架构
术语和客户机/服务器数据库架构
我们首先讨论一些术语和概念,这对理解高可用性十分重要。
一个数据库解决方案包括三个部分的软件:
用户应用程序
客户机软件
数据库引擎
除了软件,要得到一个有效的解决方案,还必须拥有一些其他资源:
服务器硬件
网络连接
磁盘存储
操作系统
当设计一个 HA 解决方案时,必须考虑所有这些方面。仅仅使数据库引擎高度可用未必就能创建出一个 HA 解决方案。HA 解决方案的设计并不完全是一个技术问题,它还必须考虑其他一些因素,例如解决方案的成本、技能需求以及管理需求。
数据库应用程序是基于客户机/服务器的。应用程序能否产生一致的结果,取决于数据库软件的完整性。虽然这一点是显而易见的,但是它在选择和设计解决方案时十分重要。
SQL 事务可分为两种类型:读和写。读事务是不需要插入、更新或删除活动的选择语句。而写事务则要更改至少一个数据库。读事务需要数据的一致视图 —— 即当同时提交两个读事务时,如果它们选择相同的数据范围,那么应该产生一致的结果集。写事务要求提交的数据库更改被持久化,即使出现故障时也是如此。业务需求会影响到什么 HA 解决方案是可用的或者是最适合的。通常,HA 解决方案的设计由两个因素驱动,正常运行时间(uptime)需求和事务一致性。如果业务要求更高的可用性,并且读一致性不是很重要,那么选择异步可能是更经济的方法。另一方面,如果事务一致性是关键需求,那么则需要选择更加同步的解决方案。如果事务一致性和可用性都是必需的,那么将进一步缩小可选择的范围。
高可用性
有两种类型的高可用性可供选择:持续可用性(continuous availability)和故障转移可用性(failover availability)。
持续可用性
持续可用性要求数据库引擎随时可用,没有可觉察的停机时间。在这些场景中,停机时间以不存在、一秒或数秒来度量。传统上,只会在最关键的应用程序中实现这种类型的可用性。为实现这个目标,需要有高度的冗余。
对于这些类型的系统,有三种基本的设计 —— 编程式(programmatic)可用性、共享(shared)可用性和多重副本(multiple copy)可用性。
编程式可用性
编程式的设计实际上是一个用户编程解决方案,它不是在数据库级实现的,而是在用户应用程序级实现的。实际上,应用程序在多个系统上实现 SQL 事务。一个系统上出现故障不会导致其他系统上的事务被中断。应用程序逻辑使应用程序即使在一个数据库系统出现故障时仍可以继续执行工作。
这种类型的系统具有最大的灵活性,但同时也要求实现大量的工作。当编写这些类型的环境时,DB2 对分布式工作单元和事务监视器的支持可以提供一定的帮助,但是大部分工作仍有赖于应用程序开发小组。编写的所有应用程序都必须支持您的设计。“开箱即用” 应用程序将不能理解您的环境。另外还需要解决其他问题:
保持数据库系统的同步
非确定函数的使用
非原子存储过程的使用
非确定函数是指根据不同的运行环境可能产生不同的输出的函数。例如,由于系统时钟不同步,或者语句不可能完全在同一时间到达系统,DB2 专用寄存器 CURRENT TIMESTAMP 在不同的系统上会产生不同的输出。
非原子存储过程是指不作为一个整体一起提交或回滚的存储过程。根据运行的环境,存储过程中的事务可能产生不同的结果。
表 1. 编程式可用性
优点 | 缺点 |
灵活性 | 应用程序开发时间和成本 |
缺乏对打包应用程序的支持 | |
复杂性 |
共享可用性
共享设计在共享关键资源的同时使用冗余系统。这种共享设计是这样工作的:如果有 2 个或更多的系统在工作,当其中一个系统出现故障时,其他的系统可以继续工作。成员之间并非完全独立,而必须通过共享机制或数据才能执行它们的工作。
最常见的共享资源是物理数据存储。图 1 演示了数据如何被存储在一个中央存储系统上,并被三个成员访问。
图 1. 共享可用性
为了让这种架构能够正确地运行,需要共享的资源不仅仅是共享存储。为了让每个系统执行工作,它们必须共享一些类型的锁和锁机制。锁机制使得每个系统可以在共享数据上执行工作,同时不会执行对其他成员正在执行的工作造成干扰。例如,如果一个成员正在更新一行数据,那么另一个成员就不能以未提交读(uncommitted read)以外的任何隔离级别读取这一行。为了防止这样的事情发生,成员之间必须共享锁机制。为了确保一致的视图时间,必须实现一个共享锁机制。
这种架构的特点是高度复杂,并且要求硬件和软件的高度集成。必须解决的问题有:锁机制、系统计时器集成、数据缓冲区共享或非共享以及日志记录机制。如何实现这些机制对于性能和可用性有很大的影响。如果成员不共享数据缓冲区,那么每个成员就有可能缓冲相同的数据。如果数据的所有关系可以简单地在成员之间划分,那么您将拥有更好的数据缓冲,但是有可能遇到事务路由问题。如果需要处理一个更新事务,而该事务由不拥有那部分数据的成员接收,那么需要将它路由到另一个成员。显然,这种路由会影响性能,您可能被迫通过在应用程序中实现代码来将事务路由给正确的成员。如果一个成员出故障,那么可用性可能受到影响,影响的大小取决于其他成员必须做什么事情才能继续工作。理想情况下,不需要做任何事情,其他成员可以继续执行工作,并且可用性不受影响。然而,一些共享设计要求挂起或停止所有事务,并重新初始化缓存和锁机制。这实际上造成了停机时间,直到这些任务被完成为止。
数据共享环境中的 DB2 for zOS 诠释了共享架构的理想目标。这个环境的基础是 z Parallel Sysplex,它提供了 sysplex 计时器和耦合设施(coupling facilities)。耦合设施是高度集成的组件,通过它们可以创建锁设施和缓冲池等共享资源。此外,成员之间的通信技术是非常高效的。一个成员出故障不会影响其他成员的事务工作负载。除了更好的可用性外,还可以得到更大的容量和更好的工作负载平衡。不需要对应用程序做出更改,就能有效地使用这个解决方案。
用于非 zOS 平台的 DB2 不支持这种类型的架构。
表 2. 共享可用性
优点 | 缺点 |
非常高的可用性 | 高成本 |
增加可伸缩性 | 需要专门化硬件 |
不需要更改应用程序 | 实现需要专门化技能 |
多重副本可用性
多重副本设计利用数据库的多个副本,工作负载分布在这些副本上。当一个副本出现故障时,工作负载继续在其他数据库副本上运行。使用一个数据库的多个副本时要解决的最大问题是,如何保持它们同步,以及如何跨多个副本创建一致的查询结果。有些类型的复制解决方案是创建和同步这些副本的最简单方法。但是,由于传统复制解决方案固有的异步本性,我选择了在故障转移小节描述这个场景。
xkoto 中的 Gridscale 提供了另一种多重数据库副本解决方案,这种解决方案具有高级的同步过程和负载平衡。图 3 显示了 Gridscale 解决方案的基本架构。
Gridscale 在数据库解决方案中充当事务层。它可以根据可用性、系统利用率或同步状态将事务性工作发送到任何数据库副本。如果一个副本变得不可用,那么只需将工作转移到其他副本。它将根据系统负载将工作负载转移给其他副本。
写事务(插入、更新和删除)被同时发送到所有副本。Gridscale 跟踪在响应写事务时被同步的副本。当对写事务作出响应时,它们才有资格接收之后的读事务(选择)。这种机制确保事务性工作总是产生一致的结果。
可以集群化 Gridscale 系统来防止它成为故障点。Gridscale 实现了自己的可在几种条件下使用的缓存和事务日志记录。如果一个读事务被发送到一个出现故障或者在合理时间内未能返回的副本,那么可以将该事务路由到另一个副本。这个过程对应用程序是完全透明的。如果某种类型的故障或维护使一个副本不可用,那么可以根据 Gridscale 事务日志对它进行同步,这个过程完成后,它便可以开始参与分布式工作负载。要增加更多的副本以取得更大的可伸缩性,只需从一个副本恢复一个备份,并允许 Gridscale 将新的系统与其他副本同步。
DB2 和 Gridscale 解决方案的实现和管理非常简单。可以使用 Gridscale 管理工具来创建和同步副本。通过 Gridscale 工具,可以估计整