tornado+sqlalchemy+celery,數據庫連接消耗在哪里


  隨着公司業務的發展,網站的日活數也逐漸增多,以前只需要考慮將所需要的功能實現就行了,當日活越來越大的時候,就需要考慮對服務器的資源使用消耗情況有一個清楚的認知。
     最近老是發現數據庫的連接數如果幾天不重啟服務器,就經常會發現有很多sleep很久的數據庫連接,對數據庫服務器的性能有較大的影響。所以需要知道我們的數據庫連接到底是在哪里被創建的,什么時候會被復用,什么時候會被釋放。
     測試的時候使用的代碼,適當進行調整,可幫助梳理清楚場景。

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import (sessionmaker)
from sqlalchemy import create_engine
import time

## []括起來的參數,這邊就是做一個占位符
engine = create_engine("mysql+{driver}://{username}:{password}@{server}/{database}?charset={charset}"\
    .format(
        driver   = [MYSQL_DRIVER],
        username = [MYSQL_USERNAME],
        password = [MYSQL_PASSWORD],
        server   = [MYSQL_MASTER_SERVER],
        database = [DB_NAME],
        charset  = [DB_CHARSET]
    ),
    pool_size    = 20,
    max_overflow = 100,
    pool_recycle = 7200,
    echo         = False  # 調試模式,開啟后可輸出所有查詢語句
)
DBSession = sessionmaker(bind=engine)
session=DBSession()
engine.execute("select 1;")
time.sleep(10)
session.execute("select 1;")
engine.execute("select 1;")
# session.close()
time.sleep(10)
session1=DBSession()
session1.execute("select 1;")
# session1.execute("select 1;")
engine.execute("select 1;")

    就是在上面的這一部分代碼的測試,可以對以下的問題給出一些個人理解:
1.什么時候創建新的數據庫連接的?
   A.engine.excute
   B.session.excute
   C.session.query
2.什么時候關掉sqlachemy里面的連接(其實是將可用的數據庫連接丟回到sqlachemy的連接池里面去):
   A.engine的excute執行完成時
   B.session.close()/session.commit()/session.rollback()
   C.engine定義里面設置的pool_recycle時間到期,如果某一個session長期占有,沒有close,在這個到期了之后就會被回收回去;
3.什么時候關掉數據庫連接:
   A.python3進程關掉,比如kill或者重啟服務器的時候;
   B.數據庫連接的sleep時間超過wait_timeout的時候;比如在一個http請求里面,先用了一次session.query,然后休眠了10秒鍾,這個時候我們的數據庫的wait_timeout如果設置為5秒,在query執行完成之后,數據庫就會顯示連接進入sleep狀態,超過5秒就會被關掉。這個時候,如果我們如果需要繼續用這個session來進行查詢的話,就會提示“MySQL connection not available”

    所以,為了不產生比較多的數據庫連接,導致無謂的資源消耗,就是一定要注意盡量少創建新的,使用完了以后,一定要注意丟回到連接池中;當然還要保證,數據庫的wait_timeout時間不能低於engine的pool_recyle時間,否則會出現mysql連接不可用的提示。
    在tornado里面,可以在base的on_finish方法里面將本次請求產生的session關掉;
    使用celery的時候也需要注意,可以在函數執行的末尾關掉本次創建的session,也可以寫裝飾器;並且需要注意,對函數異常也要進行捕獲。

本次的測試過程使用到的一些知識:
    ①.查詢數據庫的連接超時設置:show variables like '%wait_timeout%';
    ②.查詢數據庫的最大可用連接數:show variables like '%max_connections%';
    ③.設置數據庫的連接超時:set wait_timeout=28800;||set global wait_timeout=5;(這個global參數待查)
    ④.查看當前連接的使用情況:show status like 'Threads%';
    ⑤.查看所有的數據庫連接情況:show full processlist;
    ⑥.lsof -i :3306 查看數據庫的端口[3306]現在運行的情況

不過,后續還是需要把sqlachemy 官網推薦的web如何使用session的英文擼一擼。。。http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#session-faq-whentocreate

然后還有一個疑惑,是在使用⑥的時候,有發現有一些celery程序有出現closewait的狀態。
      tcp連接有3次握手,斷開連接有4次握手。closewait狀態的產生,其實就是如果A是主動斷開的一方,那么在B這邊顯示就會是CloseWait狀態。
      所以celery出現closewait,那就說明是mysql先關閉了連接,但是,celery和MySQL的連接,也是,一個是使用的是db_config里面的engine,回收時間是7200,mysql的wait_timeout是28800,按道理不會出現數據庫中關掉了,但是celery里面沒關掉的情況。。。
      可能是我還是有哪里沒有弄的很透徹。。。

 


免責聲明!

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



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