python - DBUtils 連接池減少oracle數據庫的連接數


問題:

接到需求,告知項目的oracle連接次數過多,對系統造成太過大的負擔,要求減少oracle數據庫的連接次數

分析:

仔細分析代碼以后,發現產生問題的原因,在於之前要求提升oracle監控的監控速度時,將oracle監控的腳本代碼,拆分成了多個子進程。導致每次循環服務器都會產生子進程次數的數據庫連接,產生了過多的不必要連接

解決方案:

討論分析過后,決定更改代碼的架構,用DBUtils的連接池功能+多線程(http://www.cnblogs.com/fnng/p/3670789.html)的組合,替代現有的 多進程+子進程對數據庫的單次連接

DBUtils:

DBUtils 是一套允許線程化 Python 程序可以安全和有效的訪問數據庫的模塊。

下載並安裝:

$ wget https://pypi.python.org/packages/65/65/89afee016aca7fbb5c1642e6ef3864d80af808dc5efa7367b328093eece9/DBUtils-1.1.tar.gz

tar -zxf DBUtils-1.1.tar.gz

cd DBUtils-1.1
python setup.py install

使用:

  參考:http://blog.163.com/power_mr/blog/static/138744007201391823253744/

  導入:import DBUtils.PersistentDB

  • dbapi :數據庫接口
  • mincached :啟動時開啟的空連接數量
  • maxcached :連接池最大可用連接數量
  • maxshared :連接池最大可共享連接數量
  • maxconnections :最大允許連接數量
  • blocking :達到最大數量時是否阻塞
  • maxusage :單個連接最大復用次數
#不用連接池的MySQL連接方法
import MySQLdb
conn= MySQLdb.connect(host='localhost',user='root',passwd='pwd',db='myDB',port=3306)  
cur=conn.cursor()
SQL="select * from table1"
r=cur.execute(SQL)
r=cur.fetchall()
cur.close()
conn.close()
#用連接池后的連接方法
import MySQLdb
from DBUtils.PooledDB import PooledDB
pool = PooledDB(MySQLdb,5,host='localhost',user='root',passwd='pwd',db='myDB',port=3306) #5為連接池里的最少連接數

conn = pool.connection()  #以后每次需要數據庫連接就是用connection()函數獲取連接就好了
cur=conn.cursor()
SQL="select * from table1"
r=cur.execute(SQL)
r=cur.fetchall()
cur.close()
conn.close()

 

 

自用:

生成mysql池

    # get mysql PooledDB
    logger.info("get MySQL connect.")
    host = get_config('monitor_server','host')
    port = get_config('monitor_server','port')
    user = get_config('monitor_server','user')
    passwd = get_config('monitor_server','passwd')
    dbname = get_config('monitor_server','dbname')
    try:
        # mincached 最少的空閑連接數,如果空閑連接數小於這個數,pool會創建一個新的連接
        mysql_pool = PooledDB(MySQLdb,mincached=20,blocking=True,host=host,user=user,passwd=passwd,port=int(port),db=dbname,connect_timeout=5,charset='utf8')
        glob.set_value('mysql_conn',mysql_pool)
    except Exception,e:
        print "start mysql(pooledDB) error:" + str(e)

生成oracle池:

    #get oracle servers list
    logger.info("get Oracle connect.")
    servers=func.mysql_query("select id,host,port,dsn,username,password,tags from db_servers_oracle where is_delete=0 and monitor=1;")
    if servers:
        for row in servers:
            server_id=row[0]
            host=row[1]
            port=row[2]
            dsn=row[3]
            username=row[4]
            password=row[5]
            tags=row[6]

            ora_dsn = host + ":" + port + "/" + dsn
            try:
                oracle_pool = PooledDB(cx_Oracle,mincached=20,blocking=True,user=username,password=password,dsn=ora_dsn)
                conn_name = "server_"+str(server_id)+"_pool"
                glob.set_value(conn_name,oracle_pool)
            except Exception, e:
                logger_msg="check oracle server connect %s : %s" %(ora_dsn,str(e).strip('\n'))
                logger.warning(logger_msg)

 

問題:

改動過程中,碰到了比較難以解決的“疑難雜症”:腳本在執行過程中,會出現異常導致無限執行的死循環中斷現象,同時出現中斷時,不產生異常報錯,導致bug的解決比較困難

為了找出異常的部分,對代碼進行了更詳細的測試:

  1. 搭建代碼框架,進行框架測試
  2. 向框架中填充基本內容,進行基本內容測試
  3. 對代碼的各個部分,進行實驗性測試:
連接池 + 單index線程循環 + 服務器循環外join + 執行oracle操作 -> 異常退出

單連接 + 單index線程循環 + 服務器循環外join + 執行oracle操作 -> 異常退出

單連接 + 單index線程循環 + 服務器循環外join + 不執行oracle操作 -> 正常

連接池 + 單index線程循環 + 服務器循環外join + 不執行oracle操作 -> 正常

連接池 + 單index線程循環 + 服務器循環外join + 執行單條oracle操作 -> 異常

確認了問題產生於oracle數據庫

確認了問題所在后,經過多次試驗,發現在使用多線程連接數據庫的過程中,打印出了兩次異常:

  KPEDBG_HDL_POP_FCPTRKPEDBG_HDL_POP_FCPTRKPEDBG_HDL_POP_FCPTRORA-24550: signal received: [si_signo=11] [si_errno=0] [si_code=1] [si_int=16] [si_ptr=0x10] [si_addr=(nil)]

百度后修改oracle客戶端的配置文件(sqlnet.ora)

#路徑:/usr/lib/oracle/12.2/client64/network/admin/sqlnet.ora
DIAG_ADR_ENABLED=OFF
DIAG_SIGHANDLER_ENABLED=FALSE
DIAG_DDE_ENABLED=FALSE

同時,改動oracle數據庫的使用方式:

      從之前獲取連接以后,使用連接作為oralce監控方法的傳輸參數,

      改為,傳遞oracle連接池的池連接(oralce_pool)作為參數,在方法內,生成新的oracle連接

1.     搭建代碼框架,進行框架測試


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM