救命!我的服务器内存不足并锁定,需要硬重启

救命!我的服务器内存不足并锁定,需要硬重启

我有一个 VPS(256MB 内存),今天挂了不止一次。它完全冻结了,无法通过 SSH 访问。我不得不运行提供商的“强制关机”程序来恢复。然后服务器持续了几个小时,然后又挂了。

第一次出现一条消息,提示内存不足并试图终止 mysqld 进程。下一次我设法在 syslog 文件中找到了这条消息:

Sep 23 01:47:34: [16942.757665]  [out_of_memory+0x19e/0x1e0] out_of_memory+0x19e/0x1e0
Sep 23 01:47:34: [16942.758875] Out of memory: kill process 5983 (apache2) score 57519 or a child

我已经将 Apache 和 MySQL 配置为相当注意低 RAM,至少据我所知,我想知道为什么会发生这种情况。我是否只需要升级,还是出了什么问题?

以下是我的 Apache 配置的摘录:

#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 30

#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On

#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 200

#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 3

##
## Server-Pool Size Regulation (MPM specific)
## 

# prefork MPM
# StartServers: number of server processes to start
# MinSpareServers: minimum number of server processes which are kept spare
# MaxSpareServers: maximum number of server processes which are kept spare
# MaxClients: maximum number of server processes allowed to start
# MaxRequestsPerChild: maximum number of requests a server process serves
<IfModule mpm_prefork_module>
    StartServers          1
    MinSpareServers       1
    MaxSpareServers      3
    MaxClients          50
    MaxRequestsPerChild   1000
</IfModule>

我的 MySQL 配置如下:

[mysqld]
#
# * Basic Settings
#

#
# * IMPORTANT
#   If you make changes to these settings and your system uses apparmor, you may
#   also need to also adjust /etc/apparmor.d/usr.sbin.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
language    = /usr/share/mysql/english
skip-external-locking
skip-locking
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address        = 127.0.0.1
#
# * Fine Tuning
#
key_buffer      = 16K
max_allowed_packet  = 1M
thread_stack        = 64K
thread_cache_size   = 4
sort_buffer     = 64K
net_buffer_length   = 2K
#max_connections        = 100
#table_cache            = 64
#thread_concurrency     = 10
#
# * Query Cache Configuration
#
query_cache_limit       = 500k #was 1M
query_cache_size        = 8M #was 16M, lowered for RAM
#
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
# Be aware that this log type is a performance killer.
#log        = /var/log/mysql/mysql.log
#
# Error logging goes to syslog. This is a Debian improvement :)
#
# Here you can see queries with especially long duration
#log_slow_queries   = /var/log/mysql/mysql-slow.log
#long_query_time = 2
#log-queries-not-using-indexes
#
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
#       other settings you may need to change.
#server-id      = 1
#log_bin            = /var/log/mysql/mysql-bin.log
expire_logs_days    = 10
max_binlog_size         = 100M
#binlog_do_db       = include_database_name
#binlog_ignore_db   = include_database_name
#
# * BerkeleyDB
#
# Using BerkeleyDB is now discouraged as its support will cease in 5.1.12.
skip-bdb
#
# * InnoDB
#
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
# Read the manual for more InnoDB related options. There are many!
# You might want to disable InnoDB to shrink the mysqld process by circa 100MB.
skip-innodb
#
# * Security Features
#
# Read the manual, too, if you want chroot!
# chroot = /var/lib/mysql/
#
# For generating SSL certificates I recommend the OpenSSL GUI "tinyca".
#
# ssl-ca=/etc/mysql/cacert.pem
# ssl-cert=/etc/mysql/server-cert.pem
# ssl-key=/etc/mysql/server-key.pem



[mysqldump]
quick
quote-names
max_allowed_packet  = 16M

[mysql]
#no-auto-rehash # faster start of mysql but no tab completition

[isamchk]
key_buffer      = 16M

如果有帮助的话,以下是ps aux重启后大约 20-30 分钟的输出:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3   3992   920 ?        Ss   01:53   0:00 /sbin/init
root         2  0.0  0.0      0     0 ?        S<   01:53   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S<   01:53   0:00 [migration/0]
root         4  0.0  0.0      0     0 ?        S<   01:53   0:00 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S<   01:53   0:00 [watchdog/0]
root         6  0.0  0.0      0     0 ?        S<   01:53   0:00 [events/0]
root         7  0.0  0.0      0     0 ?        S<   01:53   0:00 [khelper]
root        18  0.0  0.0      0     0 ?        S<   01:53   0:00 [xenwatch]
root        19  0.0  0.0      0     0 ?        S<   01:53   0:00 [xenbus]
root        27  0.0  0.0      0     0 ?        S<   01:53   0:00 [migration/1]
root        28  0.0  0.0      0     0 ?        S<   01:53   0:00 [ksoftirqd/1]
root        29  0.0  0.0      0     0 ?        S<   01:53   0:00 [watchdog/1]
root        30  0.0  0.0      0     0 ?        S<   01:53   0:00 [events/1]
root        54  0.0  0.0      0     0 ?        S<   01:53   0:00 [kblockd/0]
root        55  0.0  0.0      0     0 ?        S<   01:53   0:00 [kblockd/1]
root        65  0.0  0.0      0     0 ?        S<   01:53   0:00 [kseriod]
root       104  0.0  0.0      0     0 ?        S    01:53   0:00 [pdflush]
root       105  0.0  0.0      0     0 ?        S    01:53   0:00 [pdflush]
root       106  0.0  0.0      0     0 ?        S<   01:53   0:00 [kswapd0]
root       107  0.0  0.0      0     0 ?        S<   01:53   0:00 [aio/0]
root       108  0.0  0.0      0     0 ?        S<   01:53   0:00 [aio/1]
root       124  0.0  0.0      0     0 ?        S<   01:53   0:00 [accel_watch/0]
root       125  0.0  0.0      0     0 ?        S<   01:53   0:00 [accel_watch/1]
root      2031  0.0  0.0      0     0 ?        S<   01:53   0:00 [kjournald]
root      2192  0.0  0.3  16848   944 ?        S<s  01:53   0:00 /sbin/udevd --daemon
syslog    3514  0.0  0.2  12296   728 ?        Ss   01:53   0:00 /sbin/syslogd -u syslog
root      3534  0.0  0.2   8132   592 ?        S    01:53   0:00 /bin/dd bs 1 if /proc/kmsg of /var/run/klogd/kmsg
klog      3537  0.0  0.8   5600  2292 ?        Ss   01:53   0:00 /sbin/klogd -P /var/run/klogd/kmsg
root      3556  0.0  0.4  50916  1160 ?        Ss   01:53   0:00 /usr/sbin/sshd
root      3776  0.0  0.8  36684  2152 ?        Ss   01:53   0:00 /usr/lib/postfix/master
postfix   3794  0.0  0.8  38740  2140 ?        S    01:53   0:00 pickup -l -t fifo -u -c
postfix   3795  0.0  0.8  38784  2228 ?        S    01:53   0:00 qmgr -l -t fifo -u
root      3802  0.0  0.2  12460   644 ?        Ss   01:53   0:00 /usr/sbin/dovecot
root      3815  0.0  1.0  71648  2876 ?        S    01:53   0:00 dovecot-auth
daemon    3816  0.0  0.1  16428   428 ?        Ss   01:53   0:00 /usr/sbin/atd
root      3829  0.0  0.3  18616   976 ?        Ss   01:53   0:00 /usr/sbin/cron
dovecot   3851  0.0  0.7  14148  1876 ?        S    01:53   0:00 imap-login
dovecot   3852  0.0  0.7  14148  1876 ?        S    01:53   0:00 imap-login
dovecot   3853  0.0  0.7  14148  1876 ?        S    01:53   0:00 imap-login
root      3875  0.0  0.2   3864   592 tty1     Ss+  01:53   0:00 /sbin/getty 38400 tty1
root      3913  0.0  1.1  68272  3116 ?        Ss   01:54   0:00 sshd: root@pts/0 
postfix   3917  0.0  1.1  41248  2964 ?        S    01:54   0:00 tlsmgr -l -t unix -u -c
root      3924  0.0  0.7  18908  2080 pts/0    Ss   01:54   0:00 -bash
root      3958  0.0  0.2   3864   592 ?        Ss   01:55   0:00 /sbin/getty 38400 console
root      4232  0.0  0.2   3944   608 pts/0    S    02:22   0:00 /bin/sh /usr/bin/mysqld_safe
mysql     4271  0.1  5.0 124404 13244 pts/0    Sl   02:22   0:02 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --pi
root      4272  0.0  0.2   5068   768 pts/0    S    02:22   0:00 logger -p daemon.err -t mysqld_safe -i -t mysqld
root      4415  0.0  3.6 201880  9516 ?        Ss   02:29   0:00 /usr/sbin/apache2 -k start
www-data  4527  0.5 11.9 225720 31340 ?        S    02:47   0:01 /usr/sbin/apache2 -k start
www-data  4539  0.6 12.2 226492 32092 ?        S    02:50   0:00 /usr/sbin/apache2 -k start
www-data  4541  2.3 12.1 226492 31992 ?        S    02:52   0:00 /usr/sbin/apache2 -k start
root      4544  0.0  0.4  15064  1088 pts/0    R+   02:53   0:00 ps aux

有人可以帮我从这里出去吗?

答案1

你确实需要精简你的服务。更好的是,您可能需要考虑使用 inetd 或 xinetd(无论哪种情况适用于您的安装)。与其让多个服务启动并等待(并占用宝贵的 RAM),不如在需要时启动服务,从而降低 CPU 性能。这就是 inetd/xinetd 的真正目的 - 它们旨在提供一种低内存方式,允许服务按需启动,而不是让它们一直挂起。当然,您的里程可能会非常长 - 您仍然可能会遇到内存资源问题 - 但如果它暂时让您渡过难关......

跟进从哪里开始(来自评论):

我会首先考虑将 Apache 迁移过来。将最大子进程数减少到 2 - 除非您要服务的用户比您自己还多,否则运行 3 个进程没什么用。

对于 dovecot,特别是 imap-auth 进程,您只需要一个。您也可以在 inetd 中运行它,尽管它看起来相当薄。如果您在服务器上不使用 IMAP 或 POP,请将其关闭。最糟糕的情况是,您又回到了在命令行中阅读邮件 - 虽然不漂亮,但功能齐全。

您也可以移动 sshd,尽管我最初会在另一个端口号上执行此操作,并在切换该端口的开关之前确认它已连接。

如果可能的话,考虑迁移到 Exim(这是 Debian/Ubuntu 设置的默认安装)。我喜欢 Postfix,我不使用 Exim,但 Debian 选择它作为默认安装是有原因的 - 它只需要很少的资源并且相当安全。

查看 /proc/sys/vm/swappiness 设置 ( echo /proc/sys/vm/swappiness) 并确定它是太高还是太低。较高的数字将有助于释放内存(通过提前交换到 VM),但是当它太高时,您会疯狂地交换。大多数安装都说“60”,但对于低内存,它应该更像是 85。我不建议您在设置中使用 100。

最后,想想“绿屏”。你谈论的是使用在更老的系统上已经存在很长时间的技术(因为它们也受到资源限制)。这样做有点过时,但如果你可以在 shell 中的客户端程序中完成工作,而不是启动服务,那么你将进一步扩展你的计算资源。

答案2

留意正在运行的 httpd 进程的数量以及它们使用的内存量。我认为您的 Web 服务器正在交换,可能是因为 MaxClients 指令超过了服务器的最佳值。您需要计算每个 apache 进程所需的平均 RAM(根据 ps 的结果,大约为 30M),并将 MaxClients 的值设置为不超过总可用 RAM 的值,并为其他进程(如 MySQL)提供足够的空间。

答案3

如果在服务器开始变慢时输入命令“free”,您将看到内存使用情况,我敢打赌,正如 HD 所说,您的服务器正在耗尽交换空间。根据您的 PS 输出,您那里几乎有 256M。

您可能希望将 MaxSpareServers 降至 2 甚至 1。此外,Apache 还有其他替代方案,例如lighttpd它应该是轻量级的并且占用更少的内存。

我有个人观点,而且我确信有些人会不同意,那就是服务器的 RAM 不应该少于 512M 或 1G。

答案4

在 256 MB VPS 上运行 Apache、MySQL 和 PHP 是一场势均力敌的较量。256 MB RAM 对于运行这些服务来说并不算多,相反,它非常非常少。首先要考虑的是不购买更好的 VPS 是否是一种选择。

那么,如果获取更好的 VPS 不是一个选择,那么一个严肃的建议是:彻底放弃 Apache!

如今,Apache 已经成为了相当占用内存的操作系统,而且由于没有大量的空闲内存,Apache 真的应该走了。

选择 Nginx,它也非常强大,但是需要的资源却少得多!

当然,如果使用 PHP,您需要结合 Nginx 安装 PHP-FPM,然后需要正确配置您的池。

您可能还想微调 MySQL 中的各种缓存,这意味着可能减少它们的大小!

相关内容