TIME_WAIT狀態的連接過多導致系統端口資源耗盡問題(1)


  • 問題表現:
    • 從某一天開始,主服務器上逐步出現了一些報錯,比如:
      • 各種連接失敗:mysql連接失敗、redis連接失敗,memcache插入數據失敗
      • 某些時候,redis的llen命令返回值還異常,正常情況下應該是返回一個整數,但有時候會返回string,string的內容是“ok”。(后續證明,這個問題是多線程使用redis不當導致)
    • 出現連接失敗的頻率變得越來越高。
  • 問題排查:
    • 首先排除網絡原因,因為這些連接不是在本地,就是在內網。
    • 再次,排除連接數超過上限原因:監控能看到mysql/redis連接數並不多
    • 最后查了一下端口資源:sudo netstat -anp | wc -l,  你妹,2w多個, 其中絕大部分的連接狀態是TIME_WAIT。好了,問題基本可以確定,就是socket連接過多,導致端口資源耗盡。
  • 問題解決

初步確定問題后,要找到問題的源頭才好解決。所以要先查這些TIME_WAIT從哪里來的。確定基本都是mysql連接

netstat -anp | grep TIME_WAIT | awk '{print $5}' | sort | uniq -c | sort -nr | less

    剛開始懷疑是網站前端php搞的,因為php的mysql連接都是短連接,短連接關閉以后,對應的socket連接狀態就會變成TIME_WAIT,持續3s左右之后才會釋放這個資源。如果前端請求較多,建立連接的速度超過釋放速度,就會導致端口資源耗盡。但php涉及mysql地方較多,一時半會兒也優化不了,所以臨時先想個方案處理一下,調整一下系統參數,設置socket連接可以重用(一般情況下不推薦):

echo 1 >> /proc/sys/net/ipv4/tcp_tw_reuse

    調整系統參數后,安定了一個星期左右,然后又開始零星出現之前的連接失敗問題。還得繼續找到源頭處理。用了一個很笨的辦法,就是不斷的查mysql的連接情況, 人工看有哪些連接經常出現,看是否能找到產生這些連接的程序

mysql -uuser -ppwd  -hdb_host -e "show full processlist"

    結果還真發現,有一類sql請求異常的多次出現,異常的原因是因為每次出現的連接端口號都不同,這意味着這個請求在不斷的申請和釋放端口資源。而這個sql請求的程序理論上應該是一個長連接才對

    查代碼,發現程序是用的一個python的mysql庫SQLAlchemy,代碼如下:

# -*- coding: utf-8 -*-
import sqlalchemy
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from common.config import mysql

class MysqlSession(object):
    mysql_engine = None
    Session = None
    def init(self):
        mysqlStr = 'mysql://{0}:{1}@{2}:{3}/{4}?charset=utf8'  \
            .format(mysql['username'], mysql['password'], mysql['host'], mysql['port'], mysql['dbname'])

        MysqlSession.mysql_engine = sqlalchemy.create_engine(
            mysqlStr,
            encoding = "utf-8",
            pool_size=20,
            pool_recycle=10,
            echo = False)
        MysqlSession.Session = sessionmaker(bind=MysqlSession.mysql_engine)

    def getSession(self):
        session = MysqlSession.Session()
        return session

Base = declarative_base()

    程序里在初始化的地方調用了上面的init,然后在一個循環里,不斷的調用getSession,然后close session。特地去實驗了一下,每次getSession確實都會從一個新的端口去連接mysql server。於是改掉此處,在循環外調用getSession和關閉 session,TIME_WAIT連接數很快就下降到幾百!

 

看起來問題解決,后續繼續觀察。


免責聲明!

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



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