- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章深度解析MySQL启动时报“The server quit without updating PID file”错误的原因由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
很多童鞋在启动mysql的时候,碰到过这个错误, 。
首先,澄清一点,出现这个错误的前提是:通过服务脚本来启动mysql。通过mysqld_safe或mysqld启动mysql实例并不会报这个错误.
那么,出现这个错误的原因具体是什么呢?
哈哈,对分析过程不care的童鞋可直接跳到文末的总结部分~ 。
总结 。
下面,来分析下mysql的服务启动脚本 。
脚本完整内容如下:
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
|
#!/bin/sh
# Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
# This file
is
public
domain
and
comes
with
NO
WARRANTY
of
any
kind
# MySQL daemon start/stop script.
# Usually this
is
put
in
/etc/init.d (
at
least
on
machines SYSV R4 based
# systems)
and
linked
to
/etc/rc3.d/S99mysql
and
/etc/rc0.d/K01mysql.
#
When
this
is
done the mysql server will be started
when
the machine
is
# started
and
shut down
when
the systems goes down.
# Comments
to
support chkconfig
on
RedHat Linux
# chkconfig: 2345 64 36
# description: A very fast
and
reliable SQL
database
engine.
# Comments
to
support LSB init script conventions
###
BEGIN
INIT INFO
# Provides: mysql
# Required-Start: $local_fs $network $remote_fs
# Should-Start: ypbind nscd ldap ntpd xntpd
# Required-Stop: $local_fs $network $remote_fs
#
Default
-Start: 2 3 4 5
#
Default
-Stop: 0 1 6
# Short-Description: start
and
stop MySQL
# Description: MySQL
is
a very fast
and
reliable SQL
database
engine.
###
END
INIT INFO
# If you install MySQL
on
some
other places than /usr/
local
/mysql,
then
you
# have
to
do one
of
the following things
for
this script
to
work
:
#
# - Run this script
from
within the MySQL installation directory
# -
Create
a /etc/my.cnf file
with
the following information:
# [mysqld]
# basedir=<path-
to
-mysql-installation-directory>
# -
Add
the above
to
any
other configuration file (
for
example ~/.my.ini)
#
and
copy my_print_defaults
to
/usr/bin
# -
Add
the path
to
the mysql-installation-directory
to
the basedir variable
# below.
#
# If you want
to
affect other MySQL variables, you should make your changes
#
in
the /etc/my.cnf, ~/.my.cnf
or
other MySQL configuration files.
# If you change base dir, you must also change datadir. These may get
# overwritten
by
settings
in
the MySQL configuration files.
basedir=
datadir=
#
Default
value,
in
seconds, afterwhich the script should timeout waiting
#
for
server start.
# Value here
is
overriden
by
value
in
my.cnf.
# 0 means don
't wait at all
# Negative numbers mean to wait indefinitely
service_startup_timeout=900
# Lock directory for RedHat / SuSE.
lockdir='
/var/lock/subsys
'
lock_file_path="$lockdir/mysql"
# The following variables are only set for letting mysql.server find things.
# Set some defaults
mysqld_pid_file_path=
if test -z "$basedir"
then
basedir=/usr/local/mysql
bindir=/usr/local/mysql/bin
if test -z "$datadir"
then
datadir=/usr/local/mysql/data
fi
sbindir=/usr/local/mysql/bin
libexecdir=/usr/local/mysql/bin
else
bindir="$basedir/bin"
if test -z "$datadir"
then
datadir="$basedir/data"
fi
sbindir="$basedir/sbin"
libexecdir="$basedir/libexec"
fi
# datadir_set is used to determine if datadir was set (and so should be
# *not* set inside of the --basedir= handler.)
datadir_set=
#
# Use LSB init script functions for printing messages, if possible
#
lsb_functions="/lib/lsb/init-functions"
if test -f $lsb_functions ; then
. $lsb_functions
else
log_success_msg()
{
echo " SUCCESS! $@"
}
log_failure_msg()
{
echo " ERROR! $@"
}
fi
PATH="/sbin:/usr/sbin:/bin:/usr/bin:$basedir/bin"
export PATH
mode=$1 # start or stop
[ $# -ge 1 ] && shift
other_args="$*" # uncommon, but needed when called from an RPM upgrade action
# Expected: "--skip-networking --skip-grant-tables"
# They are not checked here, intentionally, as it is the resposibility
# of the "spec" file author to give correct arguments only.
case `echo "testing\c"`,`echo -n testing` in
*c*,-n*) echo_n= echo_c= ;;
*c*,*) echo_n=-n echo_c= ;;
*) echo_n= echo_c='
\c
' ;;
esac
parse_server_arguments() {
for arg do
case "$arg" in
--basedir=*) basedir=`echo "$arg" | sed -e '
s/^[^=]*=//
'`
bindir="$basedir/bin"
if test -z "$datadir_set"; then
datadir="$basedir/data"
fi
sbindir="$basedir/sbin"
libexecdir="$basedir/libexec"
;;
--datadir=*) datadir=`echo "$arg" | sed -e '
s/^[^=]*=//
'`
datadir_set=1
;;
--pid-file=*) mysqld_pid_file_path=`echo "$arg" | sed -e '
s/^[^=]*=//
'` ;;
--service-startup-timeout=*) service_startup_timeout=`echo "$arg" | sed -e '
s/^[^=]*=//
'` ;;
esac
done
}
wait_for_pid () {
verb="$1" # created | removed
pid="$2" # process ID of the program operating on the pid-file
pid_file_path="$3" # path to the PID file.
i=0
avoid_race_condition="by checking again"
while test $i -ne $service_startup_timeout ; do
case "$verb" in
'
created
')
# wait for a PID-file to pop into existence.
test -s "$pid_file_path" && i='
' && break
;;
'
removed
')
# wait for this PID-file to disappear
test ! -s "$pid_file_path" && i='
' && break
;;
*)
echo "wait_for_pid () usage: wait_for_pid created|removed pid pid_file_path"
exit 1
;;
esac
# if server isn'
t running,
then
pid-file will never be updated
if test -n
"$pid"
;
then
if kill -0
"$pid"
2>/dev/
null
;
then
: # the server still runs
else
# The server may have exited
between
the
last
pid-file
check
and
now.
if test -n
"$avoid_race_condition"
;
then
avoid_race_condition=
""
continue
#
Check
again.
fi
# there
's nothing that will affect the file.
log_failure_msg "The server quit without updating PID file ($pid_file_path)."
return 1 # not waiting any more.
fi
fi
echo $echo_n ".$echo_c"
i=`expr $i + 1`
sleep 1
done
if test -z "$i" ; then
log_success_msg
return 0
else
log_failure_msg
return 1
fi
}
# Get arguments from the my.cnf file,
# the only group, which is read from now on is [mysqld]
if test -x ./bin/my_print_defaults
then
print_defaults="./bin/my_print_defaults"
elif test -x $bindir/my_print_defaults
then
print_defaults="$bindir/my_print_defaults"
elif test -x $bindir/mysql_print_defaults
then
print_defaults="$bindir/mysql_print_defaults"
else
# Try to find basedir in /etc/my.cnf
conf=/etc/my.cnf
print_defaults=
if test -r $conf
then
subpat='
^[^=]*basedir[^=]*=\(.*\)$
'
dirs=`sed -e "/$subpat/!d" -e '
s//\1/
' $conf`
for d in $dirs
do
d=`echo $d | sed -e '
s/[ ]//g
'`
if test -x "$d/bin/my_print_defaults"
then
print_defaults="$d/bin/my_print_defaults"
break
fi
if test -x "$d/bin/mysql_print_defaults"
then
print_defaults="$d/bin/mysql_print_defaults"
break
fi
done
fi
# Hope it'
s
in
the PATH ... but I doubt it
test -z
"$print_defaults"
&& print_defaults=
"my_print_defaults"
fi
#
#
Read
defaults file
from
'basedir'
. If there
is
no
defaults file there
#
check
if it
's in the old (depricated) place (datadir) and read it from there
#
extra_args=""
if test -r "$basedir/my.cnf"
then
extra_args="-e $basedir/my.cnf"
else
if test -r "$datadir/my.cnf"
then
extra_args="-e $datadir/my.cnf"
fi
fi
parse_server_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server`
#
# Set pid file if not given
#
if test -z "$mysqld_pid_file_path"
then
mysqld_pid_file_path=$datadir/`hostname`.pid
else
case "$mysqld_pid_file_path" in
/* ) ;;
* ) mysqld_pid_file_path="$datadir/$mysqld_pid_file_path" ;;
esac
fi
case "$mode" in
'
start
')
# Start daemon
# Safeguard (relative paths, core dumps..)
cd $basedir
echo $echo_n "Starting MySQL"
if test -x $bindir/mysqld_safe
then
# Give extra arguments to mysqld with the my.cnf file. This script
# may be overwritten at next upgrade.
$bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &
wait_for_pid created "$!" "$mysqld_pid_file_path"; return_value=$?
# Make lock for RedHat / SuSE
if test -w "$lockdir"
then
touch "$lock_file_path"
fi
exit $return_value
else
log_failure_msg "Couldn'
t find MySQL server ($bindir/mysqld_safe)"
fi
;;
'stop'
)
# Stop daemon. We use a signal here
to
avoid
having
to
know the
# root
password
.
if test -s
"$mysqld_pid_file_path"
then
mysqld_pid=`cat
"$mysqld_pid_file_path"
`
if (kill -0 $mysqld_pid 2>/dev/
null
)
then
echo $echo_n
"Shutting down MySQL"
kill $mysqld_pid
# mysqld should remove the pid file
when
it exits, so wait
for
it.
wait_for_pid removed
"$mysqld_pid"
"$mysqld_pid_file_path"
; return_value=$?
else
log_failure_msg
"MySQL server process #$mysqld_pid is not running!"
rm
"$mysqld_pid_file_path"
fi
#
Delete
lock
for
RedHat / SuSE
if test -f
"$lock_file_path"
then
rm -f
"$lock_file_path"
fi
exit $return_value
else
log_failure_msg
"MySQL server PID file could not be found!"
fi
;;
'restart'
)
# Stop the service
and
regardless
of
whether it was
# running
or
not
, start it again.
if $0 stop $other_args;
then
$0 start $other_args
else
log_failure_msg
"Failed to stop running server, so refusing to try to start."
exit 1
fi
;;
'reload'
|
'force-reload'
)
if test -s
"$mysqld_pid_file_path"
;
then
read
mysqld_pid <
"$mysqld_pid_file_path"
kill -HUP $mysqld_pid && log_success_msg
"Reloading service MySQL"
touch
"$mysqld_pid_file_path"
else
log_failure_msg
"MySQL PID file could not be found!"
exit 1
fi
;;
'status'
)
#
First
,
check
to
see if pid file exists
if test -s
"$mysqld_pid_file_path"
;
then
read
mysqld_pid <
"$mysqld_pid_file_path"
if kill -0 $mysqld_pid 2>/dev/
null
;
then
log_success_msg
"MySQL running ($mysqld_pid)"
exit 0
else
log_failure_msg
"MySQL is not running, but PID file exists"
exit 1
fi
else
# Try
to
find appropriate mysqld process
mysqld_pid=`pidof $libexecdir/mysqld`
# test if multiple pids exist
pid_count=`echo $mysqld_pid | wc -w`
if test $pid_count -gt 1 ;
then
log_failure_msg
"Multiple MySQL running but PID file could not be found ($mysqld_pid)"
exit 5
elif test -z $mysqld_pid ;
then
if test -f
"$lock_file_path"
;
then
log_failure_msg
"MySQL is not running, but lock file ($lock_file_path) exists"
exit 2
fi
log_failure_msg
"MySQL is not running"
exit 3
else
log_failure_msg
"MySQL is running but PID file could not be found"
exit 4
fi
fi
;;
*)
# usage
basename=`basename
"$0"
`
echo
"Usage: $basename {start|stop|restart|reload|force-reload|status} [ MySQL server options ]"
exit 1
;;
esac
exit 0
|
首先,定义相关参数 。
1
2
3
4
5
6
7
8
9
10
11
|
basedir=
datadir=
#
Default
value,
in
seconds, afterwhich the script should timeout waiting
#
for
server start.
# Value here
is
overriden
by
value
in
my.cnf.
# 0 means don
't wait at all
# Negative numbers mean to wait indefinitely
service_startup_timeout=900
# Lock directory for RedHat / SuSE.
lockdir='
/var/lock/subsys'
lock_file_path=
"$lockdir/mysql"
|
其中, 。
basedir 指的二进制压缩包解压后所在的目录,譬如/usr/local/mysql.
datadir 指的是数据目录 。
service_startup_timeout=900 定义mysql服务启动的时间限制,如果在900s中没有启动成功,则该脚本会退出.
1
|
lockdir=
'/var/lock/subsys'
|
关于/var/lock/subsys,网上的解释如下,后续会用到.
总的来说,系统关闭的过程(发出关闭信号,调用服务自身的进程)中会检查/var/lock/subsys下的文件,逐一关闭每个服务,如果某一运行的服务在/var/lock/subsys下没有相应的选项。在系统关闭的时候,会像杀死普通进程一样杀死这个服务.
通过察看/etc/rc.d/init.d下的脚本,可以发现每个服务自己操纵时都会去查看/var/lock/subsys下相应的服务.
很多程序需要判断是否当前已经有一个实例在运行,这个目录就是让程序判断是否有实例运行的标志,比如说xinetd,如果存在这个文件,表示已经有xinetd在运行了,否则就是没有,当然程序里面还要有相应的判断措施来真正确定是否有实例在运行。通常与该目录配套的还有/var/run目录,用来存放对应实例的PID,如果你写脚本的话,会发现这2个目录结合起来可以很方便的判断出许多服务是否在运行,运行的相关信息等等。 。
判断basedir和datadir 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#
Set
some
defaults
mysqld_pid_file_path=
if test -z
"$basedir"
then
basedir=/usr/
local
/mysql
bindir=/usr/
local
/mysql/bin
if test -z
"$datadir"
then
datadir=/usr/
local
/mysql/data
fi
sbindir=/usr/
local
/mysql/bin
libexecdir=/usr/
local
/mysql/bin
else
bindir=
"$basedir/bin"
if test -z
"$datadir"
then
datadir=
"$basedir/data"
fi
sbindir=
"$basedir/sbin"
libexecdir=
"$basedir/libexec"
fi
|
其中, 。
mysqld_pid_file_path 指定pid文件的路径 。
-z string 判断字符串是否为空 。
如果basedir没有显示设置,则默认为/usr/local/mysql,这也是为什么很多mysql安装教程都推荐将mysql相关文件放到/usr/local/mysql下.
如果datadir没有显示设置,则默认为$basedir/data.
定义log_success_msg()和log_failure_msg()函数 。
首先,判断/lib/lsb/init-functions文件是否存在,如果存在,则使定义在init-functions文件中的所有shell函数在当前脚本中生效.
如果没有,则定义两个函数,一个用于打印成功日志,一个是打印错误日志.
在RHCS 6.7中,该文件并不存在,已被/etc/init.d/functions所替代.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#
# Use LSB init script functions
for
printing messages, if possible
#
lsb_functions=
"/lib/lsb/init-functions"
if test -f $lsb_functions ;
then
. $lsb_functions
else
log_success_msg()
{
echo
" SUCCESS! $@"
}
log_failure_msg()
{
echo
" ERROR! $@"
}
fi
|
传递参数 。
将第一个参数传递给mode,剩下的参数传递给other_args 。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
PATH=
"/sbin:/usr/sbin:/bin:/usr/bin:$basedir/bin"
export PATH
mode=$1 # start
or
stop
[ $# -ge 1 ] && shift
other_args=
"$*"
# uncommon, but needed
when
called
from
an RPM upgrade
action
# Expected:
"--skip-networking --skip-grant-tables"
# They are
not
checked here, intentionally,
as
it
is
the resposibility
#
of
the
"spec"
file author
to
give correct arguments
only
.
case
`echo
"testing\c"
`,`echo -n testing`
in
*c*,-n*) echo_n= echo_c= ;;
*c*,*) echo_n=-n echo_c= ;;
*) echo_n= echo_c=
'\c'
;;
esac
|
解析配置文件中的参数 。
这个函数在脚本后面会涉及到.
主要涉及如下参数:--basedir,--datadir,--pid-file,--service-startup-timeout.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
parse_server_arguments() {
for
arg do
case
"$arg"
in
--basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'`
bindir=
"$basedir/bin"
if test -z
"$datadir_set"
;
then
datadir=
"$basedir/data"
fi
sbindir=
"$basedir/sbin"
libexecdir=
"$basedir/libexec"
;;
--datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'`
datadir_set=1
;;
--pid-file=*) mysqld_pid_file_path=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
--service-startup-timeout=*) service_startup_timeout=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
esac
done
}
|
判断my_print_defaults的位置 。
首先,它判断当前路径下的bin目录中是否存在该可执行文件,如果不存在,则再判断$bindir(通常指的是$basedir/bin)目录下是否存在.
如果还是没有,则会判断/etc/my.cnf是否存在并且可读,如果是,则判断该配置文件中是否指定了basedir参数, 。
如果指定了,则取出该参数的值,并判断该值对应的目录中是否存在bin/my_print_defaults可执行文件 。
最后一步,如果在上述目录中实在没发现my_print_defaults文件, 。
索性就将print_defaults设置为"my_print_defaults",寄希望于该命令在当前的PATH环境中.
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
|
# Get arguments
from
the my.cnf file,
# the
only
group
, which
is
read
from
now
on
is
[mysqld]
if test -x ./bin/my_print_defaults
then
print_defaults=
"./bin/my_print_defaults"
elif test -x $bindir/my_print_defaults
then
print_defaults=
"$bindir/my_print_defaults"
elif test -x $bindir/mysql_print_defaults
then
print_defaults=
"$bindir/mysql_print_defaults"
else
# Try
to
find basedir
in
/etc/my.cnf
conf=/etc/my.cnf
print_defaults=
if test -r $conf
then
subpat=
'^[^=]*basedir[^=]*=\(.*\)$'
dirs=`sed -e
"/$subpat/!d"
-e
's//\1/'
$conf`
for
d
in
$dirs
do
d=`echo $d | sed -e
's/[ ]//g'
`
if test -x
"$d/bin/my_print_defaults"
then
print_defaults=
"$d/bin/my_print_defaults"
break
fi
if test -x
"$d/bin/mysql_print_defaults"
then
print_defaults=
"$d/bin/mysql_print_defaults"
break
fi
done
fi
# Hope it's
in
the PATH ... but I doubt it
test -z
"$print_defaults"
&& print_defaults=
"my_print_defaults"
fi
|
查找默认的配置文件 。
-r file 如果文件可读,则为真 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#
#
Read
defaults file
from
'basedir'
. If there
is
no
defaults file there
#
check
if it's
in
the old (depricated) place (datadir)
and
read
it
from
there
#
extra_args=
""
if test -r
"$basedir/my.cnf"
then
extra_args=
"-e $basedir/my.cnf"
else
if test -r
"$datadir/my.cnf"
then
extra_args=
"-e $datadir/my.cnf"
fi
fi
|
解析配置文件中的参数 。
my_print_defaults的用法如下:
my_print_defaults --defaults-file=example.cnf client mysql 。
即读取配置文件中,client和mysql部分的参数配置, 。
具体在本脚本中,是读取mysqld,server,mysql_server,mysql.server四个部分的配置参数.
1
|
parse_server_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server`
|
设置pid file的路径 。
-z string 判断字符串是否为空 。
如果--pid-file没有在读取到的配置文件中设置或者脚本刚开始的mysqld_pid_file_path参数没有设置, 。
则pid file默认设置在datadir下,以主机名.pid命名.
如果该参数设置了,还需要进一步判断 。
如果该参数中带有斜杠,则代表给定的值带有路径,可直接使用.
如果该参数中没带路径,则代表给定的值只是pid的文件名,可将其设在datadir下.
1
2
3
4
5
6
7
8
9
10
11
12
|
#
#
Set
pid file if
not
given
#
if test -z
"$mysqld_pid_file_path"
then
mysqld_pid_file_path=$datadir/`hostname`.pid
else
case
"$mysqld_pid_file_path"
in
/* ) ;;
* ) mysqld_pid_file_path=
"$datadir/$mysqld_pid_file_path"
;;
esac
fi
|
服务脚本start选项 。
首先,切换到$basedir中 。
其次,判断$basedir/bin中的mysqld_safe是否是可执行文件,如果是,则启动mysqld实例,如果不是,则报错退出.
那么,启动流程又是如何实现的呢?
首先,执行$bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &命令,启动mysqld实例.
注意到没有,mysqld_safe其实是在basedir中执行的,包括mysql初始化脚本mysql_install_db,也建议在basedir中执行,具体可参考:
分析MariaDB初始化脚本mysql_install_db 。
然后通过wait_for_pid函数进行判断,具体可见下文对于wait_for_pid函数的分析 。
判断完毕后, 。
查看$lockdir目录是否可写,可写的话,则在目录上创建一个文件.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
case
"$mode"
in
'start'
)
# Start daemon
# Safeguard (
relative
paths, core dumps..)
cd $basedir
echo $echo_n
"Starting MySQL"
if test -x $bindir/mysqld_safe
then
# Give extra arguments
to
mysqld
with
the my.cnf file. This script
# may be overwritten
at
next
upgrade.
$bindir/mysqld_safe
--datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &
wait_for_pid created
"$!"
"$mysqld_pid_file_path"
; return_value=$?
# Make lock
for
RedHat / SuSE
if test -w
"$lockdir"
then
touch
"$lock_file_path"
fi
exit $return_value
else
log_failure_msg
"Couldn't find MySQL server ($bindir/mysqld_safe)"
fi
;;
|
wait_for_pid函数 。
在利用mysqld_safe启动mysql实例后,会调用该参数 。
1
|
wait_for_pid created
"$!"
"$mysqld_pid_file_path"
; return_value=$?
|
其中$!在shell中用于获取最后运行的后台Process的PID,具体在本例中,是mysqld_safe进程的pid.
因为第一个参数是created,所以会执行test -s "$pid_file_path" && i='' && break命令.
-s file 如果文件的长度不为零,则为真 。
该命令的意思是如果pid文件存在,则将变量i设置为空,并退出while循环.
然后执行如下判断, 。
1
2
3
4
5
6
7
|
if test -z
"$i"
;
then
log_success_msg
return
0
else
log_failure_msg
return
1
fi
|
如果$i为空,则打印成功日志,并退出脚本,很显然,在pid文件存在的情况下,会将变量i设置为空.
再来看看pid文件不存在的情况 。
首先,会判断$pid是否不为空(即if test -n "$pid") 。
如果不为空,则代表在执行完mysqld_safe后,已经捕捉到了该进程的pid.
在这种情况下,进一步通过kill -0 "$pid"确认该进程是否存在.
kill -0就是不发送任何信号,但是系统会进行错误检查,所以经常用来检查一个进程是否存在,当进程不存在时, kill -0 pid会返回错误 。
如果该进程存在,则不执行任何操作,直接跳到如下操作 。
1
2
3
|
echo $echo_n
".$echo_c"
i=`expr $i + 1`
sleep 1
|
将变量i加1,并sleep 1s.
然后,继续while循环,之所以这样做,是考虑到mysqld_safe已经执行,但是mysqld实例还在启动过程中,还没创建好pid文件.
一直到$1达到$service_startup_timeout定义的时长.
如果在while循环的过程中,通过kill -0 "$pid"判断到进程已经不存在了, 。
则会再判断一次,如果这次判断的结果依旧是pid file不存在,且进程不存在,则会执行 。
1
|
log_failure_msg
"The server quit without updating PID file ($pid_file_path)."
|
这就是大名鼎鼎的“The server quit without updating PID file”的由来.
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
|
wait_for_pid () {
verb=
"$1"
# created | removed
pid=
"$2"
# process ID
of
the program operating
on
the pid-file
pid_file_path=
"$3"
# path
to
the PID file.
i=0
avoid_race_condition=
"by checking again"
while test $i -ne $service_startup_timeout ; do
case
"$verb"
in
'created'
)
# wait
for
a PID-file
to
pop
into
existence.
test -s
"$pid_file_path"
&& i=
''
&& break
;;
'removed'
)
# wait
for
this PID-file
to
disappear
test ! -s
"$pid_file_path"
&& i=
''
&& break
;;
*)
echo
"wait_for_pid () usage: wait_for_pid created|removed pid pid_file_path"
exit 1
;;
esac
# if server isn
't running, then pid-file will never be updated
if test -n "$pid"; then
if kill -0 "$pid" 2>/dev/null; then
: # the server still runs
else
# The server may have exited between the last pid-file check and now.
if test -n "$avoid_race_condition"; then
avoid_race_condition=""
continue # Check again.
fi
# there'
s nothing that will affect the file.
log_failure_msg
"The server quit without updating PID file ($pid_file_path)."
return
1 #
not
waiting
any
more.
fi
fi
echo $echo_n
".$echo_c"
i=`expr $i + 1`
sleep 1
done
if test -z
"$i"
;
then
log_success_msg
return
0
else
log_failure_msg
return
1
fi
}
|
服务脚本stop选项 。
首先,判断pid文件的长度是否不为零.
-s file 如果文件的长度不为零,则为真 。
此时,会通过pid文件获取mysqld进程的pid,注意,不是mysqld_safe进程的pid 。
然后,判断mysqld进程是否在正常运行, 。
如果是,则通过kill $mysqld_pid的方式来关闭mysqld进程 。
杀死进程最安全的方法是单纯使用kill命令,不加修饰符,不带标志.
标准的kill命令通常会终止有问题的进程,并把进程的资源释放给系统。然而,如果进程启动了子进程,只杀死父进程,子进程仍在运行,因此仍消耗资源。为了防止这些所谓的“僵尸进程”,应确保在杀死父进程之前,先杀死其所有的子进程.
然后,调用wait_for_pid函数进行判断,其实,wait_for_pid函数中设置avoid_race_condition变量的目的是为了stop选项,确实有可能出现,mysqld是在检查pid file之后,检查进程是否存活之前退出的.
如果mysqld进程没有正常运行,在会打印“MySQL server process #$mysqld_pid is not running!”信息,并删除pid文件.
如果在执行stop的时候,判断pid文件的长度为0,则会打印"MySQL server PID file could not be found!"信息.
所以,在pid文件不存在的情况下,通过服务脚本执行stop选项并不会关闭mysqld进程,这个时候,就可通过kill $mysqld_pid的方式来关闭mysqld进程.
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
|
'stop'
)
# Stop daemon. We use a signal here
to
avoid
having
to
know the
# root
password
.
if test -s
"$mysqld_pid_file_path"
then
mysqld_pid=`cat
"$mysqld_pid_file_path"
`
if (kill -0 $mysqld_pid 2>/dev/
null
)
then
echo $echo_n
"Shutting down MySQL"
kill $mysqld_pid
# mysqld should remove the pid file
when
it exits, so wait
for
it.
wait_for_pid removed
"$mysqld_pid"
"$mysqld_pid_file_path"
; return_value=$?
else
log_failure_msg
"MySQL server process #$mysqld_pid is not running!"
rm
"$mysqld_pid_file_path"
fi
#
Delete
lock
for
RedHat / SuSE
if test -f
"$lock_file_path"
then
rm -f
"$lock_file_path"
fi
exit $return_value
else
log_failure_msg
"MySQL server PID file could not be found!"
fi
;;
|
服务脚本restart选项 。
首先,先执行stop操作,如果stop操作成功的话,则继续执行start操作.
如果stop操作失败的话,则会输出"Failed to stop running server, so refusing to try to start."信息,并退出脚本.
1
2
3
4
5
6
7
8
9
10
|
'restart'
)
# Stop the service
and
regardless
of
whether it was
# running
or
not
, start it again.
if $0 stop $other_args;
then
$0 start $other_args
else
log_failure_msg
"Failed to stop running server, so refusing to try to start."
exit 1
fi
;;
|
服务脚本reload选项 。
首先,判断pid文件的长度是否为0,如果不为0,则将该文件中的值设置为mysqld_pid变量的值.
然后对该进程执行kill -HUP操作.
1
|
kill -HUP pid
|
pid 是进程标识。如果想要更改配置而不需停止并重新启动服务,请使用该命令。在对配置文件作必要的更改后,发出该命令以动态更新服务配置.
根据约定,当您发送一个挂起信号(信号 1 或 HUP)时,大多数服务器进程(所有常用的进程)都会进行复位操作并重新加载它们的配置文件.
如果pid文件的长度为0,则输出"MySQL PID file could not be found!".
1
2
3
4
5
6
7
8
9
10
|
'reload'
|
'force-reload'
)
if test -s
"$mysqld_pid_file_path"
;
then
read
mysqld_pid <
"$mysqld_pid_file_path"
kill -HUP $mysqld_pid && log_success_msg
"Reloading service MySQL"
touch
"$mysqld_pid_file_path"
else
log_failure_msg
"MySQL PID file could not be found!"
exit 1
fi
;;
|
服务脚本status选项 。
首先,判断pid文件长度是否为0,如果不是,则读取该文件中的值,并判断pid对应的进程是否运行正常, 。
如果运行正常,则输出"MySQL running" 。
如果不正常,则输出"MySQL is not running, but PID file exists" 。
如果pid文件的长度为0,则试图通过mysqld的启动命令来获取其pid, 。
这个时候,可能存在一个mysqld程序启动了多个实例,这会导致pid_count=`echo $mysqld_pid | wc -w`大于1.
这个时候,会输出"Multiple MySQL running but PID file could not be found"信息,并退出脚本.
如果mysqld_pid为空,则会继续判断"$lock_file_path"是否存在,如果存在, 。
则会输出"MySQL is not running, but lock file ($lock_file_path) exists"信息.
如果"$lock_file_path"不存在,则会输出"MySQL is not running"信息.
如果mysqld_pid等于1,则会输出"MySQL is running but PID file could not be found"信息.
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
|
'status'
)
#
First
,
check
to
see if pid file exists
if test -s
"$mysqld_pid_file_path"
;
then
read
mysqld_pid <
"$mysqld_pid_file_path"
if kill -0 $mysqld_pid 2>/dev/
null
;
then
log_success_msg
"MySQL running ($mysqld_pid)"
exit 0
else
log_failure_msg
"MySQL is not running, but PID file exists"
exit 1
fi
else
# Try
to
find appropriate mysqld process
mysqld_pid=`pidof $libexecdir/mysqld`
# test if multiple pids exist
pid_count=`echo $mysqld_pid | wc -w`
if test $pid_count -gt 1 ;
then
log_failure_msg
"Multiple MySQL running but PID file could not be found ($mysqld_pid)"
exit 5
elif test -z $mysqld_pid ;
then
if test -f
"$lock_file_path"
;
then
log_failure_msg
"MySQL is not running, but lock file ($lock_file_path) exists"
exit 2
fi
log_failure_msg
"MySQL is not running"
exit 3
else
log_failure_msg
"MySQL is running but PID file could not be found"
exit 4
fi
fi
;;
|
服务脚本其它选项 。
如果脚本的第一个参数不是上述几个选项,则会输出Usage信息.
1
2
3
4
5
6
|
*)
# usage
basename=`basename
"$0"
`
echo
"Usage: $basename {start|stop|restart|reload|force-reload|status} [ MySQL server options ]"
exit 1
;;
|
至此,mysql的服务脚本分析完毕~ 。
总结 。
在通过服务脚本启动mysql的过程中,报“The server quit without updating PID file”错误,有两个条件 。
首先,pid文件不存在 。
其次,通过kill -0 $pid检查到进程并不存在 。
这个时候,只能通过mysql数据库的错误日志来定位.
服务脚本如果不做任何调整的话,默认的basedir是/usr/local/mysql,datadir是/usr/local/mysql/data 。
如果自己的mysql服务均不是默认路径, 。
则需要在该脚本中显式设置 。
经测试,需设置如下几处:
1. 设置basedir和添加conf变量 。
其中,conf指的是mysqld的配置文件,建议配置文件中显式指定basedir和datadir的值.
在这里,datadir可不设置,因为datadir可通过配置文件来获取.
但是basedir必须要指定,因为要首先根据basedir来判断my_print_deefauts命令 。
1
2
3
|
basedir=/usr/
local
/mysql-advanced-5.6.23-linux-glibc2.5-x86_64
datadir=
conf=/usr/
local
/mysql-advanced-5.6.23-linux-glibc2.5-x86_64/my_3308.cnf
|
2. 第256行,添加extra_args=" -c $conf" 。
1
2
3
4
5
6
7
8
9
10
11
|
extra_args=
" -e $basedir/my.cnf.bak"
if test -r
"$basedir/my.cnf"
then
extra_args=
"-e $basedir/my.cnf"
else
if test -r
"$datadir/my.cnf"
then
extra_args=
"-e $datadir/my.cnf"
fi
fi
extra_args=
" -c $conf"
|
3. 修改285行mysqld_safe的启动参数 。
将 。
1
|
$bindir/mysqld_safe
--datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &
|
修改为, 。
1
|
$bindir/mysqld_safe
--defaults-file="$conf" --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &
|
主要是添加了--defaults-file选项 。
以上所述是小编给大家介绍的深度解析MySQL启动时报“The server quit without updating PID file”错误的原因,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我网站的支持! 。
原文链接:http://www.cnblogs.com/ivictor/p/6846017.html 。
最后此篇关于深度解析MySQL启动时报“The server quit without updating PID file”错误的原因的文章就讲到这里了,如果你想了解更多关于深度解析MySQL启动时报“The server quit without updating PID file”错误的原因的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
manpage of reboot()说 Behavior inside PID namespaces Since Linux 3.4, if reboot() is called from a PI
我今天第一次在 Nvidia jetson Xavier 中安装和配置并使用了电视, 但重启后我遇到了这个问题: teamviewerd.service: 启动后无法打开 PID 文件/var/run
我在我的服务器上安装了 hhvm,在我重新启动服务器之前它一直运行良好。在 hhvm 的日志中,我看到了这个错误: Unable to read pid file /var/run/hhvm/pid
我正在尝试为我的应用程序精简,但随后无法生成 pid: $ thin -C /var/www/project_path/current/config/myproject.testing.yml sta
我正在从我的私有(private) git 存储库安装应用程序。我安装了所有依赖项并且我正在使用 Capistrano。我能够在我的本地计算机上成功运行应用程序。我正在使用 rails -v 3.2.
我已按照 DigitalOcean 指南中的步骤进行操作 here和 here使用 nginx 和 Unicorn 设置 Sinatra 服务器。我在倒数第二步: start the Unicorn
我在 C 程序中连续进行了 3 个 fork 。 1.它会以相同的顺序执行吗? (我的猜测是肯定的)。 2. 如果我做 pgrep myexecutable从 shell 中,它会按照启动的顺序给出进
我尝试通过FT_Prog更改FTDI芯片(R232R)中的PID。它可以工作,但之后我发现 Windows 7 自动重新安装 USB 设备的驱动程序,而不是 FTDI 设备。所以我想将PID改回默认值
第一次在这里发表 简单情况:在 PUTTY 中,我必须创建一个名为 admin.pid 的文件,当用户启动我正在创建的“应用程序”时,它会在其中存储 PID。我怎样才能做到这一点?谢谢 最佳答案 使用
我设法为每个单独的进程输出正确的进程 ID 顺序,但我的问题是我无法显示子进程的 PID。 我的程序能够打印 parent 的 PID 和孙子的 PID。我确实看到了 child 的 PID,但它显示
我正在从事一个项目,其中有许多 PID,我必须找出其中哪些是僵尸进程,然后终止它们的父进程以终止初始僵尸进程。我不确定是否有任何方法可以找出给定 PID 的 PPID 是什么。任何帮助将不胜感激。 最
我正在使用 htop,所以看看哪些进程占用了大量内存,以便我可以杀死它们。我有很多 tmux session 和很多类似的过程。如何检查 PID 所在的 tmux Pane ,以便确定我正在杀死我想杀
我正在通过运行跟踪应用程序: strace -f -y -qq -z -etrace=execve,... -o app.trace ./app 有没有办法确定哪个进程产生了哪个 child_proc
在我使用 exec 之后docker 容器内的命令我可以使用 exec inspect 获取 PID .问题是这个 ID 不是容器本地的,而是系统 PID。所以我会得到类似 22620 的东西,而 d
我有一个我开发的用于启动 Java 程序的 System V 初始化脚本。由于某种原因,无论何时创建 PID 文件,它都包含多个 PID 而不是一个。 下面是启动服务并写入PID文件的相关代码: da
我有一个变量 pidfile,它存储进程的 PID。 如何使用 Ruby 以编程方式终止 pidfile 中的 pid,假设我只知道文件名,而不是其中的实际 PID。 最佳答案 Process.kil
我读入了Beej's fork() primer当我调用 pid = fork(); 时,父进程获取子进程的 pid,而在子进程内部 pid = 0。 现在,由于子进程开始执行 在 fork() 语句
我正在尝试从另一个 Python 脚本运行一个 Python 脚本,并获取它的 pid 以便稍后可以终止它。 我尝试使用参数 shell=True' 的 subprocess.Popen(),但是pi
我有一个用 Cygwin 生成的进程shell 脚本,我无法用 kill 杀死它命令。即使与 Cygwin kill与 -f选项,我收到此消息: kill: couldn't open pid 123
我尝试在我的模型中为阀门构建一个 PID Controller ,我计划进行一些过程识别,获得系统对阶跃脉冲的响应和系统的传递函数,然后我可以设计 PID Controller 。但我不确定是否有用于
我是一名优秀的程序员,十分优秀!