SQLAlchemy数据库连接池错误

by LauCyun Jul 07,2017 11:32:38 62,747 views

最近,发现我的博客有时不能正常登录(用户名和密码都对),经过日志分析都是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.00 sec)

再查show global status like '%connect%';也是正常的。

可以肯定是SQLAlchemy连接池的配置问题。原来的代码:

engine = create_engine(
    'mysql+mysqlconnector://{username}:{password}@{host}:{port}/{dbname}?charset=utf8'.format(
        username=DB_CONFIG["MySQL"]["username"],
        password=DB_CONFIG["MySQL"]["password"],
        host=DB_CONFIG["MySQL"]["host"],
        port=DB_CONFIG["MySQL"]["port"],
        dbname=DB_CONFIG["MySQL"]["dbname"]
    ),
    encoding='utf-8',
    echo=False,
)

没有设置pool_size的大小,默认为5。加上pool_size=100后,此问题不再出现。

另外在在调用sql的结束地方,增加finally代码块,明确调用session.close(),让连接资源尽快回收到连接池,代码片段如下:

def query(p_img_list):
    session = DBSession()
    try:
        ...
    except Exception as e:
        pass
    finally:
        session.close()

 

错误2:

刚开始没在意,博客阅读文章等业务都很正常,就只有登录不进去后台,重启服务就正常,到后来发生好几次,意识到问题不是偶然的,查看mysql配置。

mysql> show global variables like '%timeout%';
+----------------------------+----------+
| Variable_name              | Value    |
+----------------------------+----------+
| connect_timeout            | 10       |
| interactive_timeout        | 28800    |
| wait_timeout               | 28800    |
+----------------------------+----------+
3 rows in set (0.00 sec)

由于mysql建立的连接,在8小时内都没有访问请求的话,mysql server将主动断开这条连接,后续在该连接上进行的查询操作都将失败,出现:error 2006 (MySQL server has gone away),到这里问题就清楚了,SQLAlchemy连接池中的连接资源一直没有释放,第二天来上班时,超过了8小时,SQLAlchemy连接池中获取的失效连接去访问数据库服务器导致出错。

修复后代码:

engine = create_engine(
    'mysql+mysqlconnector://{username}:{password}@{host}:{port}/{dbname}?charset=utf8'.format(
        username=DB_CONFIG["MySQL"]["username"],
        password=DB_CONFIG["MySQL"]["password"],
        host=DB_CONFIG["MySQL"]["host"],
        port=DB_CONFIG["MySQL"]["port"],
        dbname=DB_CONFIG["MySQL"]["dbname"]
    ),
    encoding='utf-8',
    pool_size=100,
    pool_recycle=3600,  # 1 hour
    echo=False,
)

pool_recycle设置为3600(该值必须小于数据库服务器的interactive_timeout),连接池中的空闲连接超过1小时候,自动释放。

在解决问题的过程中,发现还是官方文档最好用,有空还是多上去看看:http://docs.sqlalchemy.org/en/rel_1_0/core/engines.html

关于sqlalchemy数据库的连接配置参数摘要:

Parameters:
  • case_sensitive=True –

    if False, result column names will match in a case-insensitive fashion, that is, row['SomeColumn'].

    Changed in version 0.8: By default, result row names match case-sensitively. In version 0.7 and prior, all matches were case-insensitive.

  • connect_args – a dictionary of options which will be passed directly to the DBAPI’s connect() method as additional keyword arguments. See the example at Custom DBAPI connect() arguments.
  • convert_unicode=False –

    if set to True, sets the default behavior of convert_unicode on the String type to True, regardless of a setting of False on an individual String type, thus causing all String -based columns to accommodate Python unicode objects. This flag is useful as an engine-wide setting when using a DBAPI that does not natively support Python unicode objects and raises an error when one is received (such as pyodbc with FreeTDS).

    See String for further details on what this flag indicates.

  • creator – a callable which returns a DBAPI connection. This creation function will be passed to the underlying connection pool and will be used to create all new database connections. Usage of this function causes connection parameters specified in the URL argument to be bypassed.
  • echo=False – if True, the Engine will log all statements as well as a repr() of their parameter lists to the engines logger, which defaults to sys.stdout. The echo attribute of Engine can be modified at any time to turn logging on and off. If set to the string "debug", result rows will be printed to the standard output as well. This flag ultimately controls a Python logger; see Configuring Logging for information on how to configure logging directly.
  • echo_pool=False – if True, the connection pool will log all checkouts/checkins to the logging stream, which defaults to sys.stdout. This flag ultimately controls a Python logger; see Configuring Logging for information on how to configure logging directly.
  • encoding –

    Defaults to utf-8. This is the string encoding used by SQLAlchemy for string encode/decode operations which occur within SQLAlchemy, outside of the DBAPI. Most modern DBAPIs feature some degree of direct support for Python unicode objects, what you see in Python 2 as a string of the form u'some string'. For those scenarios where the DBAPI is detected as not supporting a Python unicode object, this encoding is used to determine the source/destination encoding. It is not used for those cases where the DBAPI handles unicode directly.

    To properly configure a system to accommodate Python unicode objects, the DBAPI should be configured to handle unicode to the greatest degree as is appropriate - see the notes on unicode pertaining to the specific target database in use at Dialects.

    Areas where string encoding may need to be accommodated outside of the DBAPI include zero or more of:

    • the values passed to bound parameters, corresponding to the Unicode type or the String type when convert_unicode is True;
    • the values returned in result set columns corresponding to the Unicode type or the String type when convert_unicode is True;
    • the string SQL statement passed to the DBAPI’s cursor.execute() method;
    • the string names of the keys in the bound parameter dictionary passed to the DBAPI’s cursor.execute() as well as cursor.setinputsizes() methods;
    • the string column names retrieved from the DBAPI’s cursor.description attribute.

    When using Python 3, the DBAPI is required to support all of the above values as Python unicode objects, which in Python 3 are just known as str. In Python 2, the DBAPI does not specify unicode behavior at all, so SQLAlchemy must make decisions for each of the above values on a per-DBAPI basis - implementations are completely inconsistent in their behavior.

  • execution_options – Dictionary execution options which will be applied to all connections. See execution_options()
  • implicit_returning=True – When True, a RETURNING- compatible construct, if available, will be used to fetch newly generated primary key values when a single row INSERT statement is emitted with no existing returning() clause. This applies to those backends which support RETURNING or a compatible construct, including Postgresql, Firebird, Oracle, Microsoft SQL Server. Set this to False to disable the automatic usage of RETURNING.
  • isolation_level –

    this string parameter is interpreted by various dialects in order to affect the transaction isolation level of the database connection. The parameter essentially accepts some subset of these string arguments: "SERIALIZABLE""REPEATABLE_READ""READ_COMMITTED""READ_UNCOMMITTED" and "AUTOCOMMIT". Behavior here varies per backend, and individual dialects should be consulted directly.

    Note that the isolation level can also be set on a per-Connection basis as well, using the Connection.execution_options.isolation_level feature.

    See also

    Connection.default_isolation_level - view default level

    Connection.execution_options.isolation_level - set per Connection isolation level

    SQLite Transaction Isolation

    Postgresql Transaction Isolation

    MySQL Transaction Isolation

    Setting Transaction Isolation Levels - for the ORM

  • label_length=None – optional integer value which limits the size of dynamically generated column labels to that many characters. If less than 6, labels are generated as “_(counter)”. If None, the value of dialect.max_identifier_length is used instead.
  • listeners – A list of one or more PoolListener objects which will receive connection pool events.
  • logging_name – String identifier which will be used within the “name” field of logging records generated within the “sqlalchemy.engine” logger. Defaults to a hexstring of the object’s id.
  • max_overflow=10 – the number of connections to allow in connection pool “overflow”, that is connections that can be opened above and beyond the pool_size setting, which defaults to five. this is only used with QueuePool.
  • module=None – reference to a Python module object (the module itself, not its string name). Specifies an alternate DBAPI module to be used by the engine’s dialect. Each sub-dialect references a specific DBAPI which will be imported before first connect. This parameter causes the import to be bypassed, and the given module to be used instead. Can be used for testing of DBAPIs as well as to inject “mock” DBAPI implementations into the Engine.
  • paramstyle=None – The paramstyle to use when rendering bound parameters. This style defaults to the one recommended by the DBAPI itself, which is retrieved from the .paramstyle attribute of the DBAPI. However, most DBAPIs accept more than one paramstyle, and in particular it may be desirable to change a “named” paramstyle into a “positional” one, or vice versa. When this attribute is passed, it should be one of the values "qmark""numeric""named""format" or "pyformat", and should correspond to a parameter style known to be supported by the DBAPI in use.
  • pool=None – an already-constructed instance of Pool, such as a QueuePool instance. If non-None, this pool will be used directly as the underlying connection pool for the engine, bypassing whatever connection parameters are present in the URL argument. For information on constructing connection pools manually, see Connection Pooling.
  • poolclass=None – a Pool subclass, which will be used to create a connection pool instance using the connection parameters given in the URL. Note this differs from pool in that you don’t actually instantiate the pool in this case, you just indicate what type of pool to be used.
  • pool_logging_name – String identifier which will be used within the “name” field of logging records generated within the “sqlalchemy.pool” logger. Defaults to a hexstring of the object’s id.
  • pool_size=5 – the number of connections to keep open inside the connection pool. This used with QueuePool as well as SingletonThreadPool. With QueuePool, a pool_size setting of 0 indicates no limit; to disable pooling, set poolclass to NullPool instead.
  • pool_recycle=-1 – this setting causes the pool to recycle connections after the given number of seconds has passed. It defaults to -1, or no timeout. For example, setting to 3600 means connections will be recycled after one hour. Note that MySQL in particular will disconnect automatically if no activity is detected on a connection for eight hours (although this is configurable with the MySQLDB connection itself and the server configuration as well).
  • pool_reset_on_return='rollback' –

    set the “reset on return” behavior of the pool, which is whether rollback()commit(), or nothing is called upon connections being returned to the pool. See the docstring forreset_on_return at Pool.

    New in version 0.7.6.

  • pool_timeout=30 – number of seconds to wait before giving up on getting a connection from the pool. This is only used with QueuePool.
  • strategy='plain' –

    selects alternate engine implementations. Currently available are:

  • executor=None – a function taking arguments (sql, *multiparams, **params), to which the mock strategy will dispatch all statement execution. Used only by strategy='mock'.

(全文完)

Tags