現象
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# #字符集#