错误2006年:MySQL服务器已经消失

我使用uWSGI和nginx在CentOS服务器上运行Python金字塔应用程序。 我使用SQLAlchemy作为ORM,MySQLdb作为API,MySQL作为数据库。 该网站还没有活着,所以唯一的交通是我和公司的其他员工。 我们购买了一些数据来填充数据库,所以最大的(也是最经常查询的)表是大约150,000行。

昨天我迅速连续打开了网站的四个新标签,并且收到了一些502错误的网关错误。 我查看了uWSGI日志,发现如下:

sqlalchemy.exc.OperationalError: (OperationalError) (2006, 'MySQL server has gone away') 'SELECT ge... 

重要提示:这个错误不是由于MySQL的wait_timeout造成的。 去过也做过。

我想知道这个问题是否是由同时服务的并发请求造成的。 我使自己成为一个穷人的负载testing仪:

 for i in {1..10}; do (curl -o /dev/null http://domain.com &); done; 

果然,在这十个请求中,至less有一个会抛出2006年的错误,时常更多。 有时错误会变得更加陌生,例如:

 sqlalchemy.exc.NoSuchColumnError: "Could not locate column in row for column 'table.id'" 

当列最肯定存在和工作正常所有其他相同的请求。 或者,这个:

 sqlalchemy.exc.ResourceClosedError: This result object does not return rows. It has been closed automatically. 

当再一次,所有其他请求都能正常工作。

为了进一步validation问题源于并发数据库连接,我将uWSGI设置为单个worker,禁用了multithreading,强制一次处理一个请求。 果然,问题消失了。

为了试图find这个问题,我为MySQL设置了一个错误日志。 除了在MySQL启动时的一些通知,它仍然是空的。

这是我的MySQLconfiguration:

 [mysqld] default-storage-engine = myisam key_buffer = 1M query_cache_size = 1M query_cache_limit = 128k max_connections=25 thread_cache=1 skip-innodb query_cache_min_res_unit=0 tmp_table_size = 1M max_heap_table_size = 1M table_cache=256 concurrent_insert=2 max_allowed_packet = 1M sort_buffer_size = 64K read_buffer_size = 256K read_rnd_buffer_size = 256K net_buffer_length = 2K thread_stack = 64K innodb_file_per_table=1 log-error=/var/log/mysql/error.log 

大量的谷歌上显示的错误很less,但build议我增加max_allowed_pa​​cket。 我增加到100M,并重新启动MySQL,但这根本没有帮助。

总结一下: MySQL的并发连接导致2006, 'MySQL server has gone away'等一些奇怪的错误。 在MySQL的错误日志中没有任何关联。

我一直在这工作几个小时,没有取得任何进展。 有人能帮我吗?

我也遇到过这个,find原因并修复。

发生这种情况的原因是,在应用程序加载到父级之后,python uwsgi插件(或者更可能是所有的uwsgi插件)fork()新工作者。 结果,子项从父项inheritance所有资源(包括文件描述符,如db连接)。

你可以在uwsgi wiki上简单阅读一下:

uWSGI尽可能地尝试滥用fork()拷贝。 默认情况下,它将在加载应用程序后分叉。 如果你不想要这样的行为,请使用–lazy选项。 启用它,将指示uWSGI在每个工人的fork()之后加载应用程序

正如你所知,Python的mysqldb连接和游标不是线程安全的,除非你明确地保护它们。 因此多个进程(如uwsgi worker)同时使用相同的mysql连接/游标会损坏它。

在我的情况下(对于亚瑟王的黄金 API),当我在另一个模块的作用域中创build每个请求的MySQL连接时,这个工作正常,但是当我需要持久连接来提高性能时,我将数据库连接和光标移动到全局范围父模块。 结果,我的联系就像你一样在彼此之间走来走去。

解决这个问题的方法是将“lazy”关键字(或–lazy命令行选项)添加到您的uwsgiconfiguration中。 因此,应用程序将被重新分配给每个孩子,而不是从父母分支并共享连接(并且在某个时刻踩到这个连接,使得MySQL服务器由于某个点上的请求被破坏而强制它closures)。

最后,如果你想在不修改你的uwsgiconfiguration的情况下做到这一点,你可能会使用@postfork装饰器在分支工作进程之后立即创build一个新的数据库连接。 你可以在这里阅读。

我从后续看到,你已经切换到pgsql,但这里的答案是,你可以在晚上睡得更好,对于像你我这样的人,我试图find答案!

PS一旦我对这个问题有所了解(由于工作人员相互之间的光标被损坏了),但是没有意识到fork()和–lazy的问题,我正在考虑实现我自己的池,从全局范围池中检查“一个mysql连接,然后在退出应用程序()前重新检查”,但是可能使用起来更好 – 除非你的Web /应用程序负载变化足够大,以至于你不断创造新的工作者。 即使这样,我可能更喜欢 – 懒,因为它比实现你自己的数据库连接池更清洁。

编辑:这是一个更彻底的写这个问题+解决scheme,因为其他人遇到它的信息短缺: http : //tns.u13.net/?p=190