一背景和现象
初创公司, 架构 lanmp,web 前端和后端分开服务器, 业务驱动主要是 nginx 和 apache,nginx 主要是处理静态文件和反向代理, 前后端搜索引擎缓存队列等附加的服务都是用 docker 容器部署因为比较初级, 上传文件和采集文件都是直接写在硬盘上, 涉及到的目录共享, 就在其中一台服务器存储并且 nfs 共享我们暂且分为 ECS1(apache1)ECS2(apache2)ECS3(nginx) 某天网站业务中断, 但是没有报错一直在等待响应, 默认响应超时是一分钟, 所以很基础高可用没有起到作用中断 10 分钟左右, 重启服务, 提示 open too many files, 但是 lsof 统计没几个因为初级处理不了, 所以直接重启服务器, 一段时间后一切恢复正常, 可是第二天又来一次这种情况
二第一次出现后的排查思路
本来第一次发现这种问题的时候就要追查原因了, 看了一下 zabbix 监控图像其中断了十分钟, 包括网络内存 CPU 硬盘 IO 等监控数据首先想到的是网络问题, 结论是 zabbix-servert 获取不到了 zabbix-agent 采集的数据, 估计就是网络不通了
但是, 这个结论站不住脚, 因为我本身通过 ssh 登录服务器, 并且命令输入无卡顿, 不至于头文件都传不过来后来一看阿里云的云监控, 上面有数据, 似乎也可以佐证网络这个说法, 因为云监控是阿里云内部的监控, 可以内网获取到监控数据直到看 CPU 的使用率这项, 发现有一段时间的 CPU 使用率 100% 并且我重启的时候 CPU 恢复正常, 不能说网络一定没问题, 但系统肯定有问题也可以解释因为 CPU 使用已经是 100%,zabbix-agent 和根本不能正常运行, 所以没有监控数据因为这个公司全部都是云服务器, 没有使用 IDC 所以我们也没有安装 smokeping 来监控, 接着我们就不把重心在网络上了
目前掌握的信息就是: 在毫无征兆的情况下, CPU 暴涨到 100%, 重启之前一直保留, 重启之后恢复原样匆忙之中又看了一下系统各日志, 因为太匆忙, 没有总结, 没有找到什么有价值的东西现在有下面几种猜想: 第一, 程序的 bug 或者部署不当, 触发之后耗尽资源第二 docker 容器的 bug 第三网络攻击第四病毒入侵第五阿里云方系统不稳定
小总结了一下, 现在问题还没有找出来下次还有这个问题的可能, 所以先尽量防范, 但是又不能重启一刀切所以在 zabbix 上面设置了自动化, 当检测到 ECS1 获取不到数据的时候马上操作 ECS3 标记后端为 ECS1 的 apache 为 down 保留异常现场 (请求停止的时候, CPU100% 还在)
三现场排查
1 相应的排查计划 (想到这些信息需要获取的, 实际上没有严格按照这样的步骤)
1) 用 htop 和 top 命令监控 CPU 内存使用大的进程先看看哪个进程消耗资源较多, 用户态内核态内存 IO 同时 sar -b 查 io 的历史定时抽样
2) 统计 tcp 连接数, 看看有没有 DDOS 攻击 netstat -anp |grep tcp |wc -l 用 iftop-i eth1 看看通讯同时用 tail -n 1200 /var/log/messages 查看内核日志
3) 用 pstree 查看打开进程, ps aux|wc-l 看看有没有特别多的进程虽然 zabbix 监控上说没有, 但是我们要检查一下看看有没有异常的进程名字
4) 查看全部容器的资源使用 docker stats $(docker ps -a -q), 看看能不能从容器上排查
5) 有了 too many open files 的启发, 计算打开文件数目 lsof|wc -l, 根据进程看看 ll /proc/PID/fd 文件描述符有没有可疑的打开文件文件描述符
6) 关于用 lsof 打开文件数找到的线索, 排序打开文件找出进程号 lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more
7) 关于用 lsof 打开文件数找到的线索, 用 lsof -p PID 查看进程打开的句柄直接查看打开的文件
8) 启动容器的时候又总是 open too many files" 那就是打开文件数的问题, 因为 CPU 的使用率是 CPU 的使用时间和空闲时间比, 有可能因为打开文件数阻塞而导致 CPU 都在等待针对连接数的问题, 大不了最后一步试试 echo 6553500> /proc/sys/fs/file-max 测试打开文件对 CPU 的影响
9) 玩意测出来了消耗 CPU 的进程, 可以使用 strace 最终程序用户态的函数调用跟踪用 ltrace, 所以这里我们应该用 strace-p PID
10) 从程序里面看到调用系统底层的函数可以跟踪跟踪操作 strace -T -e * -p PID, 主要看看代码调用的函数有没有问题
2 现场排查
第二天同样时间, ECS 果然暴涨了 CPU 这是时候 zabbix 的工作如希望进行保留了一台故障的 ECS1 给我
1) 用 htop 看到资源使用最大是, 搜索引擎下我写的一个判断脚本 xunsearch.sh 脚本里面很简单, 判断索引和搜索服务缺一个就全部重启就当是我的容器有问题我直接关掉搜索引擎容器 httpd 顶上, 我又关掉 apache 容器 rabbitmq 相关进程又顶上这时候我没心情周旋了, 肯定不也是这个原因 sar -b 查看的历史 io 也没有异常
2) 统计 tcp 连接, 几百先不用着重考虑攻击了用 tail -n 1200 /var/log/messages 查看内核日志, 是 TCP TIME WAIT 的错误可以理解为 CPU 使用 100%, 程序无响应外面的 tcp 请求超时这是结果, 还是没有找到根本原因
接着往下看系统内核日志, 发现了和 open too many files 呼应的错误, file-max limit 65535 reached 意思是, 已到达了文件限制瓶颈这里保持怀疑, 继续收集其他信息
3) 查看进程数量, 数量几百列出来也看到都是熟悉的进程, 可以先排除异常进程
4) 监控容器的资源使用, 里面很不稳定, 首先是 xunsearch 容器使用 80% 的 CPU, 关掉 xunsearch, 又变成了其他容器使用 CPU 最高很大程度上可以排查容器的问题和执行程序的问题
5) 查看了最大连接数 cat /proc/sys/fs/file-max 是 65535 但是用 lsof 查到的连接数是 10000 多, 完全没有达到连接数
6) 各项参数都正常, 现在聚焦在打开的文件数这个问题上面也可以用另外同一种方式查看一下内核统计文件 /proc/sys/fs/file-nr, 比较一下差异, 看看能不能找出问题 cat 了一下, 打开文件数是 66080, 果然超了! 内核日志就以这个为标准
但是看 lsof 怎么统计不出来, ll /proc/PID/fd 也没几个这个问题放在后面, 先按照步骤 echo 6553500> /proc/sys/fs/file-max 给连接数提高到 100 倍, CPU 果然降了下来原因确认了, 但是必须找到根源, 为什么忽然有这么大的打开文件数关掉全部 docker 容器和 docker 引擎, 打开文件数是少了一点, 但是仍然在 65535 差不多我就先排除一下业务的影响, 把 ECS3 的 nginx 直接指向视频 ECS2 的 apache, 就等同于在 ECS2 上实现了 ECS1 的场景查看一下 ECS2 的句柄数, 才 4000 多, 排除了业务相关应用对服务器的影响那就能下个小结论, ECS1 被神秘程序打开了 6 万多句柄数, 打开业务就多了 2000 多的句柄数, 然后就崩溃了不过这个现象有点奇怪, ECS2 和 ECS1 在一样的机房一样的配置一样的网络环境, 一样的操作系统, 一样的服务, 一样的容器, 为什么一个有问题, 一个没问题呢? 不同的只是有一台是共享 nfs 难道是静态文件共享了, 其他人读了, 也算是本服务器打开的?
7) 现在程序找不到, 没法继续 lsof -p 了排查之前的猜想带着排查得到对的结论往下想
程序的 bug 和部署不当, 那是不可能的, 因为主要问题来自于打开句柄数, 当部署到 ECS2 那里, 一切正常 docker 容器的 bug, 那也不可能的, 每个都是我亲自写脚本, 亲自编译, 亲自构建的, 关键是我关掉了 docker 容器和引擎都没有很大改善网络攻击也排除, 因为网络连接数没几个, 流量也不变那就只剩下病毒入侵也不是, 没有异常进程考虑到 ECS 的稳定性问题了这方面就协助阿里云工程师去排查
8) 阿里云工程师用的排查手段和我差不多, 最终也是没能看到什么也只是给了我一些治标不治本的建议后来上升到专家排查, 专家直接在阿里云后端抓取了 coredump 文件分析打开的文件是图片, 程序是 nfsd
好像印证了我刚才后面的猜想, 应该就是 ECS1 使用了 nfs 共享其他服务器打开了然后算在 ECS1 头上那问题又来了, 我们的业务已经到达了可以影响服务器的程度吗?
9) 既然问题解决到这一步, 先不管程序有没有关闭打开的文件和 nfs 的配置我们架构上面的图片应该是归 nginx 读取, 难道是 linux 的内存机制让它缓存了带着缓存的问题, 首先去 ECS3 上释放内存 echo 3> /proc/sys/vm/drop_caches, 释放之后, 发现没什么改善, 有点失落总是觉得还有一台后端是 PHP 主导, 但是逻辑上是写入, 没有打开文件之说后来从程序员中了解到, PHP 也有打开图片我猛然去 ECS2 释放一下内存, 果然, 句柄数降下来 (这里大家一定有个疑问, 为什么我直接想到内存缓存而不是目前打开的文件呢其一, 这是生产环境, web 前端只有一个, 不能乱来停服务其二, 第一次遇到问题的时候, 重启之后没有问题, 过了一天之后积累到一定的程度才爆发, 这里已经引导了我的思路是积累的问题, 那就是缓存不断积累了)
10) 因为 ECS2 的调用 ECS1 的 nfs 共享文件, 所以 lsof 也有读不到那么多句柄数的理由如果说是 nfs 的服务本身就有缓存, 导致问题的话, 我查看了配置文件, 还是默认值允许缓存, 30S 过期, 根本不会因为 nfs 的缓存造成打开文件过多如果我们的后端程序打开之后没好好处理的话, 那倒有可能然后尝试排除: 我改了 ECS3 的配置, 使程序只读 ECS1 后端, 从 ECS1 上面却看不到有什么异常表现, 说明 PHP 程序已经好好处理了打开的文件也不是 docker 挂载了 nfs 的共享的问题, 因为 nginx 也有挂载排查到这里也很大程度上解决问题, 而且缓存了 nfs 的全部共享文件, 句柄并没有增加, 也算合理, 所以就增加了打开文件数的限制
11) 现在排查的结果是跟后端和 nfs 共享有关就是说, 后端挂载了 nfs 的网络共享, 被程序读取而程序释放之后, 在正常背景的硬盘文件是没有缓存的但是在 nfs 挂载的环境下, 缓存并没有得到释放
12) 总结: 很多问题的排查和我们的猜想结果一样, 但是有些例外的情况比如这次我想到的原因都一一排除, 但是问题也是在一步步排查中, 逐步被发现的
来源: https://www.cnblogs.com/hodge01/p/8658538.html