问题:我最近修改了一台服务器,在使用之前进行了testing,并且运行良好,但是几天前,我注意到通常写入根卷的数量大约是4倍。 这不是一个性能问题 – 服务器运行良好。
我的改造是相当广泛的(全面重build),所以我没有太多的理由。 简而言之,我的变化包括:
基本设置:
free和iostat显示最小交换使用率)。 mount --bind )。底层EBS卷挂载在/mnt/data 新的设置运行比旧系统“更平滑”(更快,更less的内存等),并且已经稳定了20天(10月中旬) – 据我所知,高位写入一直存在。
与我所期望的相反,我的读取量很低(我的读取量大约是我写入的1.5%,无论是在根卷上的块还是字节上)。 在过去几天里,我并没有改变根卷上的任何东西(例如新的安装等),但是写入量仍然远高于预期。
目标:确定增加写入到根卷的原因(主要是弄清楚它是一个进程(和哪个进程),不同的(ext4)文件系统或另一个问题(例如内存))。
系统信息:
根目录和数据卷每天被快照 – 但是,这应该是一个“读”操作,而不是写操作。 (另外,在以前的服务器上也使用了相同的做法,而以前的服务器也是t1.micro。)
导致我查看I / O的数据是在我最后一个AWS账单的细节中(它超出了正常的I / O – 这并不意外,因为我正在设置这个服务器,并且在开始时安装了很多东西),随后在所附EBS卷的CloudWatch指标上。 我通过从11月份(当我没有更改服务器时)推断I / O活动来估计每月的价值,并将其与过去几个月我不工作时的I / O进行比较,来到“4倍正常”在我以前的服务器上。 (我没有从我以前的服务器确切的iostat数据)。 同样数量的写入一直持续到11月,170-330MB /小时。
诊断信息 (以下输出的正常运行时间为20.6天):
Cloudwatch指标:
输出: df -h (仅限根卷)
Filesystem Size Used Avail Use% Mounted on /dev/xvda1 4.0G 1.2G 2.8G 31% /
使用的空间并没有明显增加,因为这个系统已经启动了(对我来说,build议文件正在更新,而不是创build/附加)。
输出: iostat -x (joinBlk_read , Blk_wrtn ):
Linux 2.6.35.14-95.38.amzn1.i686 11/05/2011 _i686_ Device: rrqm/s wrqm/sr/sw/s rsec/s wsec/s Blk_read Blk_wrtn avgrq-sz avgqu-sz await svctm %util xvdap1 0.00 3.42 0.03 2.85 0.72 50.19 2534636 177222312 17.68 0.18 60.93 0.77 0.22 xvdf 0.00 0.03 0.04 0.35 1.09 8.48 3853710 29942167 24.55 0.01 24.28 2.95 0.12 xvdg 0.00 0.00 0.00 0.00 0.02 0.04 70808 138160 31.09 0.00 48.98 4.45 0.00
输出: iotop -d 600 -a -o -b
Total DISK READ: 6.55 K/s | Total DISK WRITE: 117.07 K/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO COMMAND 852 be/4 root 0.00 B 26.04 M 0.00 % 0.42 % [flush-202:1] 539 be/3 root 0.00 B 528.00 K 0.00 % 0.08 % [jbd2/xvda1-8] 24881 be/4 nginx 56.00 K 120.00 K 0.00 % 0.01 % nginx: worker process 19754 be/4 mysql 180.00 K 24.00 K 0.00 % 0.01 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 3106 be/4 mysql 0.00 B 176.00 K 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 19751 be/4 mysql 4.00 K 0.00 B 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 3194 be/4 mysql 8.00 K 40.00 K 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 3156 be/4 mysql 4.00 K 12.00 K 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 3099 be/4 mysql 0.00 B 4.00 K 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 24216 be/4 web14 8.00 K 10.43 M 0.00 % 0.00 % php-fpm: pool web14 24465 be/4 web19 0.00 B 7.08 M 0.00 % 0.00 % php-fpm: pool web19 3110 be/4 mysql 0.00 B 100.00 K 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 579 be/4 varnish 0.00 B 76.00 K 0.00 % 0.00 % varnishd -P /var/run/varnish.pid -a :80 -f /etc/varnish/default.vcl -T 127.0.0.1:6082 -t 3600 -w 1,1000,120 -u varnish -g varnish 582 be/4 varnish 0.00 B 144.00 K 0.00 % 0.00 % varnishd -P /var/run/varnish.pid -a :80 -f /etc/varnish/default.vcl -T 127.0.0.1:6082 -t 3600 -w 1,1000,120 -u varnish -g varnish 586 be/4 varnish 0.00 B 4.00 K 0.00 % 0.00 % varnishd -P /var/run/varnish.pid -a :80 -f /etc/varnish/default.vcl -T 127.0.0.1:6082 -t 3600 -w 1,1000,120 -u varnish -g varnish 587 be/4 varnish 0.00 B 40.00 K 0.00 % 0.00 % varnishd -P /var/run/varnish.pid -a :80 -f /etc/varnish/default.vcl -T 127.0.0.1:6082 -t 3600 -w 1,1000,120 -u varnish -g varnish 1648 be/4 nobody 0.00 B 8.00 K 0.00 % 0.00 % in.imapproxyd 18072 be/4 varnish 128.00 K 128.00 K 0.00 % 0.00 % varnishd -P /var/run/varnish.pid -a :80 -f /etc/varnish/default.vcl -T 127.0.0.1:6082 -t 3600 -w 1,1000,120 -u varnish -g varnish 3101 be/4 mysql 0.00 B 176.00 K 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 19749 be/4 mysql 0.00 B 32.00 K 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 19750 be/4 mysql 0.00 B 0.00 B 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 19752 be/4 mysql 0.00 B 108.00 K 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 19788 be/4 mysql 0.00 B 12.00 K 0.00 % 0.00 % mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock 853 be/4 root 4.00 K 0.00 B 0.00 % 0.00 % [flush-202:80] 22011 be/4 varnish 0.00 B 188.00 K 0.00 % 0.00 % varnishd -P /var/run/varnish.pid -a :80 -f /etc/varnish/default.vcl -T 127.0.0.1:6082 -t 3600 -w 1,1000,120 -u varnish -g varnish
总结上述(并推断为每日价值)在10分钟内看起来像:
有趣的是,在[flush-202]和php-fpm之间可能会出现每日写入量。
使用ftop ,我无法追查flush或php-fpm写入(例如ftop -p php-fpm 。
我的问题至less有一部分来自于识别哪些进程正在写入根卷。 在上面列出的那些中,我希望所有的都是写入数据卷(因为相关的目录在那里是符号链接的)(例如, nginx , mysql , php-fpm , varnish目录都指向不同的EBS卷)
我相信JBD2是ext4的日志块设备, flush-202是脏页面的后台刷新。 dirty_ratio是20, dirty_background_ratio是10.脏的内存(来自/proc/meminfo )通常在50-150kB之间)。 页面大小( getconf PAGESIZE )是系统默认值(4096)。
输出: vmstat -s | grep paged vmstat -s | grep paged
3248858页在104625313页分页
输出: sar -B | grep Average sar -B | grep Average
pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff Average: 1.38 39.57 113.79 0.03 36.03 0.38 0.02 0.29 73.66
上述似乎build议大量的页面 – 但是,我希望页面将写入我的交换分区,如果有必要,而不是我的根卷。 在总内存中,系统通常有35%使用率,10%缓冲区,40%caching,15%未使用(即65%免费)。
输出: vmstat -d
disk- ------------reads------------ ------------writes----------- -----IO------ total merged sectors ms total merged sectors ms cur sec xvda1 105376 14592 2548092 824418 10193989 12264020 179666824 626582671 0 7872 xvdf 126457 579 3882950 871785 1260822 91395 30081792 32634413 0 4101 xvdg 4827 4048 71000 21358 1897 15373 138160 307865 0 29
vmstat始终显示si , so值为0
输出: swapon -s
Filename Type Size Used Priority /dev/xvdg partition 1048572 9252 -1
在I / O写入的预感可能是内存相关的,我禁用清漆,并重新启动服务器。 这改变了我的记忆configuration文件在使用10%,缓冲区2%,20%caching,68%未使用(即90%免费)。 然而,超过10分钟的运行时间,iotop的结果与之前一样:
在重启后的一小时内,已经有330MB的数据被写入根卷,并且有370K页被换出。
inputinotifywatch -v -e modify -t 600 -r /[^mnt]*
Establishing watches... Setting up watch(es) on /bin /boot /cgroup /dev /etc/ home /lib /local /lost+found /opt /proc /root /sbin /selinux /src /sys /usr /var OK, /bin /boot /cgroup /dev /etc/ home /lib /local /lost+found /opt /proc /root /sbin /selinux /src /sys /usr /var is now being watched. Total of 6753 watches. Finished establishing watches, now collecting statistics. Will listen for events for 600 seconds. total modify filename 23 23 /var/log/ 20 20 /usr/local/ispconfig/server/temp/ 18 18 /dev/ 15 15 /var/log/sa/ 11 11 /var/spool/postfix/public/ 5 5 /var/log/nginx/ 2 2 /var/run/pure-ftpd/ 1 1 /dev/pts/
chkservd ,几乎所有的写操作都可以归结为每5分钟运行一个(未知)进程,并检查各种服务的状态(如cPanel上的chkservd ,但是我不使用cPanel ,并没有安装这个)。 它相当于在10分钟内更新的4个日志文件(cron,maillog,ftp,imapproxy) – 以及一些相关的项目(postfix sockets,pure-ftpd连接)。 其他项目主要是修改ispconfig会话,系统记帐更新和无效(不存在的server_name)Web访问尝试(logging到/ var / log / nginx)。
结论和问题:
让我开始说我有点困惑 – 我通常相当彻底,但我觉得我失去了这个明显的东西。 很明显, flush和php-fpm占了大部分的写入,但是,我不知道为什么会这样。 首先,我们来看看php-fpm–它甚至不应该写入根卷。 它的目录(文件和日志)被连接到另一个EBS卷。 其次,php-fpm应该编写的主要内容是会话和页面caching – 这些都是less数和小的 – 当然不是1MB /分钟的数量级(更多的是1K /分钟,如果是这样的话)。 大多数网站是只读的,只是偶尔更新。 在最后一天修改的所有网页文件的总大小是2.6MB。
其次,考虑到刷新 – 从它的重要写道暗示脏页面经常被刷新到磁盘 – 但鉴于我通常有65%的空闲内存和交换空间单独的EBS卷,我不能解释为什么这会影响我的根卷上的写入,尤其是发生的程度。 我意识到有些进程会把脏页面写到他们自己的交换空间(而不是使用系统交换空间),但是当然,在我的绝大多数内存是空闲的情况下,立即重启后,我不应该遇到大量的脏页面。 如果您确实相信这是原因,请告诉我如何确定哪些进程正在写入自己的交换空间。
整个脏页面的想法完全可能只是一个红鲱鱼,而且完全与我的问题无关(我希望它实际上)。 如果是这样的话,我唯一的想法就是ext4日志中没有ext3的内容。 除此之外,我目前没有想法。
更新):
2011年11月6日:
设置dirty_ratio = 10和dirty_background_ratio = 5 ; 用sysctl -p更新(通过/ proc确认); reran 10分钟iotoptesting有类似的结果(flush写了17MB,php-fpm写了16MB,MySQL写了1MB,而JBD2写了0.7MB)。
我改变了所有我设置使用mount --bind的符号链接。 重新启用清漆,重新启动服务器; reran 10分钟iotoptesting有类似的结果(flush写了12.5MB,php-fpm写了11.5MB,Varnish写了0.5MB,JBD2写了0.5MB,而MySQL写了0.3MB)。
在上面的运行中,我的内存configuration文件占用了20%,缓冲区占用了2%,caching占用了58%,未使用占用了20%(即免费占用了80%)。为了防止在这种情况下我对空闲内存的解释存在缺陷,这里是free -m的输出(这是一个t1.micro)。 被caching的总使用空闲共享缓冲区Mem:602 478 124 0 14 347 – / + buffers / cache:116 486 Swap:1023 0 1023
一些额外的信息:输出: dmesg | grep EXT4 dmesg | grep EXT4
[ 0.517070] EXT4-fs (xvda1): mounted filesystem with ordered data mode. Opts: (null) [ 0.531043] EXT4-fs (xvda1): mounted filesystem with ordered data mode. Opts: (null) [ 2.469810] EXT4-fs (xvda1): re-mounted. Opts: (null)
我也同时运行ftop和iotop,并且惊讶地注意到在iotop中出现的条目没有出现在ftop中。 ftop列表被过滤到php-fpm,因为我可以相当可靠地触发写入该进程。 我注意到php-fpm每页大概写了2MB,而且我还没有弄清楚它可能写的是什么 – 关于确定写什么的任何想法都将不胜感激。
我会尽量在接下来的几天closures日志,看看是否改善了事情。 现在,我发现自己想知道是否有I / O问题或内存问题(或两者兼而有之) – 但是我很难看到内存问题,如果有的话。
2011年11月13日:
由于文件系统使用扩展盘区,因此不可能将其挂载为ext3,此外,尝试将其挂载为只读,只是导致将其重新挂载为读写。
文件系统确实启用了日志function(128MB日志),如下所示:
输出: tune2fs -l /dev/sda1 | grep features tune2fs -l /dev/sda1 | grep features
has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
根据以下内容,大约140GB已经写入到这个卷中,不到一个月的时间 – 大概是每天5GB。
输出: dumpe2fs -h /dev/sda1
Filesystem volume name: / Last mounted on: / Filesystem UUID: af5a3469-6c36-4491-87b1-xxxxxxxxxxxx Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize Filesystem flags: signed_directory_hash Default mount options: (none) Filesystem state: clean Errors behavior: Continue Filesystem OS type: Linux Inode count: 262144 Block count: 1048576 Reserved block count: 10478 Free blocks: 734563 Free inodes: 210677 First block: 0 Block size: 4096 Fragment size: 4096 Reserved GDT blocks: 511 Blocks per group: 32768 Fragments per group: 32768 Inodes per group: 8192 Inode blocks per group: 512 RAID stride: 32582 Flex block group size: 16 Filesystem created: Wed Sep 21 21:28:43 2011 Last mount time: Sun Nov 13 16:10:11 2011 Last write time: Sun Oct 16 16:12:35 2011 Mount count: 13 Maximum mount count: 28 Last checked: Mon Oct 10 03:04:13 2011 Check interval: 0 (<none>) Lifetime writes: 139 GB Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 256 Required extra isize: 28 Desired extra isize: 28 Journal inode: 8 First orphan inode: 18610 Default directory hash: half_md4 Directory Hash Seed: 6c36b2cc-b230-45e2-847e-xxxxxxxxxxx Journal backup: inode blocks Journal features: journal_incompat_revoke Journal size: 128M Journal length: 32768 Journal sequence: 0x0002d91c Journal start: 1
继续查找打开的文件,我尝试在根卷上使用fuser :
输出: fuser -vm / 2>&1 | awk '$3 ~ /f|F/' fuser -vm / 2>&1 | awk '$3 ~ /f|F/'
root 1111 Frce. dhclient root 1322 frce. mysqld_safe mysql 1486 Fr.e. mysqld root 1508 Frce. dovecot root 1589 Frce. master postfix 1600 Frce. qmgr root 1616 Frce. crond root 1626 Frce. atd nobody 1648 Frce. in.imapproxyd postfix 1935 Frce. tlsmgr root 2808 Frce. varnishncsa root 25818 frce. sudo root 26346 Fr.e. varnishd postfix 26925 Frce. pickup postfix 28057 Frce. smtpd postfix 28070 Frce. showq
没什么意外的,不幸的 由于底层硬件的原因,我恢复了昨天的根卷快照(在最后一天没有任何变化),并将实例的根卷replace为新卷。 如预期的那样,这对问题没有影响。
我的下一个步骤就是删除日志,然而我在find这个解决scheme之前偶然发现了这个解决scheme。
问题在于APC使用文件支持的mmap。 修复这个下降的磁盘I / O大约35倍 – (估计)150MB /天(而不是5GB)。 我可能仍然会考虑删除日志,因为这似乎是这个价值的主要贡献者,但是这个数字暂时是可以接受的。 达到APC结论所采取的步骤在下面的答案中公布。
由于主要原因似乎是日记,这将是我的下一步。 但是,为了删除日志logging,我需要将EBS卷附加到另一个实例。 我决定使用(一天的)快照testing过程,但是,在删除日志之前,我重新运行了10分钟的iotoptesting(在testing实例上)。 令我惊讶的是,我看到了正常(即非boost)的价值,这是第一次, flush-202甚至没有出现在名单上。 这是一个function齐全的实例(我还恢复了我的数据的快照) – 在12小时内,根卷没有被修改。 所有的testing都显示在两台服务器上都运行相同的进程。 这使我相信,这个原因必须归结为“活”服务器正在处理的一些请求。
看看显示问题的服务器的iotop输出和看起来没有问题的服务器之间的差异,唯一的区别是flush-202和php-fpm 。 这让我想到,虽然很长一段时间,也许这是一个有关PHPconfiguration的问题。
现在,这个部分并不理想 – 但是由于现场服务器上运行的所有服务都不会遭受几分钟的停机时间,所以并不重要。 为了缩小问题,在服务器上的所有主要服务(postfix,dovecot,imapproxy,nginx,php-fpm,varnish,mysqld,varnishncsa)都停止了,并且iotoptesting重新运行 – 没有提升的磁盘I / O 。 服务分三批重新启动,留下php-fpm直到结束。 每批次重新启动后,iotoptesting证实没有问题。 一旦php-fpm开始,问题返回。 (在testing服务器上模拟一些PHP请求会很容易,但是在这一点上,我不确定它实际上是PHP)。
不幸的是,如果没有PHP,服务器将是毫无意义的,所以这不是一个理想的结论。 然而,由于flush-202似乎暗示了一些与内存相关的东西(尽pipe有足够的空闲内存),我决定禁用APC。 重新运行iotoptesting显示磁盘I / O级别是正常的。 仔细观察一下问题,发现mmap已经启用, apc.mmap_file_mask被设置为/tmp/apc.XXXXXX (这个安装的默认设置)。 该path将APC设置为使用文件支持的mmap。 简单地评论这条线(因此使用默认的匿名内存支持)并重新运行iotoptesting显示问题已经解决。
我仍然不知道为什么没有诊断程序运行没有识别写入来自php和去/ tmp目录中的apc文件。 甚至提到/ tmp目录的唯一的testing是lsof ,但是它列出的文件是不存在的。