作者简介:
张景超,男,1971年4月出生,1993年大学本科毕业于南华大学给排水工程专业,工程学士,华中科技大学电子与信息工程系研究生在读。工作单位:湖北移动通信有限责任公司计算机信息管理中心。
BOSS系统是中国移动通信公司最重要的业务支撑系统,在BOSS系统中大量的应用构建在基本于交易中间件的三层结构下,在BOSS系统建设及维护的过程中,我们积累了很多关于中间件应用的经验,我们将这些经验总结出来,与大家分享,共同提高中间件应用的水平。
一、中间件技术在系统设计规划方面的经验总结
1.1、中间件应用架构的选择
这种架构选择的焦点就是业务逻辑到底是放在前台应用中还是放在后台中间件应用中。其实,引入中间件平台的原因之一就是业务逻辑的集中管理,出现这种争论的原因主要是开发商对这种业务逻辑集中的理解不深,在应用设计的过程中仍然没有摆脱以前两层结构的影响,再加上因为业务逻辑集中会增加程序开发量,才出现了这种情况。我们认为,把业务逻辑集中在中间件服务器上不仅对于业务逻辑的集中管理有好处,而且对于系统的后期运行维护、软件的升级管理都有着明显的优势。当然,在开发的工作量方面,业务逻辑集中时工作量大很多。
1.2、中间件服务分布的设计和优化原则
在Tuxedo中,Server可以理解成为Unix的一个进程,Service可以理解成为应用进程Server中的一个函数。用户可以任意划分Server和Service:既可以把所有的Service放在一个单一的Server中,也可以采用“一个Service一个Server”的方式。Tuxedo对此没有任何限制。
中间件应用的性能直接影响到营业前台服务的稳定性和连续性,而影响中间件应用性能的因素除了硬件资源的保��、数据库响应时间、中间件应用软件本身的质量之外,中间件应用服务的分布也起着至关重要的作用。我们有着这样的一个例子,在前台进入收费界面的时候,应用程序需要调用一个SERVICE名字叫A,A分布在一个叫SA的server中,而SA中又包含着很多其他的在线统计的SERVICE B,结果造成了SA响应B调用的时候执行时间比较长,所有的SA都在执行SERVICE B ,前台请求SERVICE A得不到响应,收费的界面怎么都进不去,从而导致前台收费业务中断。这就是个典型的因为服务分布不当造成的系统故障。
我们在系统规划设计过程中遵循的一个最基本原则就是尽量将“类似的Service”捆绑在一个Server之内。所谓“类似的Service”是指这些函数有相似的大小、执行时间、复杂度或者功能。我们来考虑一个极端的例子:假设一个Service A是完成非常简单工作的,它的平均执行时间是100毫秒。另一个Service B进行数据库的查询,它的执行时间可能长达20秒。如果将这两个Service捆绑在一起使用,就会出现非常严重的后果。大家知道,操作系统的基本调度单位是进程。在一个进程中的Service执行是串行的。Tuxedo把发往同一个Server的请求交易包放在同一个消息队列中。当Service B在执行的时候,Service A的请求包必须在队列里面等待20秒以上才可能被执行,虽然它的执行时间仅仅100毫秒。这显然是不能容忍和应该避免的。
实际上,用户在设计和开发应用程序的时候,并不能完全估计出每个Service的执行时间和频度。所以对Server和Service的划分优化是在应用程序开发完毕后进行调整的。调整的依据就是在系统运行的时候记录每个Service的执行时间和频度,然后根据这些数据来进行优化调整。下面就是我们在实际当中获得经验的一些系统总结��
1、 区分Service的不同类型:是业务操作还是简单的数据访问
在中间件应用中的Service可以进一步细分成负责完成业务操作和负责数据访问的两种类型。在设计的时候,最好把这两种不同类型的Service区别出来。所谓完成业务操作的类型其实就是进行数据修改的操作,负责数据访问的类型其实就是进行数据查询的操作。但是在实际的系统运行过程中,凡是涉及到数据修改的操作过程中必然会有数据查询的操作,这种类型的操作也应该规整到第1种类型中去。
2、 请求/响应类型的Service要和会话Service分开在不同的Server中
在Tuxedo中,一个Server要么支持请求/响应类型类型的Service,要么支持会话方式的Service。会话方式和请求/响应方式是两种互斥的通讯方式。请求/响应方式效率比较高,是使用最频繁的通讯类型。Tpcall/tpacall/tpforward都是这种类型的函数。会话方式适合大量的数据传输,但是它的代价是效率的下降。所以这两种类型的Service要分开放在不同的Server里面。
3、 执行时间相似的Service放在同一个Server里面
在Tuxedo应用环境中,可能有成百上千的Service,这些Service的执行时间显然是不同的。对于单线程的Server来说,虽然它可能有多个Service,但是这些Service的执行是串行的。如果某个Server拥有两个Service,A和B。A的执行时间是100ms,B的执行时间是1000ms,也就是说执行一次B的时间可以执行十次A。那么当B在执行的时候,可能会有十个A在队列里面等待。这种情况会急剧降低该Server处理Service的吞吐率。因此很自然的一个原则是把执行时间相似的Service放在同一个Server里面。
4、 具有相同执行频度的Service放在同一个Server里面
在一个典型的Tuxedo应用系统中,并不是所有的Service的执行频率都是相同的。可能一些Service被频繁的执行,而另外一些Service只是偶尔才被执行几次。把这些SERVICE分开可以避免偶尔调用的SERVICE堵塞频繁调用的SERVICE。
5、 避免死锁的情况发生
在Tuxedo中的死锁情况有两种,第一种是一个Server中的Service A去调用同在一个Server中的Service B。这种死锁发生的原因是,对于单线程的Server来说,它其中的Service是串行执行的。Service A去调用Service B的时候,Service A还没有执行完,它等待Service B的返回结果。 但是Service B不能执行,因为该Server还处于执行Service A的状态。最终导致Service A超时而出错。
第二种情况是两个Server中的Service互相调用。例如Server1和Server2,Server1中的Service A去调用Server2中的Service X。同时Server2中的Service Y去调用Server1中的Service B。这种情况发生的死锁和第一种情况非常类似,都是因为进程只能串行实行Service导致的。
这两种死锁情况在应用设计时特别要注意避免。第一种情况是比较容易察觉的,但是第二种情况就不大容易察觉。
1.3、中间件系统应用平台FAILOVER方式的选择
在真实的生产运行环境中,运行平台的failover是一个必须考虑的问题。Tuxedo平台上的实现failover机制基本上有两种,一种是利用tuxedo自己的failover机制配合前台配两个WSNADDR地址来实现failover。一种是利用双机软件来实现。
第一种方式是指使两台的中间件服务器处于MP工作模式下,在每一台都启动WSL进程,然后在中间件前台配置两个ip地址。通过自己实验发现利用tuxedo自己的failover机制只有如下好处即不需要额外的操作系统和软件的支持,但是其缺点确很多,主要缺点如下:
1、两台中间件平台的MASTER切换必须要手��完成,无法自动完成。
2、前台配置的两个WSNADDR地址,如果第一个地址失败,要重新连接到第二个地址需要很长的时间,并且在每次服务调用时都要等待同样的时间。
通过双机软件来实现FAILOVER是指两台中间件服务器都配置在SHP模式下,然后利用双机软件的ip切换功能来实现failover。这种方法需要在各自的配置文件中加入另外一台主机的WSL的信息,在另外一台主机故障时,通过双机软件进行IP切换,再通过双机切换脚本将这台主机的备用WSL启动即可。采用这种方式有以下优点
1、机器切换自动完成,不需要人工干预。
2、前台业务不受影响,能保证业务开展的连续性。
缺点主要有
1、在正常情况下,每一台主机的启动中间件时,备用的WSL服务会启动失败,不过这不影响正常使用,备用的WSL只在另外一台主机故障后才起作用。
2、需要额外的双机配置和脚本配置工作。
经过这些比较,我们选定了采用双机软件的方案实现了中间件的failover机制。在以后的运行维护过程中起到了好的效果。
1.4、中间件与数据库的连接方式的选择
在TUXEDO中间件应用中连接数据库的方式有两种,一种为通过XA方式连接数据库,另外一种是在应用程序中自己连接数据库。
通过XA方式连接数据库是指利用关系型数据库的XA接口,在tuxedo的配置文件中的OPENINFO段中加入连接信息,然后在server程序的初始化代码的中调用中tp_open(或xa_open),当SERVER启动时进行数据库连接。
通过应用程序直接连接数据库,数据库的连接操作不一定是在SERVER启动时进行的。
这两种方式的连接在BOSS系统中都会用到,其中的区别主要就在于如果业务操作的事务为分布式事务时,则必须要用XA方式。详细比较如下:
1、���过XA连接的方式可以实现分布式事务,即能够保证事务在不同数据库中的一致性。但是正是因为如此,它对中间件系统和数据库系统都有额外的开销,有时候这种开销甚至会影响系统的性能。
2、通过应用程序直连数据库的方法不能够实现分布式事务,但是同时也因此减少了对系统的压力。
综上,选择数据库的连接方式对整个系统的性能影响也是至关重要的,我们有个原则,凡是在不涉及到分布式事务的地方就不用XA连接。过多的依赖了XA接口,会给系统带来了许多额外的负担和压力,也会造成许多额外的故障。
二、中间件技术在系统维护方面的经验总结
在中间件的日常维护中,我们了解了一些TUXEDO的基本知识,摸索了一套行之有效的故障排除方法,积累了一些常见故障的排除经验,现在与大家介绍如下:
2.1、LICENSE数的问题
tuxedo的license由文本文件lic.txt来控制,位于udataobj目录下,分为SDK/RTK两种,两种LICENSE不能合并使用。它控制的是并发用户数并且有10%的冗余,这里的并发用户数是指在某一时刻前台程序已经发起tpinit还没有作tpterm的连接数,所以在tuxedo中间件的使用中存在着长连接和短连接的问题。长连接是指tpinit后就开始一系列的服务调用,只在系统重启或系统非常空闲的时候才做tpterm,而短连接是指每次服务调用前作tpinit,调用结束后立即作tpterm调用。因为短连接下的服务调用需要额外的连接时间消耗,这对系统响应时间会有影响,而长连接又会占用系统的并发用户数。所以在系统设计时需要针对不同的应用情况做出不同的设计,比如针对接口类型的应用因为服务调用比较频繁,进行连接的时间就会占比较大的比重,这时就需要使用长连接,而对于前台应用类型的应用,连接过程的时间对于业务操作的时间来说是可以忽略的,这时就要用短连接来节约license资源。
2.2、客户端连接的问题
当客户端无法连接中间件时,我们需要确认的是
1、 客户端的WSNADDR是否设置或是否设置正确。
2、 系统配置文件中的MAXWSCLIENTS和MAXACCESS是否正确设置。
3、 WSL是否启动,WSH的个数是否足够。
4、 是否有防火墙,如果有防火墙存在,则需要在WSL的配置中作相应的地址映射和端口指定。
5、 操作系统是否有足够的SCOKET资源使用。
解决了这些问题后,一般就可以解决客户端连接不上的问题了。
在TUXEDO中,参数TMTRACE对故障的定位和排除很有作用,它是一个环境境变量。我们一般在系统监控的工作终端上将此参数设置为on,在前台报系统故障的时候,我们直接进入故障模块将故障重现,然后在终端机器的c:/或者tuxedo的安装目录下打开一个ULOG文件,在此文件中会发现tpcall服务的失败信息,根据这个信息查找对应的SERVER和SERVICE的对应表,很快就可以找到问题服务。采用这种方式,维护人员不需要了解程序的具体流程就可以定位错误解决故障。
在TUXEDO的服务端,有几类文件需要关注,这些文件包括ULOG文件、XA接口的trc文件、数据库连接故障的sqlnet.log、标准输出文件stdout(也可以被应用程序自己定义)。在这些文件中包含着丰富的系统运行错误告警信息。ULOG记载关于中间件的启停记录和系统本身的一些配置运行告警信息。XA的trc文件记录的是XA接口方面的一些的错误信息,关于分布式事务的一些错误在这个文件中都有记录。sqlnet.log记录了应用程序和数据库连接故障的信息,只要有当前日期时间的这个文件存在,应用和数据库的连接就会存在问题。标准输出文件stdout记录了应用程序本身的运行信息。这些文件的跟踪检查对于及时主动的发现故障有着重要的意义。
2.3、事务控制的问题
1、事务边界的问题:在这里我们要遵循谁发起发起事务,谁就结束的原则,这里的谁主要是指中间件的前台和后台。我们知道在TUXEDO中事务的发起既可以在前台程序中发起,也可以在后台程序中发起。无论放在前台还是放在后台都有其优缺点。事务放在前台增加了网络传输的流量,当时可以保证异常情况下前后台操作的一致性,事务放在后台可以减少网络流量,但是对于异常情况下前后台操作的一致性很难保证。我们采用的是事务放在前台程序中。但是无论放在前台还是后台,都要遵循谁发起,谁结束的原则。
2、XA接口使用的注意事项:首先是XA资源文件的配置,在oracle数据库中一般用到的是libclntsh.a,我们可以先Make sample,提取其中用到的连接库加入到RM文件中即可。其次在oracle8i之前要对XA进行授权,要在oracle的DBA用户下执行grant select on dba_pending_transactions to public。
3、事务挂起的问题:在使用XA的情况下,我们经常会遇到这种情况,SERVER进程还在,可就是不做事。在相关的日志文件中总是报“当前的进程已经在一个本地事务中了”的错误,这时只有重启该SERVER,才能排除故障。其实这是一个事务控制的问题,它产生的根本原因是在开启全局事务前,该SERVER执行了一个本地的事务并且没有提交或回滚。在程序代码上表现为如下三种原因:
(1)、在调用该SERVER的某个带DML语句的service前没有加tpbegin。
(2)、在调用tpbegin后没有判断返回值。
(3)、tpbegin后的tpcall服务调用没有判断返回值,在全局事务超时后没有能够及时的退出后续的调用,导致下一个tpcall产生了一个本地事务。
此外,还会有一类比较特殊的问题,那就是TMS服务挂起的问题,利用tmadmin中的pq命令发现TMS的队列中有很多请求存在,在这种情况下,一般只能等待其执行完成,情况严重时,则需要调整相应的数据库参数,在ORACLE中该参数应该设为max_commit_propagation_delay>=90000。
在实际的运行维护中,我们发现即使把数据库参数调整了,有时还会有TMS挂起的故障发生。针对这件事情我们专门作了研究,TMS之所以挂起是因为TMS在等待数据库中DX独占锁的释放,这种独占锁加锁的对象一般都是ORACLE的系统对象,而这种独占锁的产生一般是在全局事务中执行着DML语句,当这种DML语句执行比较慢时,就会引起TMS的锁等待现象。此外,我们还发现,一般的查询语句是不会产生锁的(OPS的lm_lock锁除外),但是如果将查询放入一个全局事务中时,它就会产生一个共享的DX锁,如果这个在全局事务中的查询的调用是通过ORACLE的工具包DBMS_SQL来进行的话,那就会产生一个DX的排他锁。基于这些结果,我们建议在程序的开发过程中要遵循能不用XA全局事务的情况下就不用,能将查询放到事务之外的就不要放到事务之内,能不用ORACLE工具包进行开发的就不要用。我们也按照这个原则要求我们的开发商,取得了比较好的效果。
4、事务超时设置的问题
中间件应用系统的事务超时控制很重要,不设置超时时间对系统来说简直就是一种灾难。我们曾经就有过因为超时时间的设置没设和设置不当造成了严重的系统故障,最直接的故障就是系统报全局事务数不够的错误,无法开启新的事务,从而导致前台业务的终止。TUXEDO的超时主要有三种,一个是在代码中的tpbegin超时(值为其参数)T1,他控制整个事务的完成时间���第二个为XA连接的超时(配置文件中的open_info中的SesTm )T2,他控制同一连接中对于分布式事务锁的等待超时时间,还有一个为数据库中等待数据库对象非分布式事务锁释放的超时时间(_dirstributed_lock_timeout)T3。这三个超时共同作用并且有如下的关系 T1<T2<T3。
2.4、服务不能正常启动的问题
在实际的维护工作中,经常会出现服务不能正常启动的现象。明明所有的服务都已经关闭了,tmboot就是起不来。这种原因一般是因为系统的IPC资源没有释放。IPC资源是操作系统用来进行进程间通讯的系统资源,主要包括信号灯、共享内存、消息队列。在UNIX操作系统下通过IPCS命令可以清楚的看到IPC资源的使用情况。当服务无法启动的时观察IPCS就会发现tuxedo运行环境的用户下的ipc资源没有被释放,这时使用ipcrm命令清除相应的IPC资源,再启动服务就可以了。
三、结束语
以上是我们在BOSS系统的建设和维护工作当中的关于中间件一些认识和经验。这些经验和认识也是在长期工作过程中通过集体学习、研究、实践而总结出来的,有些认识还带着浓厚的感性成分在里面,所以也希望在这里共享出来同各位同行进行讨论和研究,以达到共同提高的目的。