红帽Linux故障定位技术详解与实例(2)
2011-09-28 14:26 圈儿 BEAREYES.COM 我要评论(0) 字号:T | T
在线故障定位就是在故障发生时, 故障所处的操作系统环境仍然可以访问,故障处理人员可通过console, ssh等方式登录到操作系统上,在shell上执行各种操作命令或测试程序的方式对故障环境进行观察,分析,测试,以定位出故障发生的原因。
3、内核故障情形及处理
(1)内核panic
panic是内核最直接的故障定位报告,发生panic时,内核已经认为故障定位已经导致操作系统不再具备正常运行的条件了. 当发生panic时,Linux会将所有CPU的中断和进程调度功能都关掉,所以这时系统是没有任何反应的,如果用户启动的是图形界面,则在屏幕上也看不到任何关于panic的信息.
我们通常遇到的,机器没反应,ping不通的情况,绝大部分都是panic. Panic发生时,内核直接在console上打印导致panic的代码位置的调用堆栈, 传统的用户用串口连接到机器上来收集console上的打印信息, 但串口这种方式,显然用起来不方便, 现在的Linux, 如RHEL5,RHEL6, 都采用kdump的方法来收集panic时的信息. 在配置好kdump的情况下,panic时系统会用kexec加载并切换到一个新的内核上(放置在预先分配的内存位置),并用磁盘或网络等将系统的全部或部分内存数据保存起来.
用kdump收集到panic的数据后,用户用crash工具就能直接查看导致panic的代码路径.
panic一般是很直观的,panic的堆栈信息能直接反映出导致bug的原因,如MCE故障,NMI故障, 数据结构分配失败等. 但有时panic是因为内核主动发现了关键的数据结构不一致性,这种不一致性是什么时候,什么代码导致的,并不清楚,可能还需要多次测试用SystemTap这样的工具进行捕捉
(2)多处理机环境内核执行路径产生的死锁
内核死锁和panic不一样,产生死锁时,内核并不主动的使自己处于挂起状态. 但内核死锁发生时,两个以上的CPU的执行路径在内核态不能推进了,处于互相阻塞状态, 而且是100%的占用CPU(用的spin-lock),直接或间接的导致全部CPU上的进程无法调度. 内核死锁又分两种情况:
- 涉及到中断上下文的死锁. 这种情况的死锁,最少一个CPU上的中断被屏蔽了.系统可能没法响应ping请求. 由于有一个CPU已经没法响应中断,其上的local APIC定时中断没法工作,可以用NMI Watchdog的方法来检测出来(检查local APIC handler维护的计数器变量),NMI Watchdog可以在其处理程序中调用panic(), 用户就可以用kdump收集内存信息,从而分析各死锁CPU上的调用堆栈,查处导致死锁的逻辑原因.
- 不涉及中断上下文的死锁. 这种情况的死锁,各CPU上的中断都是正常的,系统能对ping请求作出反应,这时NMI Watchdog无法被触发. 在 2.6.16之前的内核中,并没有一种很好的方法来处理这种情形. 在RHEL5, RHEL6 内核中, 每个CPU上提供了一个watchdog内核线程,在死锁出现的情况下,死锁CPU上的watchdog内核线程没法被调度(即使它是最高优先级的实时进程),它就没法update相应的counter变量,各CPU的NMI Watchdog中断会周期性的检查其CPU对应的counter, 发现没有updated, 会调用panic(),用户就可用kdump收集内存信息,分析各死锁CPU上的调用堆栈,查处导致死锁的逻辑原因.
(3)内核的oops或warning
oops 和warning和panic类似的地方是,他们都是因内核发现了不一致而主动报告的异常. 但oops和warning导致的问题严重程度要比panic轻很多,以致于内核处理该问题时不需要使系统挂起. 产生oops和warning, 内核通常已经在dmesg中记录了相当的信息,特别是oops, 至少会打印出现故障的地方的call trace. Oops也可转换成panic/kdump来进行offline-debugging, 只要将/proc/sys/kernel下的panic_on_oops变量设置为1就行了.
产生oops和warning的直接原因有很多,如内核中的segment fault, 或内核发现的某数据结构的counter值不对, 而segment fault 和counter值的变化还有更深层次的原因,通常并不能从内核dmesg的信息中看出来,解决这种问题的是要用SystemTap进行probe, 如发现某counter的值不对,就用SystemTap做一个probe来记录所有代码对该counter的访问, 然后再进行分析.
定位oops和warning会比定位应用程序的内存访问故障定位困难很多,因为在内核并不能象用valgrind去trace应用程序一样跟踪数据结构的分配和使用情况.
2、其他(硬件相关)故障
机器自动重启是一种常见的故障情形,一般是由硬件如物理内存故障引起的,软件的故障只会导致死锁或panic, 内核中几乎没有代码在发现问题的情况下去reboot机器. 在/proc/sys/kernel目录下有个参数“panic”, 其值如果设置为非0,则在panic发生若干秒后,内核会重启机器. 现在高端的PC服务器,都在努力用软件来处理物理内存故障,如MCA的 “HWPoison”方法会将故障的物理页隔离起来,Kill掉故障页所在的进程就可以了,RHEL6现在已经支持 “HWPoison”. 那些不具备MCA能力的机器,物理内存故障时,不会产生MCE异常,直接由硬件机制reboot机器
4、RHEL6 上的Debugging技术介绍
(1)Kdump故障定位收集和crash分析
kdump就是用来在内核panic的情况下收集系统内存信息的, 用户也可在online情况下用sysrq的‘c‘键触发. Kdump 采用没有污染的内核来执行dump工作,所以其比以前的diskdump, lkcd方法更可靠. 使用kdump,用户可选择将数据dump到本地盘或网络上,也可通过定义makedumpfile的参数过滤要收集的内存信息,已减少kdump所需要的停机时间
Crash就是对kdump的信息进行分析的工具.其实际就是gdb的一个wrapper. 使用crash时,最好安装kernel-debuginfo包,这样能解析kdump收集的内核数据的符号信息. 用crash来定位问题的能力,完全取决于用户对内核代码的理解和分析能力
参考 “#>man kdump.conf”, “#>man crash”, “#>man makedumpfile”学习怎样使用kdump和crash. 访问 http://ftp.redhat.com可下载debuginfo文件
(2)用systemTap定位bug
systemtap 属于probe类的定位工具,它能对内核或用户代码的指定位置进行probe, 当执行到指定位置或访问指定位置的数据时,用户定义的probe函数自动执行,可打印出该位置的调用堆栈,参数值,变量值等信息. systemtap选择进行probe的位置很灵活,这是systemtap的强大功能所在. Systemtap的probe点可包括如下几个方面:
- 内核中全部系统调用,内核及模块中全部函数的入口或出口点
- 自定义的定时器probe点
- 内核中任意指定的代码或数据访问位置
- 特定用户进程中任意制定的代码或数据访问位置
- 各个功能子系统预先设置的若干probe点,如tcp,udp,nfs,signal各子系统都预先设置了很多探测点
systemTap的脚本用stap脚本语言来编写,脚本代码中调用stap提供的API进行统计,打印数据等工作,关于stap语言提供的API函数,参考 “#> man stapfuncs”. 关于systemTap的功能和使用可参考 “#> man stap”, “#> man stapprobes”
(3)ftrace
ftrace 是linux内核中利用tracepoints基础设施实现的事件追踪机制,它的作用在于能比较清楚的给出在一定时间内系统或进程所执行的活动,如函数调用路径,进程切换流等. Ftrace可用于观察系统各部分的latency,以便进行实时应用的优化; 它也可以通过记录一段时间内的内核活动来帮助故障定位. 如用以下方法可trace某个进程在一端时间的函数调用情况
- #> echo “function” > /sys/kernel/debug/tracing/current_tracer
- #> echo “xxx” > /sys/kernel/debug/tracing/set_ftrace_pid
- #> echo 1 > /sys/kernel/debug/tracing/tracing_enabled
除tracing函数调用外,ftrace还可tracing系统的进程切换,唤醒,块设备访问,内核数据结构分配等活动. 注意,tracing和profile是不同的,tracing记录的是一段时间内的全部活动,而不是统计信息,用户可以通过/sys/kernel/debug/tracing下的buffer_size_kb设置缓冲区的大小, 以记录更长时间的数据.
关于ftrace的具体使用可参考内核源码Documenation/trace下的内容
(4)oprofile 和 perf
oprofile和perf都是对系统进行profile(抽样,统计)的工具,它们主要用来解决系统和应用的性能问题. perf功能更强大,更全面,同时perf的用户空间工具和内核源码一起维护和发布,让用户能及时的享受perf内核新增加的特征. Perf 是在RHEL6中才有,RHEL5中没有Perf. Oprofile和perf 都使用现代CPU中具有的硬件计数器进行统计工作,但perf还可以使用内核中定义的 “software counter”及 “trace points”, 所以能做更多的工作. Oprofile的抽样工作利用 CPU的NMI中断来进行,而perf既可以利用NMI中断也可利用硬件计数器提供的周期性中断. 用户能很容易用perf来oprofile一个进程或系统的执行时间分布,如
- #> perf top -f 1000 -p
还可以利用系统定义的 “software counter”和各子系统的 “trace points” 对子系统进行分析, 如
- #>perf stat -a -e kmem:mm_page_alloc -e kmem:mm_page_free_direct -e kmem:mm_pagevec_free sleep 6
能统计6秒内kmem子系统的活动 (这一点实际是利用ftrace提供的tracepoints来实现)
我认为有了perf, 用户就没必要使用oprofile了