sqlalchemy連接池錯誤:MySQL server has gone away

原文鏈接:https://blog.csdn.net/u013673976/article/details/45939297

由於是初創公司,追求快速開發,後臺選用python,採用Tornado+SQLAlchemy,數據庫是mysql。python之前沒接觸過,都是現學的,前一週差不多都在邊看邊學邊寫的狀態,好在python還是特別簡單,有其他語言基礎很容易上手,只是經常會犯排版對齊、行末忘記“:”的錯誤。
項目還沒上線,只可能寫代碼的兩人去訪問數據庫,而且頻度很低,居然發生了2次數據庫連接錯誤。經過日誌分析,都是SQLAlchemy連接池的配置問題。
錯誤1:
TimeoutError: QueuePool limit of size 5 overflow 10 reached, connection timed out, timeout 30
錯誤2:
[ERROR] (OperationalError) (2006, 'MySQL server has gone away')

對於錯誤1,首先確認數據庫的最大連接數是足夠的,至少比log裏達到的10個連接不應該出錯。

mysql> show variables like 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 100   |
+-----------------+-------+
1 row in set (0.01 sec)


再查show global status like '%connect%';也是正常的。可以肯定是SQLAlchemy連接池的配置問題。原來的代碼:
engine = create_engine('mysql://'+etc.mysql_user+':'+etc.mysql_passwd+'@'+etc.mysql_host+':'+str(etc.mysql_port)+'/'+etc.host_name+'?charset=utf8',encoding="utf-8", echo=False) 
沒有設置pool_size的大小,默認爲5。加上pool_size=100後,此問題不再出現。

另外在初版代碼裏圖省事,寫了個循環調用sql的查詢語句,正是這個語句的調用直接導致該錯誤。把循環去掉,改爲只調用SQL一次,增加一個方法獲取多件,在之後的代碼裏循環處理業務邏輯;在調用sql的結束地方,增加finally代碼塊,明確調用session.close(),讓連接資源儘快回收到連接池。之後打算加memcached或者redis,減少DB的IO。代碼片段如下:

metadata = MetaData()
Session = sessionmaker() #使用sessionmaker()不需要顯示調用session.close()
Session.configure(bind=engine)
'''
...省略
'''
def get_img_url_by_imgid_list( p_img_list ) :
    try :
        session = Session()
        items = session.query( ImgBaseItem ).filter( ImgBaseItem.imgid.in_(p_img_list)).all()
        if not items :
            return None
        res = {}
        for item in items :
            res[ item.imgid ] = item.to_url()
        return res
    except Exception as e :
        log.exp(e)
        return None
    finally :
        session.close()


對於錯誤2,剛開始沒在意,因爲發生的時機都是在早上來上班後的第一次訪問,後面的sql請求都正常了。到第三天,意識到問題不是偶然的,查看mysql配置。

mysql> show global variables like '%timeout%';
+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| connect_timeout             | 10       |
| interactive_timeout         | 28800    |
| wait_timeout                | 28800    |
+-----------------------------+----------+


是默認設置,mysql建立的連接,在8小時內都沒有訪問請求的話,mysql server將主動斷開這條連接,後續在該連接上進行的查詢操作都將失敗,出現:error 2006 (MySQL server has gone away),到這裏問題就清楚了,SQLAlchemy連接池中的連接資源一直沒有釋放,第二天來上班時,超過了8小時,SQLAlchemy連接池中獲取的失效連接去訪問數據庫服務器導致出錯。
修復後代碼:
engine = create_engine('mysql://'+etc.mysql_user+':'+etc.mysql_passwd+'@'+etc.mysql_host+':'+str(etc.mysql_port)+'/'+etc.host_name+'?charset=utf8',encoding="utf-8",pool_size=100, pool_recycle=3600, echo=False) 
pool_recycle設置爲3600(該值必須小於數據庫服務器的interactive_timeout),連接池中的空閒連接超過1小時候,自動釋放。
在解決問題的過程中,發現還是官方文檔最好用,有空還是多上去看看:http://docs.sqlalchemy.org/en/rel_1_0/core/engines.html
關於sqlalchemy數據庫的連接配置參數摘要:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章