SQLAlchemy连接在AWS MySQL RDS重启时挂起并发生故障转移

时间:2016-04-04 16:08:20

标签: python mysql sqlalchemy rds

我们有一个Python服务器,它使用SQLAlchemy从AWS MySQL MultiAZ RDS实例读取/写入数据。

我们正在经历一种行为,我们希望避免每当我们触发故障转移重启时,已经打开的连接然后发出声明无限期挂起。虽然根据AWS文档可以预期这一点,但我们希望Python MySQL连接器能够应对这种情况。

我们在网上找到的最接近的案例是google groups thread,其中讨论了该问题并提供了有关Postgres RDS的解决方案。

例如,下面的脚本将在启动故障转移重启时无限期挂起(从上面提到的谷歌群组线程中采用)。

from datetime import datetime
from time import time, sleep
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.scoping import scoped_session
from sqlalchemy.ext.declarative import declarative_base

import logging

current_milli_time = lambda: int(round(time() * 1000))
Base = declarative_base()

logging.basicConfig(format='%(asctime)s %(filename)s %(lineno)s %(process)d %(levelname)s: %(message)s', level="INFO")

class Message(Base):
    __tablename__ = 'message'
    id = Column(Integer, primary_key=True)
    body = Column(String(450), nullable=False)

engine = create_engine('mysql://<username>:<password>@<db_host>/<db_name>',echo=False, pool_recycle=1800,)
session_maker = scoped_session(sessionmaker(bind=engine, autocommit=False, autoflush=False))
session = session_maker()

while True:
    try:
        ids = ''
        start = current_milli_time()
        for msg in session.query(Message).order_by(Message.id.desc()).limit(5):
            ids += str(msg.id) + ', '
            logging.info('({!s}) (took {!s} ms) fetched ids: {!s}'.format(datetime.now().time().isoformat(), current_milli_time() - start, ids))

        start = current_milli_time()
        m = Message()
        m.body = 'some text'
        session.add(m)
        session.commit()
        logging.info('({!s}) (took {!s} ms) inserted new message'.format(datetime.now().time().isoformat(), current_milli_time() - start))

    except Exception, e:
        logging.exception(e)
        session.rollback()
    finally:
        session_maker.remove()

    sleep(0.25)

我们已尝试使用连接超时但似乎问题与已打开的连接有关,只要AWS切换到故障转移实例,该连接就会挂起。

我们的问题是 - 是否有人遇到此问题或有可能的方向值得检查?

1 个答案:

答案 0 :(得分:3)

恕我直言,使用SQL连接器超时来处理switchcover就像是黑魔法。每个连接器的行为都不同,难以诊断。

如果您再次阅读@univerio评论,AWS将为SAME RDS端点名称重新分配新的IP地址。在进行切换时,您的RDS端点名称和旧IP加密器仍在您的服务器实例DNS缓存中。所以这是一个DNS缓存问题,这就是AWS要求你“清理......”的原因。

除非您重新启动SQLAlchemy以再次读取DNS,否则会话无法知道发生了什么并动态切换。最糟糕的是,问题可能发生在SQLAlchemy使用的连接器中。

恕我直言,在代码内部处理切换是不值得的。我将订阅像lambda这样的AWS服务,它可以在切换事件时起作用,触发应用服务器重新启动连接,这意味着反映新的IP地址。