petitviolet_blog

@petitviolet blog

FlaskとSQLAlchemyを使っててMySQL server has gone awayってなる

flaskとsqlalchemyでapiを実装し、そのapiに対して一度リクエストしてからmysqlのwaittime_outが過ぎると

OperationalError: (OperationalError) (2006, 'MySQL server has gone away')

というエラーが出てしまい、うまく通信が出来なかった。
ちなみに、androidのvolleyを使ったリクエストです。

解決策

  1. wait_timeを長くする
    • 上記のエラーが出る頻度は減るが、根本的な解決ではないし、mysqlの最大接続数を超えてしまう危険性がある
    • よって却下
  2. キャッシュのtimeoutを長くする
    • ごまかせるが、やはり根本的な解決ではない
  3. sqlalchemyとflaskを何とかする
    • これしかない(?)

やったこと

色々調べながら手当たり次第にやったので、どれが効果あったのかいまいちわかってません...。
とりあえずやったことを列挙

1. sqlalchemyのcraete_engineの設定をいじる
参考:
(古いけど日本語) http://omake.accense.com/static/doc-ja/sqlalchemy/reference/sqlalchemy/pooling.html
(新しいけど英語) http://docs.sqlalchemy.org/en/latest/core/pooling.html

engine = create_engine("mysql://{user}:{passwd}@{host}/{db}"\
         .format(user=user, passwd=passwd, host=host, db=db),\
         encoding="utf-8", echo=False, pool_size=15, pool_recycle=3600,\
         max_overflow=0, echo_pool=True)

2. sqlalchemyのsessionの作り方を変える
参考:
(古いけど日本語) http://omake.accense.com/static/doc-ja/sqlalchemy/session.html
(新しいけど英語) http://docs.sqlalchemy.org/en/rel_0_9/orm/session.html

from sqlalchmy.orm import sessionmaker, scoped_session

Session = scoped_session(sessionmaker(\
          autocommit=False, autoflush=False, bind=engine))
# session = Session()として使う

3. sessionを毎回commitする
参考:見失った

hoge = session.query(Table).all()#selectする
session.commit()
session.close()


4. flaskのappをいじる
参考:http://flask.pocoo.org/docs/patterns/sqlalchemy/

app = Flask("app_name")
@app.teardown_appcontext
def shutdown_session(exception=None):
    Session.remove()

Sessionが使えなくなっちゃうのでやめたほうがいいです多分。


5. mysqlserverにpingを送ってプロセスを起こす
参考:http://docs.sqlalchemy.org/en/latest/core/pooling.html

from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy.pool import Pool

@event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
    cursor = dbapi_connection.cursor()
    try:
        cursor.execute("SELECT 1")
    except:
        # optional - dispose the whole pool
        # instead of invalidating one at a time
        # connection_proxy._pool.dispose()

        # raise DisconnectionError - pool will try
        # connecting again up to three times before raising.
        raise exc.DisconnectionError()
    cursor.close()

これが効いたかも?

mysql

備忘録的

プロセスをみる

mysqlのコンソールから、

show processlist;

ってやるとプロセス一覧が見れる

設定値をみる
show variables; # like "%timeout";

ってやれば設定値がみれる
timeout関係がみたければlikeでみる
また、これだとセッション値がみれて、(/etc/my.cnfで)設定した値を確認するには

show global variables;

とする
コンソールから変更するには

set session wait_timeout = 15;
set global wait_timeout = 15;

とでもすればOK
globalの方は権限が必要っぽいですが