在前两篇中, 我们介绍了如何排查长时间运行的query, 以及如何在服务器上启用core generation。今天,我们来介绍下,如何收集进程的coredump进行排错。
1. 关于coredump的介绍
当程序异常或崩溃时,操作系统会中止进程,并将进程此时的内存中的内容拷贝到磁盘的指定目录下存储,生成一个core文件(是一个内存映像,同时加上调试信息),它记录了程序挂掉时详细的状态描述,以方便编程人员调试。
Greenplum什么情况下会生成coredump
当发生以下情况之一时, 就会产生coredump
- 由于硬件故障导致程序内部无法访问特定内容, 在某些情况下, 程序会发送终止信号给进程, 强制程序退出重启。
- 由于一些程序错误导致进程访问了错误的内存地址。
- 用户主动控制进程dump core文件, 这种操作一般用于排查故障, 这个之后会提到。
Greenplum集群的coredump在哪里?
如果需要让系统允许程序dump core文件, 那么需要开启一些其他参数, 比如需要在ulimit里将core的大小设置为足够大(或者不限制)
$ ulimit -a | grep core
core file size (blocks, -c) unlimited
一般情况下, 在linux系统中, 可以通过以下参数确认core file的路径:
# sysctl kernel.core_pattern
kernel.core_pattern = /<directory>/core-%e-%s-%u-%g-%p-%t
更多的配置细节请参考《如何在服务器上启用core generation》
另外, 在一些情况下(比如排查之前我们上几篇文章中提到的query慢等问题), 用户需要主动在运行中的进程上收集coredump。这时就可以用到gcore 这个命令。注意这个命令是包含在gdb程序组件中, 如果需要使用的话需要现在操作系统上安装gdb包。以下以centos 举例:
### 安装gdb ###
$ sudo yum -y install gdb
### 使用gcore收集seg0上的con8对应进程的coredump,对应的进程号为27705 ###
$ ps -ef | grep con[0-9] | grep con8 | grep seg0
gpadmin 27705 27589 0 16:19 ? 00:00:00 postgres: 20000, gpadmin gpadmin 192.168.6.198(39012) con8 seg0 cmd6 MPPEXEC UTILITY
$ gcore 27705
...
Saved corefile core.27705
之后, 就会在当前目录生成一个名为 core.[pid] 的文件, 这个即为进程27705的coredump
2. 如何收集coredump
如果需要针对core文件做离线排错(offline troubleshooting)。除了core文件本身之外, 我们还需收集所有对应进程调用的库文件(library)。如果库文件有缺失, 那么通过gdb打开core文件的话将会有信息确认, 导致排错困难。
查找和收集库文件相对比较繁琐, 所幸, 我们用于收集日志的GPMT工具已经支持自动收集打包coredump和库文件的指令。详细信息可以参考之前的文章。
举例:
$ ./gpmt packcore -cmd collect -core ~/core/core.27705
Creating temp directory ./packcore-core.27705
...
Packcore generated:
packcore-core.27705.tar.gz
3. 如何快速手动收集所有文件
有时候我们无法使用gpmt工具收集文件。比如core文件本身有问题(gpmt无法正确解析binary), 或者我们的环境里有安全要求不允许上传执行文件到服务器。在这种情况下, 我们就可以通过以下方法手工收集文件了。
简单来说, 步骤如下:
- 通过gdb命令info shared library 来获取所有进程调用的库文件
- 将所有库文件复制到对应的目录。 (注: 有很多库文件是以软连接的形式存在的, 因此我们需要复制其对应的目标文件。)
我们编写了如下脚本来帮助您快速实现上述步骤:
#!/bin/bash
### 执行core文件的路径 ###
coreFile='/home/gpadmin/core/core.27705'
### GPHOME的路径 ###
GOHOME="/opt/greenplum-db"
unset PYTHONHOME
unset PYTHONPATH
unset LD_LIBRARY_PATH
for i in `gdb -ex "info sharedlibrary" -ex "quit" $GPHOME/bin/postgres $coreFile | grep "^0x" | awk '{print $NF}'`; do dir=`dirname $i`; file=`basename $i`; mkdir -pv .$dir ; cp -Lrpv $dir/$file .$dir/$file ;done
cp -rp $coreFile ./
cp -rp $GPHOME/bin/postgres ./
示例如下:
$ bash collect_core.sh
mkdir: created directory ‘./lib64’
‘/lib64/libz.so.1’ -> ‘./lib64/libz.so.1’
mkdir: created directory ‘./opt’
mkdir: created directory ‘./opt/greenplum-db’
mkdir: created directory ‘./opt/greenplum-db/./lib’
‘/opt/greenplum-db/./lib/libgpopt.so.3’ ->
…
### result ###
$ ll
total 405188
-rw-rw-r-- 1 gpadmin gpadmin 351986816 Mar 15 16:22 core.27705
drwxrwxr-x 2 gpadmin gpadmin 293 Mar 16 11:16 lib64
drwxrwxr-x 4 gpadmin gpadmin 50 Mar 16 11:16 opt
-rwxr-xr-x 1 gpadmin gpadmin 62921216 Sep 26 00:14 postgres
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。