sql >> データベース >  >> RDS >> Mysql

フラスコでpymysqlを使用中にエラーが発生しました

    まず、MySQLへの永続的な接続を維持するかどうかを決定する必要があります。後者の方がパフォーマンスは優れていますが、少しメンテナンスが必要です。

    デフォルト wait_timeout MySQLでは8時間です。接続がwait_timeoutより長くアイドル状態になっているときはいつでも 閉まっています。 MySQLサーバーを再起動すると、確立されたすべての接続も閉じます。したがって、持続的接続を使用する場合は、接続を使用する前に、接続が有効かどうかを確認する必要があります(有効でない場合は再接続します)。リクエストごとの接続を使用する場合、接続は常に新しいため、接続の状態を維持する必要はありません。

    リクエストごとの接続

    非永続的なデータベース接続には、着信HTTP要求ごとに、接続を開く、ハンドシェイクなど(データベースサーバーとクライアントの両方)の明らかなオーバーヘッドがあります。

    これは、Flaskの公式チュートリアルデータベース接続について からの引用です。 :

    ただし、アプリケーションコンテキスト リクエストごとに初期化されます(これは、効率の懸念とフラスコの用語によって覆い隠されています)。したがって、それはまだ非常に非効率的です。しかし、それはあなたの問題を解決するはずです。これは、pymysqlに適用されたものとして提案されているものの抜粋です。 :

    import pymysql
    from flask import Flask, g, request    
    
    app = Flask(__name__)    
    
    def connect_db():
        return pymysql.connect(
            user = 'guest', password = '', database = 'sakila', 
            autocommit = True, charset = 'utf8mb4', 
            cursorclass = pymysql.cursors.DictCursor)
    
    def get_db():
        '''Opens a new database connection per request.'''        
        if not hasattr(g, 'db'):
            g.db = connect_db()
        return g.db    
    
    @app.teardown_appcontext
    def close_db(error):
        '''Closes the database connection at the end of request.'''    
        if hasattr(g, 'db'):
            g.db.close()    
    
    @app.route('/')
    def hello_world():
        city = request.args.get('city')
    
        cursor = get_db().cursor()
        cursor.execute('SELECT city_id FROM city WHERE city = %s', city)
        row = cursor.fetchone()
    
        if row:
          return 'City "{}" is #{:d}'.format(city, row['city_id'])
        else:
          return 'City "{}" not found'.format(city)
    

    持続的接続

    持続的接続データベース接続には、2つの主要なオプションがあります。接続のプールがあるか、接続をワーカープロセスにマップします。通常、Flask WSGIアプリケーションは、スレッド数が固定されたスレッドサーバー(uWSGIなど)によって提供されるため、スレッドマッピングはより簡単で効率的です。

    パッケージ、DBUtils があります 、と PersistentDBの両方を実装します。 スレッドマップ接続用。

    持続的接続を維持する上での重要な注意点の1つは、トランザクションです。再接続のAPIは、ping 。単一ステートメントの自動コミットには安全ですが、トランザクションの合間に中断する可能性があります(詳細こちら )。 DBUtilsがこれを処理し、dbapi.OperationalErrorでのみ再接続する必要があります およびdbapi.InternalError (デフォルトでは、failuresによって制御されます PersistentDBのイニシャライザーへ )トランザクション外で発生しました。

    上記のスニペットは、PersistentDBでどのように表示されますか。 。

    import pymysql
    from flask import Flask, g, request
    from DBUtils.PersistentDB import PersistentDB    
    
    app = Flask(__name__)    
    
    def connect_db():
        return PersistentDB(
            creator = pymysql, # the rest keyword arguments belong to pymysql
            user = 'guest', password = '', database = 'sakila', 
            autocommit = True, charset = 'utf8mb4', 
            cursorclass = pymysql.cursors.DictCursor)
    
    def get_db():
        '''Opens a new database connection per app.'''
    
        if not hasattr(app, 'db'):
            app.db = connect_db()
        return app.db.connection()    
    
    @app.route('/')
    def hello_world():
        city = request.args.get('city')
    
        cursor = get_db().cursor()
        cursor.execute('SELECT city_id FROM city WHERE city = %s', city)
        row = cursor.fetchone()
    
        if row:
          return 'City "{}" is #{:d}'.format(city, row['city_id'])
        else:
          return 'City "{}" not found'.format(city)
    

    マイクロベンチマーク

    パフォーマンスへの影響が数値にどのような影響を与えるかについて少し手がかりを与えるために、ここにマイクロベンチマークがあります。

    実行しました:

    • uwsgi --http :5000 --wsgi-file app_persistent.py --callable app --master --processes 1 --threads 16
    • uwsgi --http :5000 --wsgi-file app_per_req.py --callable app --master --processes 1 --threads 16

    そして、以下を介して同時実行1、4、8、16でそれらをロードテストしました:

    siege -b -t 15s -c 16 http://localhost:5000/?city=london
    

    観察(私のローカル構成の場合):

    1. 持続的接続は最大30%高速です
    2. 同時実行性4以上では、uWSGIワーカープロセスはCPU使用率の100%以上でピークに達します(pymysql MySQLプロトコルを純粋なPythonで解析する必要があります。これがボトルネックです)、
    3. 同時実行16では、mysqld のCPU使用率は、リクエストごとに最大55%、持続的接続に最大45%です。


    1. SQL Server(T-SQL)で英国形式で日付を表示する方法

    2. 販売データベースを持つことの利点は何ですか?

    3. MySQLでコミットされていないデータを取得する

    4. MySQL JDBCドライバー接続文字列とは何ですか?