一.sqlalchemy連線池
我寫了乙個簡單的內網dns管理系統,用到flask和sqlalchemy。主要就是通過web頁面和api對dns記錄進行增刪改查,所有這些操作都寫入資料庫,每次更改後產生乙個celery任務來非同步的重新生成dns的配置檔案。
看起來乙個簡單的問題,但是在celery中讀取資料庫的時候出現了問題,每天早上都會報錯mysql has gone away,我重啟服務恢復正常,第二天早上又會出現同樣的問題,但是在flask的路由下呼叫的所有資料庫操作從未出現任何問題。諮詢dba,dba說資料庫是正常的,所以一定是我的程式處理有問題了。我在網上各種資料查詢,最後找到結果。
flask_sqlalchemy預設使用資料庫連線池來對理資料庫連線進行復用以減少建立連線的開銷,他缺省會對連線池中的每個連線隔2小時檢查一次是否可用,如果不可用就銷毀掉,建立新的連線放到連線池中,我們使用db.session的時候就需要從連線池中拿到乙個連線,使用完後呼叫db.session.close來將連線放回到連線池(close並不是關閉連線,關閉連線的操作由連線池來管理)。但是我在路由函式中從來沒有使用過db.session.close,也從來沒有出現過問題,是因為flask_sqlachemy會自動在請求上下文結束時自動將連線放回連線池,這樣放回連線池的連線就會每隔兩小時接受一次檢查。但是在celery中查詢的時候問題就會出現,celery中並沒有請求上下文,所有查詢完以後並不會將連線放回連線池,也就是說celery中一直使用同乙個連線,從來沒有放回過連線池,也就從來不會被檢查連線的有效性,所以連線斷開的時候進行查詢,導致報錯。
連線為什麼會斷開呢?原來mysql會把閒置不用超過8小時的連線主動關掉,而dns變更大多是白天上班的時候變更,晚上基本不會變更,這樣超過8小時以後mysql的連線已經被斷開了,而celery中使用的連線還是前一天早上重啟拿到的連線,肯定失效了,拿去查詢資料失敗,丟擲異常。
所以我後來在celery中每次查詢結束後都會呼叫db.session.close,這樣會將連線放回連線池,下次查詢會重新從連線池中獲取新的連線,這個連線每個兩個小時會被檢查,因此再也沒有出現過這個問題。
二.supervisord 與 celery
這個問題出現在發布系統中,也是讓我頭疼了好久的乙個問題,這一周終於得到解決。我們的發布系統採用celery非同步的執行ansible指令碼來進行發布的,每次發布大約需要1.5到5分鐘不等的時間。我們使用supervisord來管理web端和celery端的啟動,每次修改完**之後上線重啟發布系統之後就會出現很多發布任務卡死不再繼續執行,每次都需要手動把卡死的發布任務kill掉,然後重發,這周終於找到問題根源了。
眾所周知celery有乙個warm shutdown的機制,就是給celery master傳送乙個 sig_term訊號,celery master就會通知其管理的workers停止接受新的任務,然後等待手頭的任務結束,等到所有workers均完成任務後,master會kill掉所有workers,然後結束執行。我們的發布系統需要的就是這個功能,但是我一直感覺supervisord停止celery的時候並沒有採取warm shutdown的方式,因為每次都會又一些celery worker程序未被停止,而且永遠不會結束執行,這些celery worker中執行的發布任務就會卡死不動,這個現象叫我百思不得其解。
於是我去查supervisord的文件,發現他停止程序的時候確實預設就傳送sig_term訊號,而且我也沒有這方面的配置,說明應該是使用了warm shutdown的,看celery worker列印出來的日誌也確實是有warm shutdown,但是為什麼會出現這麼詭異的事情呢?我再看supervisord的文件,發現每個由superivsord託管的程式都有乙個配置項stopwaitsecs,表示supervisord對這個程式發出sig_term訊號(用來殺死該程式)到他收到sig_chld訊號(標誌著這個程式確實被殺死)之間他願意等待的時間,如果超過這個時間,supervisord會再次向該程式發出sig_kill訊號,這個訊號是一定會殺死其管理的程式的。也就是說,supervisord會先對celery的master進行warm shutdown的操作,完了之後等待stopwaitsecs秒之後會大開殺戒,直接乾掉celery master。而這個stopwaitsecs預設為10s,對於我們乙個平均發布時間為3分鐘左右的發布任務來說顯然等不到warm shutdown真正完成,supervisord就會粗暴的乾掉celery master。而這樣粗暴的乾掉celery master之後,celery worker貌似也出現了異常,再不幹活了,因為他是非常依賴master的,而且他幹完活之後還需要想master傳送ack確認資訊的,故此導致這些workers中的發布任務卡死。
當我把stopwaitsecs調整至10分鐘之後,再沒有出現過類似問題, 因為這個時候,supervisord對celery master進行warm shutdown 操作之後會等待最多10分鐘才會粗暴的乾掉celery master,而我們的發布任務最長不會超過7分鐘,因此10分鐘以內warm shutdown一定會成功,supervisord一定會受到sig_child訊號
使用SQLAlchemy時資料庫連線池的問題
在使用 create engine建立引擎時,如果預設不指定連線池設定的話,一般情況下,sqlalchemy會使用乙個 queuepool繫結在新建立的引擎上。並附上合適的連線池引數。在以預設的方法create engine時 如下 就會建立乙個帶連線池的引擎。engine create engin...
mysql連線池 順序 Mysql 連線池
通常,如果我們的服務涉及到mysql的操作,當乙個新的請求進來的時候,可以先連線mysql,使用完之後再斷開連線即可。但這樣做有個弊端,當請求量巨大時,會在瞬間有大量的資料庫連線與斷開操作,這是非常影響 mysql 效能的做法。此時,我們就需要使用mysql連線池。在 python 服務中使用 my...
連線池與使用Tomcat的連線池
what is connection pool?看圖 1 存放connection物件的容器 2 減少連線資料庫的開銷 3 程式請求連線時,在connection pool中取連線 4 連線使用完後,放回connection pool,不釋放 5 connection pool對連線進行管理 計數 ...