閱讀目錄

   最近有個(gè)用戶量 5W-10W 的 web 應(yīng)用,頻繁導(dǎo)致 weblogic 崩潰,讓運(yùn)維組很難受。

   通過幾天跟蹤系統(tǒng)日志和 weblogic 運(yùn)行狀況,發(fā)現(xiàn)報(bào)錯(cuò)的姿勢(shì)有很多,其中對(duì)定位問題比較關(guān)鍵的報(bào)錯(cuò):

   ExecuteThread: '496' for queue: 'weblogic.kernel.Default (self-tuning)' has beenbusy for "712" seconds working on the request "XXXX", which is more than the configured time (StuckThreadMaxTime) of "600" seconds.

   weblogic 分配給 web 應(yīng)用使用的線程響應(yīng)返回周期最大為10分鐘,線程遲遲無法返回結(jié)果導(dǎo)致阻塞,并且這樣的刺頭線程越來越多。

   運(yùn)行一段時(shí)間后達(dá)到 weblogic 阻塞線程的閥值,weblogic 自然就崩潰了。

   剛開始也試著調(diào)大 weblogic 響應(yīng)周期/阻塞線程的閥值,但是阻塞線程還是會(huì)存在并且很快達(dá)到閥值。

   仔細(xì)比對(duì)奔潰前后日志,查看 weblogic 阻塞線程詳情,導(dǎo)致阻塞開始罪魁禍?zhǔn)资菙?shù)據(jù)庫(kù)查詢需要很長(zhǎng)時(shí)間。

   該系統(tǒng)與內(nèi)外圍很多廠商系統(tǒng)有進(jìn)行數(shù)據(jù)交互,數(shù)據(jù)庫(kù)里面旁根錯(cuò)雜的 db_link/synonyms/view/procedure。

   而且是老舊項(xiàng)目,代碼經(jīng)過很多人修改,已經(jīng)風(fēng)燭殘年搖搖欲墜,俺想重造它不是一天兩天了,因?yàn)楹芏嘣驘o法進(jìn)行,很無奈。

   規(guī)范數(shù)據(jù)庫(kù)中的交互流程?然后動(dòng)代碼?oh,no! 限定解決的期限將至,不能拖。

   應(yīng)用起初使用的是自帶 C3P0 ConnectionPool,出現(xiàn)崩潰問題后,輾轉(zhuǎn)嘗試很多方法。

   將應(yīng)用的數(shù)據(jù)庫(kù)連接池改動(dòng)為服務(wù)器 weblogic  JNDI ConnectionPool ,使數(shù)據(jù)庫(kù)連接的壓力從應(yīng)用轉(zhuǎn)移到 web 容器。

   崩潰問題得到了緩解,經(jīng)過后續(xù)的 weblogic 連接池參數(shù)的調(diào)整,卡死崩潰問題得到妥善解決。

   實(shí)踐證明 web 容器配置 JNDI 提供給應(yīng)用使用效率遠(yuǎn)遠(yuǎn)大于應(yīng)用自帶的連接池,也使我不得不重新審視這塊對(duì)于 web 項(xiàng)目的重要性。

   同樣 JNDI 避免了程序與數(shù)據(jù)庫(kù)之間的緊耦合,使應(yīng)用更加易于配置、易于部署。  而且這樣幾乎無代碼改動(dòng),只需變動(dòng)下 DataSource 的獲取。

   試想發(fā)布在 weblogic 上面的 10個(gè)自帶連接池的應(yīng)用,當(dāng)數(shù)據(jù)庫(kù)信息變動(dòng)時(shí),你是不是想哭?

回到頂部

1. DataSource / ConnectionPool /  JNDI 三者關(guān)系

   Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

   DataSource:數(shù)據(jù)源是在 JDBC2.0 中引入的一個(gè)概念;

                       在 JDBC 擴(kuò)展包中定義了Java.sql.DataSource 接口,它負(fù)責(zé)建立與數(shù)據(jù)庫(kù)的連接;

                       在應(yīng)用程序訪問數(shù)據(jù)庫(kù)是不必編寫連接數(shù)據(jù)庫(kù)的代碼,可直接從數(shù)據(jù)源獲得數(shù)據(jù)庫(kù)連接。

   ConnectionPool :在數(shù)據(jù)源中初始化建立了多個(gè)數(shù)據(jù)庫(kù)連接,這些數(shù)據(jù)庫(kù)連接保存在連接池(ConnectionPool)中。

                              Java程序訪問數(shù)據(jù)庫(kù)時(shí),只需從連接池中取出空閑狀態(tài)的數(shù)據(jù)庫(kù)連接,當(dāng)訪問結(jié)束時(shí),將數(shù)據(jù)庫(kù)連接返回給連接池。

   JNDI : (Java Naming and Directory Interface)Java命名與目錄接口;

              為開發(fā)人員提供了查找和訪問各種命名和目錄服務(wù)的通用、統(tǒng)一的接口。

              其實(shí)可以將 JNDI 理解為一種對(duì)象和名字綁定的技術(shù),即指定一個(gè)資源名稱,將該名稱與某一資源或服務(wù)相關(guān)聯(lián)。

              結(jié)合圖和上面的簡(jiǎn)述,數(shù)據(jù)層關(guān)鍵性對(duì)象都已展露無遺,同樣也很容易理解。

              JNDI 避免了程序與數(shù)據(jù)庫(kù)之間的緊耦合,使應(yīng)用更加易于配置、易于部署。

回到頂部

2. 配置 JNDI 數(shù)據(jù)源的方式和使用

   weblogic 上配置 JNDI 為圖形界面,操作起來很方便,而且那是運(yùn)維組的事情,術(shù)業(yè)有專攻。

   這里我拿 Tomcat 為例(開發(fā)時(shí)你也不可能在本機(jī)裝個(gè) weblogic 調(diào)試吧),簡(jiǎn)述下配置 JDNI 的幾種方式:

a. 全局使用:Tomcat 的 conf 文件夾下的 context.xml  配置文件中添加:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

<Resource name="jndi/db_test"   
            auth="Container"   
            type="javax.sql.DataSource"   
            driverClassName="com.mysql.jdbc.Driver"   
            url="jdbc:mysql://localhost:3306/db_test"   
            username="root"   
            password="123456"   
            maxActive="20"   
            maxIdle="10"   
            maxWait="10000"/>

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

b.局部使用:Tomcat 的 conf 文件夾下 server.xml 的 <host> 標(biāo)簽內(nèi)添加:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

Context path="/demo_jndi" docBase="/demo_jndi">  
   <Resource  
     name="jndi/db_test"  
     type="javax.sql.DataSource"  
     driverClassName="com.mysql.jdbc.Driver"  
     maxIdle="2"  
     maxWait="5000"  
     username="root"  
     password="123456"  
     url="jdbc:mysql://localhost:3306/db_test"  
     maxActive="4"/>  </Context>

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

 c.局部使用:應(yīng)用 META-INFO 下新建 context.xml 添加:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

<?xml version="1.0" encoding="UTF-8"?>  <Context>  
    <Resource name="jndi/db_test"   
                auth="Container"   
                type="javax.sql.DataSource"   
                driverClassName="com.mysql.jdbc.Driver"   
                url="jdbc:mysql://localhost:3306/db_test"   
                username="root"   
                password="123456"   
                maxActive="20"   
                maxIdle="10"   
                maxWait="10000"/>      </Context>

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

   上述幾種配置使用的數(shù)據(jù)源都為 javax.sql.DataSource,當(dāng)然你也可以引入其他開源的數(shù)據(jù)源。

   也就是 web 容器使用其他的開源數(shù)據(jù)庫(kù)連接池,比如像下面這幾種姿勢(shì)(記得將依賴的 jar 添加到容器的 lib 中):

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

<Resource name="jndi/db_test"   
            auth="Container"
            //DBCP
            type="javax.sql.DataSource"
            factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
        
            //C3P0
            type="com.mchange.v2.c3p0.ComboPooledDataSource"
            factory="org.apache.naming.factory.BeanFactory" 
              
            //Druid
            type="com.alibaba.druid.pool.DruidDataSource" 
            factory="com.alibaba.druid.pool.DruidDataSourceFactory"
            
            driverClassName="com.mysql.jdbc.Driver"   
            url="jdbc:mysql://localhost:3306/db_test"   
            username="root"   
            password="123456"   
            maxActive="20"   
            maxIdle="10"   
            maxWait="10000"/>

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

   配置好之后,使用起來也是相當(dāng)?shù)暮?jiǎn)單,核心如下2行代碼即可:

    Context ctx = new InitialContext();  
    DataSource ds = (DataSource) ctx.lookup("java:comp/env/jndi/db_test");

   如果項(xiàng)目中引入了 Spring 上述兩行代碼都可以省了,注入數(shù)據(jù)源配置,如下:

    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">  
        <property name="jndiName" value = "java:comp/env/jndi/db_test"/>  
    </bean>

  因?yàn)槊熬Y的不用,避免發(fā)布時(shí)忘記修改,統(tǒng)一配置 tomcat 和 weblogic 上的數(shù)據(jù)源 jndi 的方式:

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/db_test" />

 

作者:Orson 
出處:http://www.cnblogs.com/java-class/ 
如果,您認(rèn)為閱讀這篇博客讓您有些收獲,不妨點(diǎn)擊一下右下角的【推薦】 
如果,您希望更容易地發(fā)現(xiàn)我的新博客,不妨點(diǎn)擊一下左下角的【關(guān)注我】 
如果,您對(duì)我的博客內(nèi)容感興趣,請(qǐng)繼續(xù)關(guān)注我的后續(xù)博客,我是【Orson】 

本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段 聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。 

http://www.cnblogs.com/java-class/p/6717844.html