Websphere中JCA连接共享策略

阅读更多
Websphere中JCA连接共享策略

(学习笔记 )

Alex Zhang

一、简介

Java EE应用程序组件可使用可选的部署描述符元素res-sharing-scope来标示资源管理器的连接是否是可共享的。如果部署描述没有标示,容器默认连接是可共享的,也就是Shareable的. 例如,以下是我们H&F平时项目中的一个数据源的引用配置:

<resource-ref id="ResourceRef_1292364576026"><res-ref-name>security</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth><res-sharing-scope>Unshareable</res-sharing-scope></resource-ref>

在H&F项目中,所有的数据源连接都是非共享的,开发环境中要求我们的连接池大小都是1,在我们的开发环境中所有的action之间的跳转都添加了:redirect="true"。 所做的这些配置,都是为了让我们在代码中避免一些死锁的问题。下面我们来详细的学习下原理。

二、名词解释

JCA:  J2EE Connector architecture

LTC: Local transaction containments

共享池: 由LTC管理的连接池,当中的连接只供当前LTC重复使用,其它LTC不能够访问。

自由池: Websphere容器管理的连接池;该处的连接可以被其它线程重复使用。




三、事务的分类

1)全局事务 Global transaction context 

即分布式事务。资源管理器管理和协调的事务,可以跨越多个数据库和进程。资源管理器一般使用 XA 二阶段提交协议与“企业信息系统”(EIS) 或数据库进行交互。 在一个事务中包含多个资源管理器。全局事务可以使用EJB和JTA等创建。全局事务由应用服务器管理。






2)本地事务Local transaction containment

在单个 EIS 或数据库的本地并且限制在单个进程内的事务。本地事务不涉及多个数据来源。 简而言之,就是我们平时用的JDBC控制的事务编码方式。




之所以要介绍事务的分类是因为连接的共享也要根据它们的类型区别对待的,根据JCA的规定,只是有符合如下要求的连接才是shareable的:

"When multiple shareable connections x and y acquired by an application are used within a global transaction scope (for instance, container-managed or bean-managed), the application server must provide a single shared connection behavior under the following conditions:

- x and y are collocated in a single Java Virtual Machine process address space.
- x and y are using a single transactional resource manager.
- x and y have identical properties.
- x and y are marked as shareable.
- x and y are used within a container-managed or bean-managed transaction scope.



The ability to share is unspecified for connections marked shareable that are used outside a global transaction scope. Sharing is not supported for connections obtained from a non-transactional resource adapter, that is, transaction support level is NoTransaction."

以上规范最后一段是说如果事务在LTC模式下,如果定义为shareable的话,那么数据库连接就是可以共享的。但是对于全局事务模式下,必须符合以上所提的条件。更加升入的条件复合解释可以参考:

http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/cdat_conshrnon.html




在Websphere中,默认情况下,如果没有全局事务的时候,那么服务器会新建一个LTC作为默认的transaction context. 在shareable模式下,即使调用了close()方法,连接只会被放在共享池里,而不会释放在自由池中。所以,基于这个原因,shareable的使用会使数据库操作的性能得到提升,但是当单位时间内获取的连接数过多时,会造成高负荷的问题(连接数不够用的情况)。 

、基于Web的LTC




每个servlet维护一个LTC,直到当前servlet生命周期结束才结束。Forward、include后,原来关闭的连接仍然在共享池里,并没有释放到自由池里,在新的servlet中会从新建立一个新的LTC,所以新的servlet中是没法拿到前一个servlet关闭过后的连接。Redirect就没有这个问题,因为在发送一次redirect请求后,当前LTC已经结束,连接已经被释放了。只有当各个servlet结束后才会销毁LTC,所有的连接才会被正在释放。总而言之,切记每个servlet维护一个自身的LTC,具体流程可以看如下:
•LTC A begin ◦Servlet A begin ■get Connection A //shareable
■use Connection A
■close Connection A
■// Connection A remains in shared pool, associated with LTC A
■include or forward Servlet B
■LTC A suspend
■LTC B begin ■Servlet B begin ■get Connection B //shareable
■use Connection B
■close Connection B
■// Connection B remains in shared pool, associated with LTC B

■Servlet B end

■LTC B end //Connection B released to free pool
■LTC A resume
■// possible Connection A re-use (get/use/close)

◦Servlet A end

•LTC A end //Connection A released to free pool

对于Filters而言实际情况和ibm的某作者所说的完全不同,他认为:

Filters总体类似于Servlet,每个filter都会建立自己的LTC,但是只有整个请求结束后,LTC才会释放所有的连接。也就是说只有整个request/response生命周期结束过后,LTC才结束。

但是测试出来的结果是:整个Filters链都是共用的一个LTC。测试代码是这样的,我在两个filters中分别获取Connection,然后close()掉它,结果两个filter都能正常执行下去。按照他的理论,不应该是这样,所以我认为整个filter链是使用的一个LTC。理论依据是:Filter是通过FilterChain调用各个doFilter()方法,是直接调用方法。不经过服务器,那么LTC也就没有创建;而servlet之间的跳转是通过容器来实现(forward过程),LTC的创建可以在实例化servlet时由服务器创建。





五、测试案例

以下案例都是在最大连接数为1的情况下,测试各个filter、servlet或action是否能正常获取到连接,

1) 一个action内部执行两次getConnection();

代码如下:

Connection con1 = DataSourceUtils.getConnection(); //Pick 1st connection

// do something...

con1.close();

Connection con2 = DataSourceUtils.getConnection(); //Pick 2nd connection

// do shit something...

无论是shareable/Unshareable的,这段代码都会成功运行通过。这是因为在同一action中,只有一个LTC存在。



2.Action A forward 到 Action B;

在shareable的情况下,Action B中将无法得到连接。如果是redirect到Action B中,那么连接是可以拿到的,因为连接因为LTC的结束已经放回到了自由池中了。



3.从多个Filter到一个action A,再forward到action B;

在shareable的情况下,在Filter和action A都可以很顺利的拿到connection,但是action B无法拿到连接。如果是redirect到Action B中,那么连接是可以拿到的,因为连接在LTC结束后已经放回到了自由池中了。




六、死锁

根据shareable模式的特性,当系统负载过大时,可能会有死锁的产生。假如同时访问的用户数过多,所有被使用过的连接都放在共享池里,因为每次请求的连接都只有在请求结束后(LTC结束后)才释放到自由池中。 久而久之,自由池里面的连接就会被耗尽,导致系统稳定性丧失。

死锁解决方案
• 尽量在一个线程里少获取连接;
• 使用Unshareable的策略;每次获取的连接都是唯一的,close过后会立即释放到自由池里;
• 使用UserTransactions接口控制连接的释放。因为在有全局事务的情况下,LTC就不会启动,那么连接的get/close就由UserTransactions控制了。
•    尽量避一个LTC包含多个LTCs的情况。
•  Servlet之间最好用redirect的方式跳转,可以有效的避免连接耗尽的情况。


一个连接池死锁的讨论帖子: http://www.iteye.com/topic/809760




七、思考

为什么H&F project不使用shareable的方式?

其实在项目中,有的地方是用的shareable的有的地方是用unshareable的,不过大多数HFLog和Security数据源的连接都是使用的shareable方式。情况不一定。从curt的邮件,我们可以知道他是希望我们使用Unshareable的,

Make sure that all applications running on your server has all database connections set to “Unshareable”.  In web.xml under References select each resourceref DB name and make sure Sharing scope is Unshareable.  This will need to be verified for the application that you are testing, but any application running on your server.



I hope this fixes your problem, if not let me know.



Curtis Pendleton, Computer Information Technology Specialist II





猜测:也许数据连接池中设置的最大连接数有限(如几十个),如果使用的是shareable模式,那么当有多个LTC建立后,而这些LTC又没有及时销毁,连接也没有及时放回自由池,导致数据库连接池里的连接很快被用尽。这个有理,不过我想H&F并不是什么高并发的项目,难道真是因为这个原因,还是别的?




八、参考资料
1. 全局和本地事务:

http://blog.chinaunix.net/space.php?uid=20264899&do=blog&cuid=197029

2) Default behavior of managed connections in WebSphere Application Server:

http://www.ibm.com/developerworks/websphere/library/techarticles/0506_johnsen/0506_johnsen.html
3.不可共享和可共享连接

http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/cdat_conshrnon.html

你可能感兴趣的:(Websphere,Servlet,IBM,配置管理,项目管理)