首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >App Engine对Google Cloud SQL的连接限制是什么,以及如何最好地重用DB连接?

问App Engine对Google Cloud SQL的连接限制是什么,以及如何最好地重用DB连接?
EN

Stack Overflow用户
提问于 2012-05-03 10:46:31
回答 2查看 6.8K关注 0票数 10

我有一个Google App Engine应用程序,它使用Google Cloud SQL实例来存储数据。我需要我的实例能够通过restful调用一次为数百个客户端提供服务,每个调用都会导致一个或几个DB查询。我已经包装了需要DB访问的方法,并将DB连接的句柄存储在os.environ中。关于我是如何做到这一点的,请参阅this SO问题/答案。

然而,只要有几百个客户端连接到我的应用程序并触发数据库调用,我就开始在Google app Engine错误日志中收到这些错误(当然,我的应用程序返回500 ):

代码语言:javascript
复制
could not connect: ApplicationError: 1033 Instance has too many concurrent requests: 100 Traceback (most recent call last): File "/base/python27_run

有经验的Google App Engine和Google Cloud SQL用户有什么建议吗?提前谢谢。

下面是我在需要DB连接的方法周围使用的装饰器的代码:

代码语言:javascript
复制
def with_db_cursor(do_commit = False):
    """ Decorator for managing DB connection by wrapping around web calls.
    Stores connections and open connection count in the os.environ dictionary
    between calls.  Sets a cursor variable in the wrapped function. Optionally
    does a commit.  Closes the cursor when wrapped method returns, and closes
    the DB connection if there are no outstanding cursors.

    If the wrapped method has a keyword argument 'existing_cursor', whose value
    is non-False, this wrapper is bypassed, as it is assumed another cursor is
    already in force because of an alternate call stack.

    Based mostly on post by : Shay Erlichmen
    At: https://stackoverflow.com/a/10162674/379037
    """

    def method_wrap(method):
        def wrap(*args, **kwargs):
            if kwargs.get('existing_cursor', False):
                #Bypass everything if method called with existing open cursor
                vdbg('Shortcircuiting db wrapper due to exisiting_cursor')
                return  method(None, *args, **kwargs)

            conn = os.environ.get("__data_conn")

            # Recycling connection for the current request
            # For some reason threading.local() didn't work
            # and yes os.environ is supposed to be thread safe 
            if not conn:                    
                conn = _db_connect()
                os.environ["__data_conn"] = conn
                os.environ["__data_conn_ref"] = 1
                dbg('Opening first DB connection via wrapper.')
            else:
                os.environ["__data_conn_ref"] = (os.environ["__data_conn_ref"] + 1)
                vdbg('Reusing existing DB connection. Count using is now: {0}',
                    os.environ["__data_conn_ref"])        
            try:
                cursor = conn.cursor()
                try:
                    result = method(cursor, *args, **kwargs)
                    if do_commit or os.environ.get("__data_conn_commit"):
                        os.environ["__data_conn_commit"] = False
                        dbg('Wrapper executing DB commit.')
                        conn.commit()
                    return result                        
                finally:
                    cursor.close()                    
            finally:
                os.environ["__data_conn_ref"] = (os.environ["__data_conn_ref"] -
                        1)  
                vdbg('One less user of DB connection. Count using is now: {0}',
                    os.environ["__data_conn_ref"])
                if os.environ["__data_conn_ref"] == 0:
                    dbg("No more users of this DB connection. Closing.")
                    os.environ["__data_conn"] = None
                    db_close(conn)
        return wrap
    return method_wrap

def db_close(db_conn):
    if db_conn:
        try:
            db_conn.close()
        except:
            err('Unable to close the DB connection.', )
            raise
    else:
        err('Tried to close a non-connected DB handle.')
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-05-04 01:09:18

简而言之:您的查询可能太慢,mysql服务器没有足够的线程来处理您试图发送给它的所有请求。

长长的答案:

作为背景,云SQL有两个限制,这里有两个相关的限制:

  • 连接:这些连接对应于代码中的“conn”对象。在服务器上有一个相应的数据结构。一旦这些对象过多(当前配置为1000个),最近最少使用的对象将自动关闭。当您下面的连接关闭时,下次尝试使用该connection.
  • Concurrent请求时,您将得到一个未知的连接错误(ApplicationError: 1007):这些是在服务器上执行的查询。每个执行的查询都占用服务器中的一个线程,因此限制为100个。当并发请求太多时,后续请求将被拒绝,并显示错误(ApplicationError: 1033)

这听起来不像是连接限制在影响你,但我想提一下以防万一。

对于并发请求,增加限制可能会有所帮助,但这通常会使问题变得更糟。我们过去看到过两种情况:

  • 死锁:长时间运行的查询正在锁定数据库的关键行。所有后续查询都会在该锁上阻塞。应用程序对这些查询超时,但它们继续在服务器上运行,将这些线程捆绑在一起,直到triggers.
  • Slow deadlock timeout查询:每个查询都非常非常慢。当查询需要临时文件排序时,通常会发生这种情况。应用程序超时并重试查询,而查询的第一次尝试仍在运行,并根据并发请求限制进行计数。如果你能找到你的平均查询时间,你就可以估计出你的mysql实例可以支持多少QPS (例如,每次查询5毫秒意味着每个线程200 QPS。由于有100个线程,您可以执行20,000 QPS。每次查询50毫秒意味着2000 QPS。)

您应该使用EXPLAIN和SHOW ENGINE INNODB STATUS来查看这两个问题中的哪一个。

当然,也有可能你只是在你的实例上驱动了大量的流量,而没有足够的线程。在这种情况下,您可能无论如何都会耗尽实例的cpu,因此添加更多的线程也无济于事。

票数 15
EN

Stack Overflow用户

发布于 2014-09-01 12:02:05

我阅读了文档,注意到有12个连接/实例的限制:

查找“每个App Engine实例到Google Cloud SQL实例的并发连接不能超过12个”。在https://developers.google.com/appengine/docs/python/cloud-sql/中

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10424442

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档