乐趣区

关于数据库:执行sed命令卡死CPU消耗100一例分析

景象

MySQL 服务器装置 MHA,sed 命令批改装置脚本时卡死:

[root@TJ-DB-6CU552YPXS backup]# sed -i  "s/.*vip.*ping valid.*/#&/g" mha_install.sh 
^C
[root@TJ-DB-6CU552YPXS backup]#

top 查看,sed 过程 CPU 使用率 100%:

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                   
14343 root      20   0  104m 1020  852 R 100.0  0.0   0:13.94 sed

剖析

pstack 打印过程堆栈信息:


[root@TJ-DB-6CU552YPXS ~]# pstack 14343
#0  0x00007f123d474e46 in gconv () from /usr/lib64/gconv/GBK.so
#1  0x0000003f8368c6ab in mbrtowc () from /lib64/libc.so.6
#2  0x00000000004052ed in ?? ()
#3  0x0000000000405373 in ?? ()
#4  0x0000000000406323 in ?? ()
#5  0x0000000000407875 in ?? ()
#6  0x00000000004026e4 in ?? ()
#7  0x0000003f8361f0bd in __libc_start_main () from /lib64/libc.so.6
#8  0x0000000000402029 in ?? ()
#9  0x00007ffcde547f38 in ?? ()
#10 0x000000000000001c in ?? ()
#11 0x0000000000000004 in ?? ()
#12 0x00007ffcde5498d0 in ?? ()
#13 0x00007ffcde5498d4 in ?? ()
#14 0x00007ffcde5498d7 in ?? ()
#15 0x00007ffcde5498da in ?? ()
#16 0x0000000000000000 in ?? ()

sed 卡在字符集转换 gconv () 函数上,mha_install.sh 文件字符集为 uft-8,os 以后 session 字符集为 gbk:

[root@TJ-DB-6CU552YPXS backup]# file -i mha_install.sh 
mha_install.sh: text/x-shellscript; charset=utf-8
[root@TJ-DB-6CU552YPXS backup]# locale
LANG=zh_CN.gbk
LC_CTYPE="zh_CN.gbk"
LC_NUMERIC="zh_CN.gbk"
LC_TIME="zh_CN.gbk"
LC_COLLATE="zh_CN.gbk"
LC_MONETARY="zh_CN.gbk"
LC_MESSAGES="zh_CN.gbk"
LC_PAPER="zh_CN.gbk"
LC_NAME="zh_CN.gbk"
LC_ADDRESS="zh_CN.gbk"
LC_TELEPHONE="zh_CN.gbk"
LC_MEASUREMENT="zh_CN.gbk"
LC_IDENTIFICATION="zh_CN.gbk"
LC_ALL=
[root@TJ-DB-6CU552YPXS backup]#

即文件中某些内容通过 sed 命令从 uft- 8 转 gbk 时卡死,设置环境变量 LANG=en_US,不进行字符集转换,再次执行 sed 命令疾速返回后果:

[root@TJ-DB-6CU552YPXS backup]# export LANG=en_US
[root@TJ-DB-6CU552YPXS backup]# sed -i  "s/.*vip.*ping valid.*/#&/g" mha_install.sh 
[root@TJ-DB-6CU552YPXS backup]#

sed 命令到底是读到哪一行内容出了问题?应用二分查找,很快便定位了问题所在行为 325:

[root@TJ-DB-6CU552YPXS backup]# head -n 324 mha_install.sh|tail -1|sed -n '1p'

[root@TJ-DB-6CU552YPXS backup]# head -n 325 mha_install.sh|tail -1|sed -n '1p'
^C
[root@TJ-DB-6CU552YPXS backup]# head -n 325 mha_install.sh|tail -1
        #生成密钥对
[root@TJ-DB-6CU552YPXS backup]#

从输入不难猜测,应该是正文符号和中文之间没有空格,导致 sed 命令卡死,上面咱们论证测试:

[root@TJ-DB-6CU552YPXS backup]# cat fxtest.txt 
# 生成密钥对
#生成密钥对 [root@TJ-DB-6CU552YPXS backup]#

[root@TJ-DB-6CU552YPXS backup]# head -n 1 fxtest.txt |sed -n '1,$p'
# 生成密钥对
[root@TJ-DB-6CU552YPXS backup]# head -n 2 fxtest.txt |sed -n '1,$p'
# 生成密钥对
^C
[root@TJ-DB-6CU552YPXS backup]#

这个装置脚本曾经运行屡次了,始终都没问题,为何在这台机器上出了问题?机器操作系统为 centos 6,预计是 sed 版本低导致,查看 sed 版本:

[root@TJ-DB-6CU552YPXS backup]# sed --version
GNU sed  4.2.1

找一台 centos 7 机器,查看 sed 版本:

[root@fxtest01 ~]# sed --version
sed (GNU sed) 4.2.2

将 centos 7 上 sed 拷贝到这台 centos 6,再次执行同样操作,很快输入后果:

[root@TJ-DB-6CU552YPXS backup]# head -n 2 fxtest.txt |sed -n '1,$p'
# 生成密钥对
^C
[root@TJ-DB-6CU552YPXS backup]#chmod +x sed && head -n 2 fxtest.txt |./sed -n '1,$p'
# 生成密钥对
#生成密钥对 [root@TJ-DB-6CU552YPXS backup]#

总结

1、正文符号和汉字之间养成应用空格分隔习惯。
2、一些低版本工具在某些非凡状况下可能会触发 bug,仔细分析及比对,总会找到问题本源。

本文关键字:#sed# #cpu# #字符集 #

退出移动版