第9章如何用好全局事务9.1什么是全局事务全局事务是由资源管理器管理和协调的事务,可以跨越多个数据库和进程。事务管理器一般使用XA二阶段提交协议与“企业信息系统(EIS)”或数据库进行交互。也就是当一个事务需要跨越多个数据库时,需要使用全局事务。例如,一个事务中可能更新几个不同的数据库。对数据库的操作发生在系统的各处,但必须全部被提交或回滚。此时,一个数据库对自己内部所做操作的提交不仅依赖本身操作是否成功,还要依赖与全局事务相关的其他数据库的操作是否成功,如果任一数据库的任一操作失败,则参与此事务的所有数据库所做的所有操作都必须回滚。在一个涉及多个数据库的全局事务中,为保证全局事务的完整性,由交易中间件控制数据库做两阶段提交是必要的。但典型的两阶段提交,对数据库来说事务从开始到结束(提交或回滚)时间相对较长,在事务处理期间数据库使用的资源(如逻辑日志、各种锁),直到事务结束时才会释放。因此,使用典型的两阶段提交相对来说会占用更多的资源,如果网络条件不好,如低速网、网络颠簸频繁,情况会更为严重。9.2本地事务的优缺点本地事务容易使用,但也有明显的缺点:它们不能用于多个事务性资源。例如,使用JDBC连接事务管理的代码不能用于全局的JTA事务中。另一个缺点是局部事务趋向于侵入式的编程模型。9.3Tuxedo对事务的控制与管理当客户端连接到Tuxedo并创建一个全局事务时,TM(TransactionManager,事务管理器)就会在公告板(BB)里面创建一个事务,由TMS向GTT(GlobalTransactionTable,全局事务表,里面包含当前事务的状态信息)中插入一个条目,然后分配一个GTRID(GlobalTransactionIdentifier,全局事务标识符)来对该事务进行跟踪。Tuxedo的事务管理由TMS完成,TMS把各种RM接入到Tuxedo中的分布式计算中来,并对RM中执行的事务进行跟踪和两阶段提交。Tuxedo对事务的管理工作主要包括创建TMS、创建TLOG、运行时事务的监控和迁第9章如何用好全局事务121移。每一个在Tuxedo中用到的RM,都需要创建一个专用的TMS,否则无法在UBBCONFIG文件中调用。创建TMS的命令为:buildtms。这个命令需要从RM文件中读取信息,包括RM名、XASwitch名,以及XA支持库。为了恢复全局事务,TMS使用TLOG来记录事务日志。在每台Tuxedo主机上,只需创建一个TLOG文件,它就会被这台主机上所有的TMS实例共享使用。如果一个全局事务还没有完成,就会在TLOG文件中占用一个分页的空间(512KB),事务完成之后,它在TLOG中的记录被自动删除。在全局事务中,如果一个事务在提交前失败,在事务超时以后,TMS会把它的状态从TMGACTIVE改变为TMGABORTONLY,在Tuxedo下一次进行健康检查时,会把它从GTT中清除。另外,当Tuxedo检测到只有一个RM参与到分布式事务中时,TMS则会略去第一阶段时的事务征集过程,直接进行事务的提交或者回滚。9.4常用事务相关的函数为了界定全局事务,Tuxedo除了支持标准的TX接口外,还提供了一套自己的事务接口,其中基于TX接口的包括以下几种。1.tpopen()这个函数被服务进程和TMS(事务管理器)调用,用于建立和RM(资源管理器,一般为数据库)的连接。连接信息由服务进程组的OPENINFO参数提供。服务进程和TMS在启动时,通常会自动回调tpsvrinit()函数,tpopen()通常在tpsvrinit()函数中被调用。连接失败时返回值为–1,并把错误号保存在全局变量tperrno中。2.tpclose()这个函数在服务进程和TMS的析构函数tpsvrdone(3c)中被隐含调用,用于关闭一个RM的连接,关闭信息由进程组的CLOSEINFO参数提供。3.tpbegin()该函数的功能是开始一个全局事务,并分配一个GTRID(全局事务标识符)来对它进行跟踪。4.tpcommit()该函数的功能是提交一个全局事务,提交成功时返回零,失败时返回–1。提交失败时,可能把tperrno设置为TPETIME、TPEABORT、TPEPROTO、TPEHAZARD、TPEHEURISTIC或TPEINVAL。叱咤风云:Tuxedo企业级运维实战122TPETIME表示事务已经超时,状态未知,可能是已经提交,也可能是已经回滚。TPEABORT表示某个RM不能提交它的局部事务。TPEPROTO表示协议错误,即调用点不在一个有效的事物上下文中,如事务的提交者不是事务的初始者或者提交的事务根本不存在。TPEHAZARD表示由于某些失败的因素,全局事务已经启发式完成。TPEHEURISTIC表示由于启发式的决策,部分RM提交了事务,部分RM回滚了事务。TPEINVAL表示函数调用的参数设置不对。5.tpabort()回滚一个全局事务。6.tpsuspend()该函数功能为挂起一个全局事务。当某些对RM的操作不想纳入当前的事务上下文中时,可以在调用点之前先挂起事务,当前事务完成后,再恢复事务。7.tpresume()恢复一个被挂起的全局事务。8.tpscmt()该函数的功能是设置提交控制参数TP_COMMIT_CONTROL的值。9.tpgetlev()通过该函数的返回值来判断当前的调用点是否处在全局事务中。如果返回值是1,表示当前调用点正处在全局事务中,如果是零,表示不在全局事务中。9.5数据库连接9.5.1TMS介绍Tuxedo事务管理器(TMS)必须跟踪分布式事务处理的整个流程,记录足够的信息以便在任何时候进行提交或回滚,因此TMS使用事务日志文件(TLOG)来记录跟踪信息,同时为了区别系统中同时进行的不同事务处理流程,TMS又为不同的事务处理分配了一个全局事务编号(GTRIDs)。在事务处理的不同阶段,TMS将执行不同的动作,见表9-1。表9-1阶段TMS动作第9章如何用好全局事务123应用程序启动一项事务处理为事务处理分配一个全局事务编号(GTRIDs)启动事务处理的进程与其他进程通信跟踪这些参与事务处理的进程续表阶段TMS动作事务处理访问RM将相应的GTRIDs传递给RM,这样RM就可以监控哪些数据库记录被该事务处理存取应用程序标记一项事务处理将被提交按两步提交协议执行事务应用程序取消事务处理执行回滚操作有错误发生执行回滚操作9.5.2XA模式与NO-XA模式XA就是X/OpenDTP定义的交易中间件与数据库之间的接口规范(即接口函数),交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。XA接口函数由数据库厂商提供。NO-XA应用服务器不需要参与事务管理,只针对单一事务资源,不能跨越多个事务资源。9.5.3Tuxedo与各种数据库的连接Tuxedo可以和所有的有标准XA接口的RM连接,目前几乎所有的关系型数据库和消息队列产品都支持标准的XA接口。Tuxedo和各种数据库相连,都需要配置一个重要的文件RM。RM文件包含所有的资源管理器的入口,它们被Tuxedo应用访问,RM文件在$TUXDIR/udataobj目录下。下面以Oracle数据库为例进行介绍。1.操作系统的准备工作如果Tuxedo连接的数据库不在本地,需要安装oracle客户端。2.Oracle数据库中的准备工作Sysadmin登录数据库,执行如下脚本。示例9-1:SQL@$ORACLE_HOME\rdbms\admin\xaview.sql赋权限给public用户。示例9-2:SQLgrantselectonv$xatrans$topublicwithgrantoption;叱咤风云:Tuxedo企业级运维实战124SQLgrantselectonv$pending_xatrans$topublicwithgrantoption;SQLGRANTSELECTONDBA_PENDING_TRANSACTIONSTOScott;3..profile文件的设置,需要设置ORACLE_HOME并修改PATH示例9-3:ORACLE_HOME=/u01/app/oracle/product/10.2.1/clientexportORACLE_HOMEPATH=$PATH:$ORACLE_HOME/binexportPATH4.修改RM文件如果使用的不是COBOL(CommonbusinessOrientedLanguage)开发的程序,Oracle_XA的值不需要改变,否则需要作如下修改。示例9-4:Oracle_XA:xaosw:-L${ORACLE_HOME}/lib–L${ORACLE_HOME}/precomp/lib/cobsqlintf.o–lclntsh5.创建tms文件在TUXAPP目录下创建文件TMS_ORA10G,Tuxedo通过TMS_ORA10g与ORACLE数据库采用XA协议进行通信。示例9-5:buildtms-o$TUXAPP/TMS_ORA10g-rOracle_XA6.修改UBBCONFIG文件在*GROUPS中添加如下内容。示例9-6:OPENINFO=ORACLE_XA:Oracle_XA+Acc=P/scott/scott+sqlNet=ORCL+SesTm=100+LogDir=.+MaxCur=5TMSNAME=TMS_ORA10gTMSCOUNT=29.6全局事务的使用规则全局事务的使用遵守两阶段提交协议,另外在事务控制问题上还有以下几个方面需要注意。第9章如何用好全局事务1259.6.1谁发起谁结束全局事务的发起和结束可以是中间件应用的前台,也可以是后台。在事务的控制上应遵循谁发起事务,谁就结束的原则。在Tuxedo中,事务既可以在前台程序中发起,也可以在后台程序中发起。无论放在前台还是放在后台都有其优缺点。事务放在前台增加了网络传输的流量,但是可以保证异常情况下前后台操作的一致性,事务放在后台可以减少网络流量,但是对于异常情况下前后台操作的一致性很难保证。通常采用的是事务放在前台程序中。但是无论放在前台还是后台,都要遵循“谁发起,谁结束”的原则。9.6.2不允许嵌套Tuxedo不支持嵌套事务处理,即发起者在调用tpbegin()和tpabort()或tpcommit()之间不能再调用tpbegin()开始一个新的事务处理,也不能再开始一个本地事务。9.6.3处理好超时Tuxedo应用系统的事务超时控制很重要,不设置超时时间对系统来说可能会引发灾难。影响Tuxedo全局事务的超时主要有以下3种。一个是在代码中的tpbegin()超时(值为其参数)时间T1,它控制整个事务的完成时间。第二个为数据库XA连接的超时(配置文件中的open_info中的SesTm)时间T2,它控制同一连接中对于分布式事务锁的等待超时时间。还有一个为数据库中等待数据库对象分布式事务锁释放的超时时间(_dirstributed_lock_timeout)T3。这3个超时共同作用并且有如下的关系:T1T2T3。9.7事务挂起的问题在使用全局事务的情况下,可能会遇到事务挂起的情况,即SERVER进程还在,但是无法响应请求。在服务对应的日志文件中总是报“当前的进程已经在一个本地事务中了”的错误,这时只有重启该SERVER,才能排除故障。其实这是一个事务控制的问题,它产生的根本原因是在开启全局事务前,该SERVER执行了一个本地的事务并且没有提交或回滚。在程序代码上表现为如下3种原因。(1)在调用该SERVER的某个带DML语句的SERVICE前没有加tpbegin。(2)在调用tpbegin后没有判断返回值。(3)tpbegin后的tpcall服务调用没有判断返回值,在全局事务超时后没有能够及时地叱咤风云:Tuxedo企业级运维实战126退出后续的调用,导致下一个tpcall产生了一个本地事务。此外,还会有一类比较特殊的问题,即TMS服务挂起的问题,利用tmadmin中的pq命令发现TMS的队列中有