1,2,3,4.

并发测试--转

上一篇 / 下一篇  2012-05-30 13:52:15 / 个人分类:我的工作

在软件应用当中,处理并发性问题主要有3种方法:
1)保守方式
这种并发性模型中数据上加了锁(如此一来会有很多的锁)。如果一个用户已经打开了一个数据,那么这允许编辑的环境中,系统会拒绝来自其他用户的读取数据的请求。此方法很安全,但不方便,导致后来的用户不能对数据进行访问。由于系统必须管理这些记录锁,所以这种模型中实现上有一定复杂度。
2)开放方式
在这种模型中,总是允许用户读取数据,甚至还允许更新数据。但是,当其他用户试图保存数据时,系统会检查自从这个用户检索数据以后是否有其他人更新过数据。如果其他数据发生了变化,那么更新就失败了。这种模型适用于不大可能出现多人同时修改同一数据的情况;但是,如果用户花费了大量时间来修改数据,最后却发现根本不能保存修改(会很郁闷^_^),那么他们会感到不方便。此时必须重新检索(刷新)并重新完成修改。
3)没有并发保护
胜利属于最后一个用户。这是所有模型中最简单的一种模型。这种方法并不对多个用户编辑相同的数据提供保护,即系统只承认最后一个用户的保存行为。之前用户的保存会丢失。此外,根据系统的具体实现方式,当两个用户试图同时保存数据时,这种方法可能会导致数据损坏。
软件采用何种并发处理方式,会影响到程序的性能、可用性和数据完整性。因此,为了验证应用程序在并发处理方面是否正确和有效(合理),根据为项目选择的并发性模型设计相应当并发性测试是非常重要的。
测试并发性很困难,时机是一个问题。无论系统处理并发采用了何种模型,为了确定系统是否『恰当』地保护理数据,测试人员必须模拟2个用户同时读取或写入数据。
在并发性测试中,可以综合考虑手动和自动化测试技术。要设计并执行正确的测试,其关键时要对系统实现有所了解。
当相同的数据可以通过不同界面或者功能更新时,并发性测试会变得更加复杂。例如,当一个用户在编辑记录,而另外一个用户却删除了此记录,此时系统必须加强对并发性的控制。事实上,为了保证正在编辑的记录不被其他功能所修改,应该测试『所有』可能访问这条记录的功能。
系统级的非功能性需求规格说明书,通常应该详细说明系统处理并发性问题的方式。如果某西特殊的系统功能与此有冲突,那么应该在描述这些特殊功能的需求文档中对之详细说明。
可见,测试人员要做到对系统实现方式了解,是多么重要和困难。

对不同的并发性模型,测试过程应该关注的要点:
保守方式
测试应主要关心的是验证能否正确定取得、释放(尤其是释放)锁,并且能正确处理应用程序中所有可能更新这条记录(或数据)的部分。这里主要关心的是一下3个方面:
锁的获得。关键是系统必须把锁正确地分配给第一个请求的用户。如果获得锁到代码实现有错误,就会导致多个用户都认为他们自己拿到了锁,但是当他们试图保存数据时,可能会遇到错误或者其他不可预料的系统行为。
获得锁的操作是可以测试的,具体方法是:让2个用户同时进入编辑状态(或者也可以有大量的请求)。
锁的效用。如果一个用户获得了锁,那么系统必须确保其他用户不能以『任何』方法和途径来修改这个数据,其中包括对数据的更新和删除。具体实现方法是:让一个用户打开一条记录(进入编辑状态并保持这个状态),同时其他用户在应用程序的所有地方试图编辑、删除或者以其他方式来更新数据。系统应该【拒绝】所有其他用户更新数据的企图。
锁的释放。测试人员必须验证:当编辑数据的用户释放了这条记录后(无论是更新完毕还是取消操作),系统能够成功地让其他用户使用这条记录。释放锁需要注意的一个重要方面是错误处理,也就是持有锁的用户遇到错误(例如系统崩溃了)的情况下,系统应该完成什么样的操作。锁是否失去控制(如释放不了)?系统重释放锁定故障中重新恢复的能力需要重点考虑。
开放方式
在某种程度上,该并发模型的实现复杂度稍低。因为允许所有用户检索并编辑数据,所以『更新』是唯一要关注的要点。在手工的方法中,2个测试人员编辑数据,然后试图同时保存数据。第一个用户更新操作应该是成功的,但第二个用户应该得到适当的提示信息。
与保守的并发模型一样,在开放的模型中,测试人员必须保证对『所有』可能修改数据的地方,开放的并发性都得到了验证,其中包括来自用户界面的不同部分的记录操作。
没有并发控制。这是最容易出错的并发模型。测试方法与测试开放的并发模型非常相似,区别是:无论更新请求的顺序如何,所有用户都应该成功完成更新操作。注意,应该关注数据的完整性。测试人员还应该验证是否正确的处理了更新错误。

测试组对系统实现计划的研究有助于他们正确地确定采用何种策略来测试并发

 

 

 

 

并发测试中,对于数据库的操作是非常重要的一个环节,对于行级,列级,表级的锁我们都要考虑到,才能真正实现并发测试,保证数据库连接的正确性和数据的完整性。

 

 

 

 

DB2通用数据库的并发性(1)

发布: 2007-7-13 22:35 |作者:佚名    |来源:网络转载     |查看: 10|进入软件测试论坛讨论

领测软件测试网

在数据库管理系统(DBMS)的领域中,术语并发性用于表示不止一个应用程序基本上(从用户的角度来看)同时访问同一数据的能力。因为DBMS的主要优点之一就是可以在多个用户和多个应用程序中共享数据,所以数据库系统应该提供一种管理并发访问数据的方法。DBMS必须确保维护数据的一致状态和数据的完整性。

取得该效果的一种方法就是实施只串行(serial-only)模式来处理数据库请求。即每个事务都要等待另一事务(具有更高的优先权或者比它早启动)完成其工作。然而,对于现在的在线系统和客户异常来说,这种处理方式所产生的性能水平简直令人无法接受。

而另一种方法就是,DBMS可以通过的方式管理多个应用程序对数据的访问。锁是一种软件机制,用于在维护数据完整性和一致性的同时,允许尽可能大的吞吐量(通过最大限度地并发访问数据)。

并发性控制的重要性

如果没有控制并发性的有效方法,就可能损害数据的完整性和一致性。DBMS必须保护数据库,防止发生下列状况:

·        丢失更新——假设应用程序A和应用程序B同时读取数据库中的同一行,并且都为其中某一列计算新值。如果应用程序A先用其新值更新该行,随后应用程序B又更新同一行,那么第一次的更新(由应用程序A执行的)就会丢失。

·        不可重复读——某些应用程序进程可能要求完成以下事件序列:程序A从表中读取特定的一行,然后继续进行其他的SQL请求。稍后,程序A再次读取开始的那一行,并且必须在所有的列中找到与第一次读取相同的值。如果缺乏合适的并发性控制,另一应用程序就可能在这两次读取操作之间修改该行数据。

·        访问未提交的数据——应用程序A更新一行中的某些列的值,而在提交该修改之前,应用程序B读入该行的新(更新)值。如果应用程序A接着又撤销更新值(通过程序逻辑中的SQL ROLLBACK语句,或者因为发生错误由DB2 UDB自动进行回滚),那么,应用程序B对该行的处理就是基于未提交的(因而可能是不正确的)数据进行的。

在维护数据完整性的同时,提供多个应用程序同时访问数据的能力称作并发性控制

锁是一种由DB2 UDB用于完成并发性控制的软件机制。锁实质上就是一个控制块,将DB2 UDB对象或资源与应用程序关联起来,并控制其他应用程序如何访问同一对象或资源。与DB2 UDB资源有关联的应用程序被称为持有拥有该锁。

通过使用锁,DB2 UDB(管理该数据库)可以防止发生上述几类问题。DB2 UDB与另一MVS地址空间IRLM配合管理这些锁。IRLM将跟踪这些锁及其所有者,以确定应用程序请求的DB2 UDB资源是否可用于该类工作。资源可以是锁定的共享的,这取决于当前资源上的锁的持有者所进行的处理类型,以及请求应用程序所预期的处理类型。

锁模式

最常用的两种锁模式是共享的排他的。共享锁与只读操作有关联,这意味着持有该锁的应用程序可以读取数据,而其他应用程序也可以读取该数据。排他锁与写操作有关联,这意味着持有该锁的应用程序有资格更新数据,但在锁所有者完成更新(将修改提交给数据库)并释放该锁之前,其他应用程序无法使用该数据。

DB2 UDBIRLM使用其他类型和子类型的锁模式来实现锁定和并发性控制。您可以在DB2 UDB Administration手册中找到关于这点的更多详细描述。

锁定粒度

除了使用各种锁模式,DB2 UDB还提供了不同的锁定级别,用以控制被锁定数据的范围。各种级别表示了DB2 UDB使用的锁定粒度,其范围可以从单个行到整个表空间。DB2 UDB根据锁定粒度来使用不同的锁模式。

具有多种锁定级别的理由十分简单。某些应用程序可能要求有权读取或更新大范围的数据,而其他应用程序则可能只要求访问窄得多的范围。如果只能使用一种锁定级别,则会降低整个系统性能。例如,一下子锁定太多数据会强制其他应用程序进行不必要的等待。否则,DB2 UDB可能使用过多的系统资源,尝试服务对附加数据资源进行锁定的附加请求。能够实现多种级别的锁粒度可以极大地提高并发性水平。

暂挂

若一个应用程序进程请求一个锁,而该锁已被另一应用程序进程所拥有,且不能共享,此时,就称该进程为暂挂的。请求应用程序会被挂起,即它将暂时停止运行。锁请求的优先次序如下:将新来的锁请求按照接收次序进行排队。已经持有锁的应用程序的请求以及进行锁提升的请求要比新应用程序的请求先得到服务。而在那些分组中,请求次序则为先进先出(first infirst outFIFO

超时

当应用程序处于暂挂状态(见上面)超过了预设的一段时间间隔,那么就要终止该应用程序。该应用程序被称为已经超时。在终止该应用程序之前,会在SQLCA中收到一条合适的错误消息。SQLCASQL通信域)是SQL应用程序预留的一块大小固定的存储区域,用于从DB2 UDB向程序传递条件代码和其他信息。

某些操作,如COMMITROLLBACK,就不能超时。在下面的子标题RESOURCE TIMEOUT中,将对决定应用程序进程可以等待资源多长时间的预设时间间隔进行讨论。

死锁

当两个或更多应用程序每个都持有另一应用程序所需资源上的锁,没有这些资源,那些应用程序都无法继续完成其工作时,这时就会出现死锁的状况。

以下是一个简单的死锁场景:

1. 应用程序A访问表T,并请求页面X上的排他(非可共享的)锁。

2. 应用程序B访问表T,并请求页面Y上的排他锁。

3. 然后,应用程序A请求页面Y上的锁,同时仍然持有页面X上的排他锁。应用程序A将被挂起,因为应用程序B具有页面Y上的排他锁。

4. 然后,应用程序B请求页面X上的锁,同时仍然持有页面Y上的排他锁。应用程序B将被挂起,因为应用程序A具有页面X上的排他锁。

5. 这是一种僵持情况。应用程序AB都无法继续工作。

在一段预设的时间间隔之后(请参阅标题DEADLOCK TIME下面的讨论),DB2 UDB将终止当前工作单元,因为某个应用程序陷入死锁状态(通常为所做工作最少的应用程序)。这将释放终止程序所持有的锁,并允许剩余的应用程序继续下去。DB2 UDB将向被终止的应用程序的SQLCA发送描述性的错误消息和信息。

实用程序和命令的并发机制

SQL应用程序使用事务锁来控制对DB2 UDB对象的并发访问时,DB2 UDB实用程序和命令可以通过其他方法访问DB2 UDB对象,即声明(claim)、放弃(drain兼容性规则。

声明是指通知DB2 UDB当前正在访问某个特定对象。提交之后,该声明通常不会继续存在。为了在下一工作单元里访问DB2 UDB对象,应用程序需要进行新的声明。声明通知DB2 UDB当前正关注某个DB2 UDB对象,或是该对象上存在活动。只要DB2 UDB对象上存在声明,在释放那些声明之前,就不能采取任何放弃(drain)。

放弃(drain)是指通过下列方式来访问DB2 UDB对象的动作:

1. 阻止对对象进行任何新的声明。

2. 等待释放对象上现有的所有声明。

DB2 UDB对象上的放弃导致DB2 UDB停止(quiesce)所有当前正声明该资源的应用程序,其方式为允许它们到达提交点,但阻止它们(或任何其他的应用程序进程)进行新的声明。Drain锁还阻止冲突进程同时放弃(drain)同一对象。

DB2 UDB一般通过一组兼容性规则来控制实用程序的并发操作。如果两个实用程序不需要同时以不可兼容的模式访问相同的DB2 UDB对象,就将它们视为是兼容的。当一个实用程序作业开始时,DB2 UDB就检查系统,查看当前是否有其他任何实用程序正处理同一DB2 UDB对象。如果该对象当前未被另一实用程序访问,或者如果另一执行实用程序是可兼容的,该实用程序才可以继续。

 

数据库设计考虑

取得高度并发性应该是指导DB2 UDB数据库初始设计的目标之一。在创建各个表的同时,可能要考虑许多影响并发性的功能。您可以在实现创建之后再添加某些功能(例如通过更改DB2 UDB对象),但另一些功能则无法添加,或者至少需要大量重复操作和/或打乱当前实现。因此,最好是一开始就考虑这些问题。

分区

我极力建议您将较大的表创建为分区表。一个分区表空间只包含单个分区表。要基于分区索引的键范围将该表分成多个分区。每个分区都是作为单独的数据集(dataset)来创建的,并且可以作为单独的实体由DB2 UDB加以处理。

对于大量的批处理操作(INSERTUPDATEDELETE),您可以将大型作业划分成较小的作业,利用该分区表结构。许多这些较小的作业可以并发运行(对不同的分区进行),以便减少整个批处理操作的占用时间,从而使另一应用程序进程可以更早地访问该表。

分区表以类似的方式使实用程序作业只作用于所选择的分区,从而允许其他作业或应用程序进程并发访问表中的其他分区。在许多情况下,DB2 UDB实用程序本身就具有利用分区表的能力,而在其他情况下,它只为用户提供了设计其工作负载的选项,以便支持DB2 UDB数据的更高并发性级别。

锁升级

DB2 UDB使用升级技术来平衡锁定性能开销的并发性需求。当一个应用程序进程持有单个表或表空间上的大量页面锁、行锁或LOB锁时,DB2 UDB就获取该资源上的表或表空间锁,然后释放该资源上以前的页面锁、行锁或LOB锁。该过程称作锁升级

如果一个使用分区锁定(带有LOCKPART YESCREATEALTER)的表上发生锁升级,那么,就只升级当前被锁定的分区,未锁定的分区仍旧未锁定。一旦表空间中发生了锁升级,那么就要用表空间锁来锁定随后访问的未锁定分区。

在执行应用程序时,DB2 UDB首先使用页面锁或行锁,并且只要该进程访问相对较少的页面或行,还会继续这样做。当该应用程序访问许多页面或行时,DB2 UDB将变为使用表锁、表空间锁或分区锁。调用锁升级的准确时间是由LOCKSIZELOCKMAX.的值决定的。

LOCKSIZE

LOCKSIZECREATE/ALTER TABLESPACE语句的选项,在应用程序进程访问表空间中的表时,控制DB2 UDB获取的何种类型的锁(即,它决定该锁的大小,这有时也称作锁粒度)。该选项的可以是LOBTABLESPACETABLEPAGEROWANY

CREATE TABLESPACE语句的LOCKSIZE参数默认为ANYLOCKSIZE ANY允许DB2 UDB选择锁大小。DB2 UDB通常将LOCKSIZE PAGE用于非LOB的表,而将LOCKSIZE TABLESPACE用于LOB表。

我建议在创建表空间时使用该默认值,除非您有理由进行其他选择。如果您选择修改LOCKSIZE,那么就要根据使用该表空间的应用程序的性能监控结果和并发性特点来做决定。

使用何种大小的锁

DB2 V4中才开始可以使用行级锁。之前,数据页是最小的锁定单元。I/T行业中的许多人都假定行锁是并发性问题的灵丹妙药,但实际上,它并不能解决所有的并发性问题。在经历许多锁等待、死锁和超时的环境中,它也许提供了较大的改进。但在其他情形下,DB2 UDB可能在获取更多锁上消耗资源,同时无法成比例地提高并发性。

因为IRLM获取、维护和释放行锁所需的处理与页面锁需要的大致相同,所以关于指定锁大小的决定其实就是在较高的锁定开销与并发性的潜在提高之间进行权衡。

因此,至于是使用页面锁还是使用行锁,这取决于您的数据和应用程序的特点。如果您觉察到使用页面锁定级别的表空间的数据页上存在大量竞争,那么就请考虑使用行锁。通过在行级别而非页面级别上进行锁定,可以极大地减少与其他应用程序进程的竞争,特别在访问是在随机的情况下。

但是,如果多个应用程序正以不同的顺序更新某一页上的相同行,那么行锁导致的竞争甚至可能比页面的还要多。这是因为,通过页面锁,第二个以及随后的应用程序在访问该页面之前,都必须等待第一个应用程序完成,而它们就可能超时。通过行锁,多个应用程序可以同时访问同一页上的行,但如果它们试图访问相同的行集,就可能死锁。

使用LOCKSIZE TABLESPACELOCKSIZE TABLE之前,用户必须相当确定没有其他重要的应用程序进程需要并发访问该对象。在任何表上指定LOCKSIZE ROW之前,极为明智的做法就是先对增加锁开销来提高并发性是否值得进行估计。

小型表

如果一个DB2 UDB表兼具尺寸小和高使用率的特点,那么就考虑使用LOCKSIZE ROW,特别是每个页面中有许多行的时候。此外,因为表十分小,锁粒度将不会给锁开销带来较大的性能影响。

DB2 UDB对象和授权的分组

通常总是将与同一应用程序逻辑相关的表分组到一个数据库中。理想情况是,每一个应用程序进程都引用尽可能少的DB2 UDB数据库。而且,要设法给用户不同的授权ID来使用不同的DB2 UDB数据库。实际上,这将增加可能应用程序进程的数目,同时可能减少每个应用程序进程可以访问的数据库数目。因此一般说来,组合相似的事物分开不同的事物

 

应用程序设计考虑


TAG:

 

评分:0

我来说两句

日历

« 2024-04-25  
 123456
78910111213
14151617181920
21222324252627
282930    

数据统计

  • 访问量: 5517
  • 日志数: 11
  • 图片数: 2
  • 文件数: 1
  • 建立时间: 2011-12-12
  • 更新时间: 2012-05-30

RSS订阅

Open Toolbar