鏈接池(深刻 J2EE 的鏈接合用)

Java 2 Enterprise Edition (J2EE) 規範提供了實現高度可伸縮、可靠和可用的電子商務應用的分佈式基於服務的體系結構。一般,J2EE 應用體系結構與模型-視圖-控制器 (MVC) 框架相對應 -- 資源庫/外部系統資源支持域模型(模型),JSP/Servlet 管理顯示(視圖),而 EJB 處理商業邏輯(控制器)。 html

經過服務器端全部三層中的組件實現一個典型的電子商務應用用例。考慮到用戶交互數量的龐大(對於面對客戶的應用,有上百萬個),須要優化地共享有限的服務器端資源。這類資源可能包括數據庫、消息隊列、目錄、企業系統 (SAP、CICS) 等等,它們中的每個均可以由使用表明資源訪問點的鏈接對象的應用來訪問。管理對那些共享資源的訪問對於知足 J2EE 應用的高性能需求來講相當重要。 java

鏈接合用是由數據庫供應商倡導的技術,其目的是容許客戶機共享一組高速緩存的鏈接對象,這些對象提供對數據庫資源的訪問。在本文中,我分析了 J2EE 環境中服務器端資源(例如數據庫、消息隊列、目錄和企業系統)的鏈接合用。 sql

爲什麼合用資源鏈接?

考慮一下 代碼示例 ,其中,EJB 使用 JDBC 1.0、 不使用鏈接合用來訪問數據庫資源。 數據庫

很明顯,該示例的主要問題是鏈接的打開和關閉。考慮到實體 bean 是共享組件,所以,對每一個客戶機請求,都要進行幾回獲取和釋放數據庫鏈接的操做。 編程

從圖 1 能夠看出,使用 JDBC 1.0 經過數據庫管理器獲取和釋放數據庫鏈接將影響 EJB 層的性能。這種影響是由數據庫資源管理器進程建立和摧毀那些對象而引發的。應用服務器通常須要花 1 到 3 秒的時間來創建數據庫鏈接(包括與服務器通訊、認證等等),並須要對每個客戶機 (EJB) 的請求進行鏈接。 後端

圖 1. 使用 JDBC 1.0 的鏈接管理
使用 JDBC 1.0 的鏈接管理

回頁首 緩存

使用服務供應商設施的鏈接合用

如今看一下在 J2EE 環境中,數據庫和非數據庫資源類型當前可使用哪些鏈接合用設施。 安全

JDBC 2.0 標準擴展 API
JDBC 2.0 標準擴展 API 指定數據庫服務供應商能夠實現具備如下特性的合用技術:容許請求客戶機透明地共享資源池的多個鏈接對象。在那種狀況下,由於池管理器預先在啓動時建立鏈接對象,因此,J2EE 組件可使用鏈接對象,而不會致使數據庫資源管理器上的系統開銷。應用服務器供應商在其內存空間實現池管理器,並根據須要動態改變池的大小,從而優化資源的使用。圖 2 中顯示了這種狀況。 服務器

圖 2. 使用 JDBC 2.0 標準擴展的鏈接合用
使用 JDBC 2.0 標準擴展的鏈接合用

經過使用DataSource接口 (JDBC 2.0) 或DriverManager(JDBC 1.0) 接口,J2EE 組件能夠得到物理數據庫鏈接對象。要得到邏輯(合用的)鏈接,J2EE 組件必須使用如下這些 JDBC 2.0 合用管理器接口: oracle

  • javax.sql.ConnectionPoolDataSource接口,該接口充當合用的java.sql.Connection對象的資源管理器鏈接 factory。每家數據庫服務器供應商都提供該接口的實現(例如,Oracle 實現oracle.jdbc.pool.OracleConnectionPoolDataSource類)。
  • javax.sql.PooledConnection接口,該接口封裝到數據庫的物理鏈接。一樣,數據庫供應商提供其實現。

對於那些接口和 XA 鏈接的每個,都存在一個 XA(X/Open 規範)等價定義。

如下代碼示例顯示了 EJB 應用如何利用合用的鏈接對象來訪問數據庫資源(基於 JDBC 2.0)。本例中的 EJB 組件使用 JNDI 查詢來肯定數據庫鏈接池資源的位置。JNDI 1.2 標準擴展 API 容許 Java 應用以相同的方式訪問位於徹底不一樣的目錄和命名系統中的對象。使用 JNDI API,應用能夠查詢目錄來肯定任何資源(例如,數據庫服務器、LDAP 服務器、打印服務器、消息服務器、文件服務器等等)的位置。有關 JNDI 的合適概述,請參閱 "The Java Naming and Directory Interface (JNDI): A More Open and Flexible Model"

請注意: 實際代碼可能會根據數據庫供應商實現類的不一樣而不一樣。

以上代碼(使用 JDBC 2.0)和使用 JDBC 1.0 的主要不一樣在於:getConnection()從池中獲取已打開的鏈接,而close()只將鏈接對象釋放回池。現在,幾乎每一家數據庫服務器供應商(如 Oracle、DB二、Sybase 和 Informix)都提供 JDBC 2.0 驅動程序。現在大多數應用服務器供應商(IBM、BEA、iPlanet、IONA 等)也都支持 JDBC 2.0。

應該說明的一點是:現在,幾乎全部應用服務器都採用兩層鏈接合用體系結構,其中,池位於應用服務器內存空間(與獨立的鏈接代理不一樣)。

JMS 1.02 標準擴展 API
J2EE 應用組件可使用消息傳遞資源與其它企業應用異步通訊。JMS 1.02 標準擴展 API 提供獨立於供應商的方式來與消息傳遞服務供應商通訊。與數據庫資源同樣,經過使用能夠合用的鏈接對象來訪問消息隊列。

JMS 1.02 API 包括下列接口以支持資源合用:

  • 用於 factory 對象的javax.jms.QueueConnectionFactory或javax.jms.TopicConnectionFactory
  • 用於鏈接對象的javax.jms.QueueConnection或javax.jms.TopicConnection

JMS 服務供應商實現那些接口。 代碼樣本 顯示了 EJB 組件如何使用鏈接對象來訪問消息隊列資源。

在鏈接合用時,JMS factory 類一般要有代理(由管理員配置),以便open()和close()請求實際上發往管理鏈接池的代理。遵循 JMS API 的指示,JMS 服務器供應商能夠實現數據庫來管理消息隊列。在那種狀況下,適當的 JDBC 驅動程序將提供鏈接合用。若是應用已經使用 JDBC 2.0 鏈接池啓用的數據庫,那麼,您所要作的只是爲 JMS 配置 JNDI 特性,以使用那個 JDBC 實例。

JNDI API for LDAP
javax.naming.LDAP包包括特定於 LDAP 的類(而不包括在通用javax.naming.directory中)。與 JDBC 2.0 和 JMS 1.02 API 不一樣,JNDI LDAP API 不爲鏈接合用指定任何接口。目錄服務供應商能夠有選擇地經過 SDK 提供支持。例如,iPlanet 的 Netscape Directory Server SDK 4.0 for Java 包括如下構建 LDAP 客戶機所用的類:

public class netscape.ldap.util.ConnectionPool extends java.lang.Object
methods: Connection(), getConnection(), close(), etc.

有關詳細信息,請參閱 "Netscape Directory Server Application Programmer's Guide"

回頁首

J2EE Connector Architecture 1.0

在以上全部示例中,EJB 組件必須導入特定於供應商的實現類,以使用資源的鏈接合用設施。很明顯,這種作法下降了 EJB 的可移植性,並不利於 J2EE 的發展。

理想的作法是內置一個可用於任何資源類型和全部鏈接管理功能(包括合用)的通用鏈接接口。這就是即將出現的 J2EE Connector Architecture 1.0 規範的目標之一,在我寫這篇文章之時,就已經公開了一份草案副本。(請參閱 參考資料)。

圖 3 顯示了體系結構內部的主要概念, 資源適配器 。應用服務器所支持的每一種資源類型的可插入組件,資源適配器,都在應用服務器地址空間中執行。訪問那些適配器的客戶機 API 能夠是 Common Client Interface (CCI) 或(爲了向後兼容)特定於資源的 API(例如 JDBC 2.0)。例如,CCI 定義javax.resource.cci.ConnectionFactory和javax.resource.cci.Connection,分別做爲鏈接 factory 和鏈接的接口 -- 與上一節中提到的 JDBC 2.0 接口相似。

圖 3. J2EE Connector Architecture 1.0 中的資源適配器
J2EE Connector Architecture 1.0 中的資源適配器

Connector 1.0 中的鏈接合用
Connector 1.0 的編程模型以下:

  • EJB 執行鏈接 factory 的 JNDI 查詢,而後發出getConnection()請求。
  • 鏈接 factory 將請求委託給ConnectionManager。
  • 鏈接管理器在應用服務器中查詢鏈接池的實例。若是沒有可用的鏈接池,則管理器使用ManagedConnectionFactory來建立一個物理(不合用的)鏈接。

    在那種狀況下,假定資源適配器供應商實現接口。然而,鏈接器體系結構並不指定應用服務器如何實現鏈接池,而是提供一些指示,例如,根據適配器類型、服務質量 (QoS) 需求等來劃分鏈接池。有關詳細信息,請參閱 J2EE Connector Architecture 規範

例如,基於即將出現的 EJB 2.0 鏈接器體系結構的、至企業/舊有系統的 Sun 鏈接器的產品版 iPlanet Unified Integration Framework Toolkit v 6.0,爲 EJB 層可能要訪問的每一個後端系統定義了鏈接池。一個按期執行的線程監控池對象的使用和壽命。有關詳細信息,請參閱 iPlanet Unified Integration Framewor

回頁首

EJB 層的設計考慮事項

儘管有了管理鏈接池的資源管理器,可是還不能保證 EJB 層具備最優性能 -- 還有一些設計考慮事項!

首先,考慮如下 EJB 客戶機代碼示例,該客戶機訪問實現鏈接池的 LDAP 目錄 。

import netscape.ldap.util.*; 
...
public class NewCustomerBean implements SessionBean {
...
private SessionContext context;  // Bean Context
private LDAPConnection lc; // LDAP Connection object
...
public void setSessionContext(SessionContext sc) {
this.context = sc;
// initialize JNDI lookup parameters
Context ctx = new InitialContext(parms);
...
ConnectionPool cp = (ConnectionPool)ctx.lookup(cpsource);
// Establish LDAP Connection.
try {
this.lc = cp.getConnection();
...
}

以上作法有什麼不妥嗎?首先,有狀態會話對象 (NewCustomerBean) 在setEntityContext中打開鏈接對象,而後持續佔用它,直到使用完爲止 -- 若是用戶(會話)數量迅速增長,就成爲代價至關大的實現。第二,也是更重要的,由於鏈接對象不是序列化的,因此,按照 EJB 1.2 規範,容器能夠在鈍化時(例如,將會話 bean 從其活動狀態移至 bean 實例池)廢棄 bean 實例。

一種替代方法是分別在會話 bean 的ejbActivate()和ejbPassivate()方法中獲取和釋放資源鏈接。若是沒有鏈接池,代價固然會很高,也不會建議那樣作。然而,有了合用以後,使用該技術,能夠用最小的 EJB 層開銷來獲取和釋放鏈接。這裏的要點在於:除了規範和實現所提供的設施以外,設計選擇老是關鍵性能決定因素。

第二個考慮事項是有關認證問題的。您可能已經注意到,合用的鏈接意味着共享的鏈接,而共享的鏈接意味着鏈接不與特定的認證證書綁定。例如,在 JDBC 2.0 鏈接中,應用服務器池管理器在啓動時,使用一個存儲在配置文件中的認證證書(一般是用戶標識/口令)來從數據庫管理器請求預設數量的鏈接。有時候,那可能 不知足應用的安全性策略。LDAP 鏈接須要將 LDAP 子樹與特定證書綁定,於是也有一樣的問題。在那些狀況下,一種替代方法多是使用利用特定證書創建好的已高速緩存的鏈接,它能夠對相同類型的證書重複使 用。這種方法的不利之處是已高速緩存的鏈接要保留很長時間。另外一種替代方法多是對資源使用通用鏈接,並實現某種應用層安全性。

回頁首

結束語

在本文中,我根據資源的共享特性和訪問資源的 EJB 組件,顯示了 J2EE 環境中鏈接合用資源的必要。您已看到由 JDBC 2.0、JMS 1.02 和 JNDI 1.2 標準擴展 API 定義的設施,和供應商對那些 API 接口實現的支持。雖然特定於供應商的解決方案很健壯,可是對它們的使用倒是以 EJB 的可移植性做爲代價的。即將出現的 J2EE Connector Architecture 1.0 解決了該問題,並使資源可插入,從而使 EJB 層從處理特定於供應商的庫中解脫出來。最後,我解釋了爲何您的設計在利用那些合用技術來製做高性能的 J2EE 應用方面扮演着重要角色。

相關文章
相關標籤/搜索