MySQL 错误:无法创建线程来处理由许多 Gunicorn API 请求触发的新连接(errno = 11)

MySQL 错误:无法创建线程来处理由许多 Gunicorn API 请求触发的新连接(errno = 11)

我在托管虚拟服务器上运行 Ubuntu 16.04.4 LTS,该服务器具有 MySQL DB 5.7.23 和 Gunicorn Web 服务器,它为 Web 应用程序提供 API。一切都运行正常,但是当我遇到许多 API 请求(>200 个连接/请求)时,MySQL 服务器会给我这个错误:

无法创建线程来处理新连接(errno= 11)

有时,在出现 mysql 错误后,我甚至在每个命令行命令上都会出现此错误,直到我停止初始化与 MySql 服务器连接的 Web 服务器:

sudo:无法分叉:无法分配内存

在 Google 上搜索解决方案几天后,我更改了一些设置,但不幸的是,这并没有解决问题。这是我当前的配置:

/etc/mysql/mysql.conf.d/mysqld.cnf:

[mysqld_safe]
socket      = /var/run/mysqld/mysqld.sock
nice        = 0
log_error = /var/log/mysql/mysql_error.log

[mysqld]
user        = mysql
pid-file    = /var/run/mysqld/mysqld.pid
socket      = /var/run/mysqld/mysqld.sock
port        = 3306
basedir     = /usr
datadir     = /var/lib/mysql
tmpdir      = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
key_buffer_size     = 16M
max_allowed_packet  = 16M
thread_stack        = 256K
thread_cache_size       = 500
myisam-recover-options  = BACKUP
max_connections        = 20000
query_cache_limit   = 1M
query_cache_size        = 16M
log_error = /var/log/mysql/mysql_error.log
expire_logs_days    = 10
max_binlog_size   = 100M
innodb_buffer_pool_size = 2G

/etc/systemd/system/mysql.service.de/override.conf

[Service]
LimitNOFILE=1024000
LimitNPROC=1024000

/etc/security/limits.conf

mysql  soft   nproc   20960
mysql  hard   nproc   45960
mysql  soft   nofile   20960
mysql  hard   nofile   45960

/etc/security/limits.d

mysql  soft   nproc   20960
mysql  hard   nproc   45960
mysql  soft   nofile   20960
mysql  hard   nofile   45960
root   soft   nproc    20960
root   hard   nproc    45960
root   soft   nofile   20960
root   hard   nofile   45960

我的物理内存并没有用完(大约有 12GB-14GB 可用),如果我正确理解了所有新配置,我就不再会遇到操作系统级别的最大线程限制。

发生错误时,htop 如下所示: 顶部

编辑:设置说明: 我在 Gunicorn 应用服务器前面使用 Nginx 作为反向代理。Gunicorn 服务器运行着 8 个工作进程,每个工作进程有 2 个线程。

应用程序: Flask 网页上有多个图表,显示多个时间序列。每个图表都通过同一服务器上的内部异步“API”请求加载。API 请求基本上返回图表配置和时间序列数据。如果我在网页上有 20 个图表,我会向 API 发出 20 个异步请求。此外,API 还在内部使用 API 的其他部分。例如https://xyz/getCharts/1--> 进行一次数据库查询,获取图表 1 中应显示的内容信息,然后再次调用 API 请求所需的时间序列数据https://xyz/getSeries/123,这又会进行数据库查询。因此,一个 API 请求可以触发多个其他 API 请求和数据库请求。由于复合索引和每个查询的数据量相对较少,每个数据库查询本身都非常快。

评论表明,对于 MySQL 数据库或服务器设置来说,超过 200 个连接/请求太多了。如果是这样,我该如何限制客户端的请求数量?所以基本上是在 Nginx 或 Gunicorn 级别限制请求。到目前为止,我在这方面尝试过的是减少 gunicorn 工作者的数量。但是,当我这样做时,我得到了这样的 gunicorn 错误:

OSError:[Errno 105] 没有可用的缓冲区空间

这对我来说根本没有意义,当我减少工人数量时,我会遇到缓冲区空间错误。

编辑2: 完整流程列表 ps:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0 188876  2352 ?        Ss   Feb19   0:01 init -z
root         2  0.0  0.0      0     0 ?        S    Feb19   0:00 [kthreadd/277985]
root         3  0.0  0.0      0     0 ?        S    Feb19   0:00 [khelper/2779850]
root         4  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root         5  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root         6  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root         7  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root         8  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root         9  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        10  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        11  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        12  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        13  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        14  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        15  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        16  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        17  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        18  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        19  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        20  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        21  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        22  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        23  0.0  0.0      0     0 ?        S    Feb19   0:00 [rpciod/2779850/]
root        24  0.0  0.0      0     0 ?        S    Feb19   0:00 [nfsiod/2779850]
root        86  0.0  0.0  59788 12228 ?        Ss   Feb19   0:05 /lib/systemd/systemd-journald
root       109  0.0  0.0  41808   640 ?        Ss   Feb19   0:00 /lib/systemd/systemd-udevd
root       214  0.0  0.0  27668   444 ?        Ss   Feb19   0:00 /usr/sbin/cron -f
message+   215  0.0  0.0  42832   588 ?        Ss   Feb19   0:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
syslog     226  0.0  0.0 184624  1152 ?        Ssl  Feb19   0:01 /usr/sbin/rsyslogd -n
root       227  0.0  0.0  28484   596 ?        Ss   Feb19   0:00 /lib/systemd/systemd-logind
root       338  0.0  0.0  92748  1720 ?        Ss   08:47   0:00 sshd: svm [priv]
root       343  0.0  0.0  65448  1048 ?        Ss   Feb19   0:01 /usr/sbin/sshd -D
svm        350  0.0  0.0  92748  1576 ?        S    08:47   0:00 sshd: svm@pts/3
svm        351  0.0  0.0  20080  1572 pts/3    Ss   08:47   0:00 -bash
root       352  0.0  0.0  14412   144 tty1     Ss+  Feb19   0:00 /sbin/agetty --noclear --keep-baud console 115200 38400 9600 vt220
root       353  0.0  0.0  12780   152 tty2     Ss+  Feb19   0:00 /sbin/agetty --noclear tty2 linux
root       369  0.0  0.0 126068  1428 ?        Ss   Feb19   0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data   370  0.0  0.0 127276  3968 ?        S    Feb19   0:19 nginx: worker process
www-data   371  0.0  0.0 127400  4208 ?        S    Feb19   0:32 nginx: worker process
www-data   372  0.0  0.0 126708  3460 ?        S    Feb19   0:18 nginx: worker process
www-data   373  0.0  0.0 127560  4308 ?        S    Feb19   0:14 nginx: worker process
www-data   374  0.0  0.0 127060  3712 ?        S    Feb19   0:18 nginx: worker process
www-data   375  0.0  0.0 127488  4240 ?        S    Feb19   0:19 nginx: worker process
www-data   376  0.0  0.0 127280  4164 ?        S    Feb19   0:20 nginx: worker process
www-data   377  0.0  0.0 127376  4132 ?        S    Feb19   0:26 nginx: worker process
root       412  0.0  0.0  92748  1212 ?        Ss   Feb19   0:00 sshd: svm [priv]
root       532  0.0  0.0  92616  1532 ?        Ss   08:52   0:00 sshd: svm [priv]
svm        541  0.0  0.0  92748  1260 ?        S    08:52   0:00 sshd: svm@notty
svm        542  0.0  0.0  12820   316 ?        Ss   08:52   0:00 /usr/lib/openssh/sftp-server
root       564  0.0  0.0  65348   768 ?        Ss   Feb19   0:00 /usr/lib/postfix/sbin/master
postfix    570  0.0  0.0  67464   780 ?        S    Feb19   0:00 qmgr -l -t unix -u
svm       1138  0.0  0.0  44952   996 ?        Ss   Feb19   0:00 /lib/systemd/systemd --user
svm       1139  0.0  0.0  60768  1592 ?        S    Feb19   0:00 (sd-
svm       1149  0.0  0.0  92748  1424 ?        S    Feb19   0:05 sshd: svm@pts/0
svm       1150  0.0  0.0  20084  1404 pts/0    Ss   Feb19   0:00 -bash
root     12567  0.0  0.0  92748  1340 ?        Ss   Feb19   0:00 sshd: svm [priv]
svm      12576  0.0  0.0  92748  1412 ?        S    Feb19   0:01 sshd: svm@pts/1
svm      12577  0.0  0.0  20092   888 pts/1    Ss+  Feb19   0:00 -bash
root     13508  0.0  0.0  92748  1640 ?        Ss   Feb19   0:00 sshd: root@pts/2
root     13510  0.0  0.0  36504   944 ?        Ss   Feb19   0:00 /lib/systemd/systemd --user
root     13511  0.0  0.0 212328  1632 ?        S    Feb19   0:00 (sd-
root     13521  0.0  0.0  19888  1204 pts/2    Ss   Feb19   0:00 -bash
mysql    14816  2.2  9.9 7023536 1665064 ?     Ssl  11:55   6:56 /usr/sbin/mysqld
postfix  20748  0.0  0.0  67416  2532 ?        S    16:40   0:00 pickup -l -t unix -u -c
root     26860  0.0  0.0  51360  2136 pts/2    S+   16:52   0:00 sudo nano gunicorn-error.log
root     26861  0.4  1.0 196540 177104 pts/2   S+   16:52   0:04 nano gunicorn-error.log
svm      29711  0.1  0.1  86568 20644 pts/0    S+   17:06   0:00 /home/svm/Intranet/venv/bin/python3 /home/svm/Intranet/venv/bin/gunicorn intranet:app --bind 127.0.0.1:50
svm      29714  1.5  0.6 3174864 114096 pts/0  Sl+  17:06   0:02 /home/svm/Intranet/venv/bin/python3 /home/svm/Intranet/venv/bin/gunicorn intranet:app --bind 127.0.0.1:50
svm      29715  1.5  0.6 3175340 114368 pts/0  Sl+  17:06   0:02 /home/svm/Intranet/venv/bin/python3 /home/svm/Intranet/venv/bin/gunicorn intranet:app --bind 127.0.0.1:50
svm      29716  1.4  0.6 3172408 111204 pts/0  Sl+  17:06   0:02 /home/svm/Intranet/venv/bin/python3 /home/svm/Intranet/venv/bin/gunicorn intranet:app --bind 127.0.0.1:50
svm      29718  1.9  0.6 3248820 112212 pts/0  Sl+  17:06   0:02 /home/svm/Intranet/venv/bin/python3 /home/svm/Intranet/venv/bin/gunicorn intranet:app --bind 127.0.0.1:50
svm      29719  1.5  0.6 3174548 113900 pts/0  Sl+  17:06   0:02 /home/svm/Intranet/venv/bin/python3 /home/svm/Intranet/venv/bin/gunicorn intranet:app --bind 127.0.0.1:50
svm      29721  2.0  0.6 3176232 115440 pts/0  Sl+  17:06   0:02 /home/svm/Intranet/venv/bin/python3 /home/svm/Intranet/venv/bin/gunicorn intranet:app --bind 127.0.0.1:50
svm      29723  1.7  0.6 3174600 113644 pts/0  Sl+  17:06   0:02 /home/svm/Intranet/venv/bin/python3 /home/svm/Intranet/venv/bin/gunicorn intranet:app --bind 127.0.0.1:50
svm      29725  1.6  0.6 3172224 111324 pts/0  Sl+  17:06   0:02 /home/svm/Intranet/venv/bin/python3 /home/svm/Intranet/venv/bin/gunicorn intranet:app --bind 127.0.0.1:50
root     30271  0.0  0.0  65448  3224 ?        Ss   17:08   0:00 sshd: [accepted]
root     30272  0.0  0.0  65448  3444 ?        Ss   17:08   0:00 sshd: [accepted]
sshd     30273  0.0  0.0  65448  1324 ?        S    17:08   0:00 sshd: [net]
svm      30274  0.0  0.0  36024  1660 pts/3    R+   17:08   0:00 ps aux

我尝试创建交换空间。但是,我的 VPS 主机没有权限创建交换空间。

ulimit -a:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 1030918
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1030918
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

DF-H:

Filesystem         Size  Used Avail Use% Mounted on
/dev/ploop43863p1  788G   17G  740G   3% /
devtmpfs           8,0G     0  8,0G   0% /dev
tmpfs              8,0G     0  8,0G   0% /dev/shm
tmpfs              8,0G   25M  8,0G   1% /run
tmpfs              5,0M     0  5,0M   0% /run/lock
tmpfs              8,0G     0  8,0G   0% /sys/fs/cgroup
none               8,0G     0  8,0G   0% /run/shm
tmpfs              1,7G     0  1,7G   0% /run/user/1001
tmpfs              1,7G     0  1,7G   0% /run/user/0

编辑:MySQL 问题的解决方案: 我想我找到了 MySQL 错误的原因。python 应用程序对每个新的数据库请求都使用来自 sqlalchemy 的方法“create_engine”,而不是重用引擎并只打开一个新连接。然而,虽然解决了这个瓶颈,但 Gunicorn 错误: OSError: [Errno 105] No buffer space available 现在出现得更频繁了,因为应用程序不再遇到 MySQL 错误。

编辑: 显示全局变量:https://pastebin.com/LGsBQgR0

显示全局状态:https://pastebin.com/Q0pGJpwn

MysqlTuner:https://pastebin.com/U1nBVPTT

请求期间的 iostat:https://pastebin.com/yQkAib91

答案1

max_connections        = 20000

太高了。200 更现实。如果你尝试使用 20K 连接打开同时,你的系统也存在架构问题。

API 请求应该在几毫秒内就可以完成访问,从而不会堆积 20K 个实时连接。

如果你的客户端(Apache、Tomcat 等)允许 20K 线程运行,那么是一个问题。

状态/变量分析

观察结果:

  • 版本:5.7.23-0ubuntu0.16.04.1
  • 16 GB RAM
  • 正常运行时间 = 05:08:49;某些 GLOBAL STATUS 值可能尚无意义。
  • 您没有在 Windows 上运行。
  • 运行 64 位版本
  • 您似乎正在运行全部(或大部分)InnoDB。

更重要的问题:

很多SHOW命令——发生了什么事?

许多查询使用内部临时表或进行全表扫描。降低long_query_time并打开 slowlog 以查看最糟糕的情况。

详细信息和其他观察结果:

( innodb_buffer_pool_size / _ram ) = 2048M / 16384M = 12.5%-- 用于 InnoDB 缓冲池的 RAM 百分比

( (key_buffer_size / 0.20 + innodb_buffer_pool_size / 0.70) / _ram ) = (16M / 0.20 + 2048M / 0.70) / 16384M = 18.3%-- 大多数可用 RAM 应用于缓存。--http://mysql.rjweb.org/doc.php/memory

( Innodb_buffer_pool_pages_free / Innodb_buffer_pool_pages_total ) = 67,332 / 131056 = 51.4%-- 缓冲池的百分比当前未使用 -- innodb_buffer_pool_size 是否大于必要的?

( Uptime / 60 * innodb_log_file_size / Innodb_os_log_written ) = 18,529 / 60 * 256M / 122842112 = 674-- InnoDB 日志轮换之间的分钟数从 5.6.8 开始,可以动态更改;请确保也更改 my.cnf。--(轮换之间建议 60 分钟有点武断。)调整 innodb_log_file_size。(无法在 AWS 中更改。)

( innodb_flush_method ) = innodb_flush_method =-- InnoDB 应如何要求操作系统写入块。建议使用 O_DIRECT 或 O_ALL_DIRECT (Percona) 来避免双重缓冲。(至少对于 Unix 而言。)有关 O_ALL_DIRECT 的注意事项,请参阅 chrischandler

( Com_rollback ) = 65,020 / 18529 = 3.5 /sec-- InnoDB 中的回滚。-- 回滚频率过高可能表明应用程序逻辑效率低下。

( Handler_rollback ) = 35,725 / 18529 = 1.9 /sec ——为什么会有这么多的回滚?

( Innodb_rows_deleted / Innodb_rows_inserted ) = 250,597 / 306605 = 0.817-- 流失 -- “不要排队,直接执行。”(如果 MySQL 被用作队列。)

( innodb_flush_neighbors ) = 1-- 将块写入磁盘时进行小幅优化。-- 对于 SSD 驱动器使用 0;对于 HDD 使用 1。

( innodb_io_capacity ) = 200-- 磁盘每秒的 I/O 操作数。慢速驱动器为 100;旋转驱动器为 200;SSD 为 1000-2000;乘以 RAID 因子。

( innodb_print_all_deadlocks ) = innodb_print_all_deadlocks = OFF-- 是否记录所有死锁。-- 如果您受到死锁的困扰,请启用此功能。注意:如果您有大量死锁,这可能会将大量数据写入磁盘。

( (Com_show_create_table + Com_show_fields) / Questions ) = (1 + 19522) / 140291 = 13.9%-- 不合理的框架 -- 花费大量精力重新发现模式。-- 向第三方供应商投诉。

( local_infile ) = local_infile = ON -- local_infile = ON 存在潜在的安全问题

( (Queries-Questions)/Queries ) = (24488180-140291)/24488180 = 99.4%-- 存储例程内的查询比例。--(如果很高的话还不错;但它会影响其他一些结论的有效性。)

( Created_tmp_disk_tables ) = 19,628 / 18529 = 1.1 /sec-- 创建频率磁盘“临时”表作为复杂 SELECT 的一部分 - 增加 tmp_table_size 和 max_heap_table_size。检查临时表的规则,了解何时使用 MEMORY 而不是 MyISAM。也许较小的架构或查询更改可以避免使用 MyISAM。更好的索引和查询的重新表述更有可能有所帮助。

( Created_tmp_disk_tables / Questions ) = 19,628 / 140291 = 14.0%-- 需要磁盘临时表的查询的百分比。-- 更好的索引/没有 blob/等等。

( Created_tmp_disk_tables / Created_tmp_tables ) = 19,628 / 22476 = 87.3%-- 溢出到磁盘的临时表的百分比 -- 可能增加 tmp_table_size 和 max_heap_table_size;改进索引;避免 blob 等。

( Com_rollback / Com_commit ) = 65,020 / 765 = 8499.3%-- 回滚:提交率 -- 回滚成本高昂;更改应用程序逻辑

( (Com_insert + Com_update + Com_delete + Com_replace) / Com_commit ) = (669 + 24 + 164 + 1) / 765 = 1.12-- 每次提交的语句数(假设所有都是 InnoDB)-- 低:可能有助于将查询分组到事务中;高:长事务会给各种事物带来压力。

( Select_scan ) = 25,262 / 18529 = 1.4 /sec-- 全表扫描 -- 添加索引/优化查询(除非它们是小表)

( Select_scan / Com_select ) = 25,262 / 38182 = 66.2%-- 执行全表扫描的选择百分比。(可能会被存储例程欺骗。)-- 添加索引/优化查询

( innodb_autoinc_lock_mode ) = 1-- Galera:愿望 2 -- 2 = “交错”;1 = “连续”是典型的;0 = “传统”。

( slow_query_log ) = slow_query_log = OFF-- 是否记录慢速查询。(5.1.12)

( long_query_time ) = 10-- 定义“慢速”查询的截止时间(秒)。-- 建议 2

( Aborted_clients / Connections ) = 1,010 / 1457 = 69.3%-- 由于超时导致线程中断 -- 增加 wait_timeout;最好使用 disconnect

( thread_cache_size ) = 500-- 需要保留多少个额外进程(使用线程池时不相关)(从 5.6.8 开始自动调整大小;基于 max_connections)

( thread_cache_size / max_connections ) = 500 / 500 = 100.0%

( thread_cache_size / Max_used_connections ) = 500 / 136 = 367.6% -- 线程缓存大于可能的连接数没有任何好处。浪费空间才是缺点。

异常大:

Com_kill = 0.39 /HR
Com_show_charsets = 0.39 /HR
Com_show_fields = 1.1 /sec
Com_show_slave_hosts = 0.39 /HR
Com_show_storage_engines = 0.78 /HR
Com_show_warnings = 38 /HR
Handler_read_next / Handler_read_key = 5,206
Innodb_dblwr_pages_written / Innodb_dblwr_writes = 62.7
Performance_schema_file_instances_lost = 1
gtid_executed_compression_period = 0.054 /sec
wait_timeout = 1.0e+6

异常字符串:

ft_boolean_syntax = + -><()~*:&
innodb_fast_shutdown = 1
optimizer_trace = enabled=off,one_line=off
optimizer_trace_features = greedy_search=on, range_optimizer=on, dynamic_range=on, repeated_subselect=on
session_track_system_variables = time_zone, autocommit, character_set_client, character_set_results, character_set_connection
slave_rows_search_algorithms = TABLE_SCAN,INDEX_SCAN

答案2

每秒速率 = RPS - 针对 my.cnf [mysqld] 部分的建议

read_rnd_buffer_size=256K  # from 1M to reduce handler_read_rnd_next RPS of 4,950
innodb_io_capacity=1500  # from 200 to enable higher IOPS
tmp_table_size=64M  # from 32M for additional capacity
max_heap_table_size=64M  # from 32M to reduce created_tmp_disk_tables
innodb_lru_scan_depth=100  # from 1024 to reduce CPU cycles used every SECOND

我们需要讨论 65,000 多个 com_rollback 事件的原因、错误日志内容等。

答案3

发现以下内容解决了上述错误消息的问题。 https://www.programmersought.com/article/67991070331/

问候,伊恩

相关内容