问题状态
生产环境使用了开源软件srs服务来调取实时视频,但是调取时提示出现了暂无数据,请稍后再试的错误,一直调取不到视频信息。
问题排查
查看了srs服务、文件服务、通信服务是否正常,云服务器负载情况,内存使用情况,网络情况,最后发现srs服务器进程状态为D,进程无法用 kill 杀掉,导致了生产环境不可用。
ps 的手册里说 D 状态是 uninterruptible sleep,Linux 进程有两种睡眠状态,一种 interruptible sleep,处在这种睡眠状态的进程是可以通过给它发信号来唤醒的,比如发 HUP 信号给 nginx 的 master 进程可以让 nginx 重新加载配置文件而不需要重新启动 nginx 进程;另外一种睡眠状态是 uninterruptible sleep,处在这种状态的进程不接受外来的任何信号,这也是为什么之前我无法用 kill 杀掉这些处于 D 状态的进程,无论是 kill, kill -9 还是 kill -15,因为它们压根儿就不受这些信号的支配。
进程为什么会被置于 uninterruptible sleep 状态呢?处于 uninterruptible sleep 状态的进程通常是在等待 IO,比如磁盘 IO,网络 IO,其他外设 IO,如果进程正在等待的 IO 在较长的时间内都没有响应,那么就很会不幸地被 ps 看到了,同时也就意味着很有可能有 IO 出了问题,可能是外设本身出了故障,也可能是比如挂载的远程文件系统已经不可访问了,我这里遇到的问题就是由 down 掉的 NFS 服务器引起的。
正是因为得不到 IO 的相应,进程才进入了 uninterruptible sleep 状态,所以要想使进程从 uninterruptible sleep 状态恢复,就得使进程等待的 IO 恢复。
查看message日志文件找到相关内核报错日志
默认情况下, Linux会最多使用40%的可用内存作为文件系统缓存。当超过这个阈值后,文件系统会把将缓存中的内存全部写入磁盘, 导致后续的IO请求都是同步的。将缓存写入磁盘时,有一个默认120秒的超时时间。 出现上面的问题的原因是IO子系统的处理速度不够快,不能在120秒将缓存中的数据全部写入磁盘。IO系统响应缓慢,导致越来越多的请求堆积,最终系统内存全部被占用,导致系统失去响应。
从系统中看下 hung_task 相关的参数及其参数值
1 2 3 4 5 6 7 8 9 10 11 12 13
| [root@aliy-nt1 ~]# sysctl -a | grep 'vm.dirty' vm.dirty_background_bytes = 0 vm.dirty_background_ratio = 10 vm.dirty_bytes = 0 vm.dirty_expire_centisecs = 3000 vm.dirty_ratio = 20 vm.dirty_writeback_centisecs = 500
[root@aliy-nt1 ~]# sysctl -a | grep hung kernel.hung_task_check_count = 4194304 kernel.hung_task_panic = 0 kernel.hung_task_timeout_secs = 120 kernel.hung_task_warnings = 0
|
通过sar查看一段时间内的cpu使用情况,CPU使用率不高。
查看内存,内存使用也不高
1
| sar -r -f /var/log/sa/sa17
|
查看硬盘IO
1
| sar -d -f /var/log/sa/sa17
|
检查磁盘分区是否存在坏块,发现没有坏块情况
1 2 3 4 5 6 7 8 9 10 11 12
| [root@aliy-nt1 ~]# /sbin/badblocks -v /dev/vda 正在检查从 0 到 41943039的块 Checking for bad blocks (read-only test): done Pass completed, 0 bad blocks found. (0/0/0 errors) [root@aliy-nt1 ~]# /sbin/badblocks -v /dev/vdb 正在检查从 0 到 41943039的块 Checking for bad blocks (read-only test): done Pass completed, 0 bad blocks found. (0/0/0 errors) [root@aliy-nt1 ~]# /sbin/badblocks -v /dev/vdc 正在检查从 0 到 104857599的块 Checking for bad blocks (read-only test): done Pass completed, 0 bad blocks found. (0/0/0 errors)
|
查找网上解决方法如下:
根据应用程序情况,对vm.dirty_ratio,vm.dirty_background_ratio两个参数进行调优设置。
1 2 3 4 5 6 7 8 9 10 11
| # sysctl -w vm.dirty_ratio=10 # sysctl -w vm.dirty_background_ratio=5 # sysctl -p
如果系统永久生效,修改/etc/sysctl.conf文件。加入如下两行: #vi /etc/sysctl.conf
vm.dirty_background_ratio = 5 vm.dirty_ratio = 10
sysctl -p
|
但是观察了一段时间,进程依然状态会导致为D,查看了srs配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| listen 1935; max_connections 1000; srs_log_tank file; srs_log_file ./objs/srs.log; http_api { enabled on; listen 1985; } http_server { enabled on; listen 8080; dir ./objs/nginx/html; # crossdomain on; } stats { network 0; disk sda sdb xvda xvdb; } vhost __defaultVhost__ { http_remux { enabled on; mount [vhost]/[app]/[stream].flv; hstrs on; } # mix_correct on; http_hooks { enabled on; on_publish http://10.25.208.243:1241/callbackOnPublish; on_unpublish http://10.25.208.243:1241/callbackOnUnpublish; on_play http://10.25.208.243:1241/callbackOnPlay; on_stop http://10.25.208.243:1241/callbackOnStop; on_dvr http://10.25.208.243:1241/callbackOnDvr; } dvr { enabled on; dvr_path /mnt/mov/[stream]-[timestamp].flv; dvr_plan session; dvr_duration 30; dvr_wait_keyframe on; time_jitter full; } hls { enabled on; hls_path /mnt/mov; hls_m3u8_file [stream].m3u8; hls_ts_file [stream]-[seq].ts; hls_fragment 10; hls_window 60000; } }
|
srs录制视频、语音是通过阿里云NFS文件服务挂载到本地/mnt/mov文件,作为临时视频中转服务,后期会自动上传到OSS对象存储服务,是否因为频繁的对该NFS读写IO性能导致srs出现hung呢?
查看相关文档,阿里云由此文档
https://help.aliyun.com/knowledge_detail/53839.html?spm=a2c4g.11186623.4.7.jXaKcm
1 2 3 4 5 6 7 8 9 10 11
| Linux nfs客户端对于同时发起的NFS请求数量进行了控制,若该参数配置较小会导致IO性能较差,请查看该参数:cat /proc/sys/sunrpc/tcp_slot_table_entries
[root@aliy-nt1 srs]# cat /proc/sys/sunrpc/tcp_slot_table_entries 2
默认编译的内核该参数最大值为256,可适当提高该参数的值来取得较好的性能,请以root身份执行以下命令:
echo "options sunrpc tcp_slot_table_entries=128" >> /etc/modprobe.d/sunrpc.conf echo "options sunrpc tcp_max_slot_table_entries=128" >> /etc/modprobe.d/sunrpc.conf sysctl -w sunrpc.tcp_slot_table_entries=128 修改完成后,您需要重新挂载文件系统或重启机器。
|