$ export HEART_COMMAND="erl -heart"$ erl -heartheart_beat_kill_pid = 12640Erlang R15B03 (erts-5.9.3.1) 1 [64-bit] [smp:16:16] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.9.3.1 (abort with ^G)1> os:getpid()."12640"2>CTRL + Z 挂起 erlang$ pstree -p…+-beam.smp(12640)-+-heart(12670)| | | |-{beam.smp}(12647)| | | |-{beam.smp}(12648)| | | |-{beam.smp}(12650)| | | |-{beam.smp}(12653)| | | |-{beam.smp}(12654)| | | |-{beam.smp}(12655)| | | |-{beam.smp}(12656)| | | |-{beam.smp}(12657)| | | |-{beam.smp}(12658)| | | |-{beam.smp}(12659)| | | |-{beam.smp}(12660)| | | |-{beam.smp}(12661)| | | |-{beam.smp}(12662)| | | |-{beam.smp}(12663)| | | |-{beam.smp}(12664)| | | |-{beam.smp}(12665)| | | |-{beam.smp}(12666)| | | |-{beam.smp}(12667)| | | |-{beam.smp}(12668)| | | `-{beam.smp}(12669)| | `-pstree(13702)…$ heart: Fri Aug 23 20:36:25 2013: heart-beat time-out, no activity for 65 secondsheart_beat_kill_pid = 27920我们看到 erl 重新被启动起来了。现在简单的分析下原理。 heart 由两部份组成:
- 外部程序: heart
- erlang port 模块: heart.erl
- erlang 虽然内置了很多 supervisor,可以保证 process 的高可靠性,但是假如 emulator 死亡了,那这一切都消失了,erlang 只能靠 heart 来重新启动。
- 热部署的时候 release_handling 需要重新启动 emulator 的时候也必须借助外部程序,即 heart 来辅助。
[root@Betty coredump_test]# export HEART_COMMAND="erl -heart" -- 执行 heart 重启业务时执行的命令[root@Betty coredump_test]# erl -heart -- 启动 heart 功能heart_beat_kill_pid = 4904Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]Eshell V6.0 (abort with ^G)1> 1> os:getpid()."4904"2> [1]+ Stopped erl -heart -- 这里通过 Ctrl + Z 挂起[root@Betty coredump_test]# [root@Betty coredump_test]# [root@Betty coredump_test]# heart: Mon Mar 7 15:09:49 2016: heart-beat time-out, no activity for 65 seconds -- 65 秒后输出该打印信息heart_beat_kill_pid = 5066[1]+ 已杀死 erl -heart[root@Betty coredump_test]#另一个窗口
[root@Betty ~]# ps ajxf PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND ... 1890 3925 3925 3925 ? -1 Ss 0 0:00 \_ sshd: root@pts/1 3925 3927 3927 3927 pts/1 4904 Ss 0 0:00 \_ -bash 3927 4904 4904 3927 pts/1 4904 Sl+ 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /us 4904 4926 4926 4926 ? -1 Ss 0 0:00 \_ heart -pid 4904...[root@Betty ~]# pstree -pinit(1)─┬─abrtd(2369) ... ├─sshd(1890)─┬─sshd(3465)─┬─bash(4576) │ │ └─bash(14788)───pstree(5058) │ └─sshd(3925)───bash(3927)───beam.smp(4904)─┬─heart(4926) │ ├─{beam.smp}(4908) │ ├─{beam.smp}(4909) │ ├─{beam.smp}(4910) │ ├─{beam.smp}(4911) │ ├─{beam.smp}(4912) │ ├─{beam.smp}(4913) │ ├─{beam.smp}(4914) │ ├─{beam.smp}(4915) │ ├─{beam.smp}(4916) │ ├─{beam.smp}(4917) │ ├─{beam.smp}(4918) │ ├─{beam.smp}(4919) │ ├─{beam.smp}(4920) │ ├─{beam.smp}(4921) │ ├─{beam.smp}(4922) │ ├─{beam.smp}(4923) │ ├─{beam.smp}(4924) │ └─{beam.smp}(4925) ...[root@Betty ~]# ps ajxf|grep heart14788 5061 5060 14788 pts/3 5060 S+ 0 0:00 | | \_ grep heart 3927 4904 4904 3927 pts/1 3927 Tl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 4904 4926 4926 4926 ? -1 Ss 0 0:00 \_ heart -pid 4904[root@Betty ~]# [root@Betty ~]# ps ajxf|grep heart -- 65 秒后输出内容发生了变化14788 5096 5095 14788 pts/3 5095 S+ 0 0:00 | | \_ grep heart 1 4926 4926 4926 ? -1 Ss 0 0:00 heart -pid 4904 4926 5066 4926 4926 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5066 5088 5088 5088 ? -1 Ss 0 0:00 \_ heart -pid 5066[root@Betty ~]#【验证手动杀死各类进程的效果】 后台启动 erlang 进程
[root@Betty ~]# erl -heart -detached可以看到,此时创建了两个进程:erlang 业务进程 + heart 子进程
[root@Betty ~]# ps ajxf|grep heart|grep -v grep 1 5505 5504 5504 ? -1 Sl 0 0:00 /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart -noshell -noinput 5505 5524 5524 5524 ? -1 Ss 0 0:00 \_ heart -pid 5505[root@Betty ~]#杀死 erlang 业务进程后,能看到其 heart 子进程会重新创建 erlang 业务进程和新 heart 子进程。
[root@Betty ~]# kill -9 5505[root@Betty ~]# ps ajxf|grep heart|grep -v grep 1 5524 5524 5524 ? -1 Ss 0 0:00 heart -pid 5505 5524 5534 5524 5524 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5534 5556 5556 5556 ? -1 Ss 0 0:00 \_ heart -pid 5534[root@Betty ~]#再一次杀死 erlang 业务进程,可以看到 erlang 进程的父 heart 进程也消失了,而 erlang 进程的 heart 子进程会重新启动 erlang 业务进程和其 heart 子进程。
[root@Betty ~]# kill -9 5534[root@Betty ~]# [root@Betty ~]# ps ajxf|grep heart|grep -v grep 1 5556 5556 5556 ? -1 Ss 0 0:00 heart -pid 5534 5556 5568 5556 5556 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5568 5590 5590 5590 ? -1 Ss 0 0:00 \_ heart -pid 5568[root@Betty ~]#杀死 erlang 业务进程的父 heart 进程,可以看到对 erlang 业务进程和其子 heart 进程无任何影响。
[root@Betty ~]# [root@Betty ~]# kill -9 5556[root@Betty ~]# ps ajxf|grep heart|grep -v grep 1 5568 5556 5556 ? -1 Sl 0 0:00 /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5568 5590 5590 5590 ? -1 Ss 0 0:00 \_ heart -pid 5568[root@Betty ~]#再一次杀死 erlang 业务进程,能看到其 heart 子进程会重新创建 erlang 业务进程和新 heart 子进程。
[root@Betty ~]# [root@Betty ~]# kill -9 5568[root@Betty ~]# ps ajxf|grep heart|grep -v grep 1 5590 5590 5590 ? -1 Ss 0 0:00 heart -pid 5568 5590 5605 5590 5590 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5605 5627 5627 5627 ? -1 Ss 0 0:00 \_ heart -pid 5605[root@Betty ~]#杀死 erlang 业务进程的 heart 子进程,可以看到 erlang 业务进程也随之消失了。
[root@Betty ~]# [root@Betty ~]# kill -9 5627[root@Betty ~]# ps ajxf|grep heart|grep -v grep[root@Betty ~]#【验证通过不同信号杀死进程的效果】 以下内容均在窗口 1 中观察
初次启动[root@Betty ~]# erl -heartheart_beat_kill_pid = 5668Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]Eshell V6.0 (abort with ^G)1> (此时在窗口 2 中 kill -9 xxx)1>1> 已杀死heart: Mon Mar 7 15:48:42 2016: Erlang has closed.heart_beat_kill_pid = 5697[root@Betty ~]# (此时在窗口 2 中再次 kill -9 xxx )此时能看到如下一行信息输出,这是由创建 erlang 业务进程的 heart 父进程输出的,下同。[root@Betty ~]# heart: Mon Mar 7 15:49:05 2016: Executed "erl -heart" -> 9. Terminating.heart: Mon Mar 7 15:49:05 2016: Erlang has closed.heart_beat_kill_pid = 5725[root@Betty ~]# [root@Betty ~]# [root@Betty ~]# heart: Mon Mar 7 15:49:23 2016: Executed "erl -heart" -> 9. Terminating.heart: Mon Mar 7 15:49:23 2016: Erlang has closed.heart_beat_kill_pid = 5754[root@Betty ~]# (此时在窗口 2 中 kill -15 xxx )[root@Betty ~]# heart: Mon Mar 7 15:49:56 2016: Executed "erl -heart" -> 15. Terminating.heart: Mon Mar 7 15:49:56 2016: Erlang has closed.heart_beat_kill_pid = 5783[root@Betty ~]# (此时在窗口 2 中 kill -SIGUSR1 xxx )此时能看到,有生成 crash dump 文件的信息,并最后通过 -9 信号杀死 erlang 业务进程(没有找到生成的 crash dump 文件)。[root@Betty ~]# heart: Mon Mar 7 15:50:42 2016: Erlang is crashing .. (waiting for crash dump file)heart: Mon Mar 7 15:50:42 2016: Executed "erl -heart" -> 9. Terminating.heart_beat_kill_pid = 5816[root@Betty ~]# 再来一次,仍旧没找到 crash dump 文件[root@Betty ~]# [root@Betty ~]# heart: Mon Mar 7 15:52:58 2016: Erlang is crashing .. (waiting for crash dump file)heart: Mon Mar 7 15:52:58 2016: Executed "erl -heart" -> 9. Terminating.heart_beat_kill_pid = 5851[root@Betty ~]# (此时在窗口 2 中 kill -SIGUSR2 xxx )[root@Betty ~]# heart: Mon Mar 7 15:54:17 2016: Executed "erl -heart" -> 12. Terminating.heart: Mon Mar 7 15:54:17 2016: Erlang has closed.heart_beat_kill_pid = 5884[root@Betty ~]# (此时在窗口 2 中 kill -SIGSEGV xxx )可以看到,此时在当前目录生成了操作系统的 core 文件。[root@Betty ~]# heart: Mon Mar 7 15:55:26 2016: Executed "erl -heart" -> 139. Terminating.heart: Mon Mar 7 15:55:26 2016: Erlang has closed.heart_beat_kill_pid = 5915[root@Betty ~]# [root@Betty ~]# ll总用量 11132...-rw------- 1 root root 107769856 3月 7 15:55 core.5884...[root@Betty ~]#(此时在窗口 2 中 kill -SIGABRT xxx )可以看到,此时在当前目录同样生成了操作系统的 core 文件。[root@Betty ~]# heart: Mon Mar 7 15:56:59 2016: Executed "erl -heart" -> 134. Terminating.heart: Mon Mar 7 15:56:59 2016: Erlang has closed.heart_beat_kill_pid = 5949[root@Betty ~]# [root@Betty ~]# ll总用量 21880...-rw------- 1 root root 107769856 3月 7 15:55 core.5884-rw------- 1 root root 107769856 3月 7 15:56 core.5915...[root@Betty ~]# (此时在窗口 2 中 killall heart)此时可以看到生成了 erl_crash.dump 文件[root@Betty ~]# Crash dump was written to: erl_crash.dumpKernel pid terminated (heart) ()[root@Betty ~]# [root@Betty ~]# ll总用量 780..-rw-r----- 1 root root 396922 3月 7 16:10 erl_crash.dump...以下内容均在窗口 2 中观察
[root@Betty upu]# ps ajxf|grep heart|grep -v grep 3927 5668 5668 3927 pts/1 5668 Sl+ 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5668 5690 5690 5690 ? -1 Ss 0 0:00 \_ heart -pid 5668[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR111) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+338) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+843) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+1348) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-1253) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-758) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-263) SIGRTMAX-1 64) SIGRTMAX[root@Betty upu]# [root@Betty upu]# kill -9 5668[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# ps ajxf|grep heart|grep -v grep 1 5690 5690 5690 ? -1 Ss 0 0:00 heart -pid 5668 5690 5697 5690 5690 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5697 5719 5719 5719 ? -1 Ss 0 0:00 \_ heart -pid 5697[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# kill -9 5697[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# ps ajxf|grep heart|grep -v grep 1 5719 5719 5719 ? -1 Ss 0 0:00 heart -pid 5697 5719 5725 5719 5719 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5725 5747 5747 5747 ? -1 Ss 0 0:00 \_ heart -pid 5725[root@Betty upu]# [root@Betty upu]# kill -9 5725[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# ps ajxf|grep heart|grep -v grep 1 5747 5747 5747 ? -1 Ss 0 0:00 heart -pid 5725 5747 5754 5747 5747 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5754 5776 5776 5776 ? -1 Ss 0 0:00 \_ heart -pid 5754[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# kill -15 5754[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# ps ajxf|grep heart|grep -v grep 1 5776 5776 5776 ? -1 Ss 0 0:00 heart -pid 5754 5776 5783 5776 5776 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5783 5805 5805 5805 ? -1 Ss 0 0:00 \_ heart -pid 5783[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# kill -SIGUSR1 5783[root@Betty upu]# [root@Betty upu]# ps ajxf|grep heart|grep -v grep 1 5805 5805 5805 ? -1 Ss 0 0:00 heart -pid 5783 5805 5816 5805 5805 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5816 5838 5838 5838 ? -1 Ss 0 0:00 \_ heart -pid 5816[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# kill -SIGUSR1 5816[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# ps ajxf|grep heart|grep -v grep 1 5838 5838 5838 ? -1 Ss 0 0:00 heart -pid 5816 5838 5851 5838 5838 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5851 5873 5873 5873 ? -1 Ss 0 0:00 \_ heart -pid 5851[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# kill -SIGUSR2 5851[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# ps ajxf|grep heart|grep -v grep 1 5873 5873 5873 ? -1 Ss 0 0:00 heart -pid 5851 5873 5884 5873 5873 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5884 5906 5906 5906 ? -1 Ss 0 0:00 \_ heart -pid 5884[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# kill -SIGSEGV 5884[root@Betty upu]# [root@Betty upu]# ps ajxf|grep heart|grep -v grep 1 5906 5906 5906 ? -1 Ss 0 0:00 heart -pid 5884 5906 5915 5906 5906 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5915 5938 5938 5938 ? -1 Ss 0 0:00 \_ heart -pid 5915[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# kill -SIGABRT 5915[root@Betty upu]# [root@Betty upu]# ps ajxf|grep heart|grep -v grep 1 5938 5938 5938 ? -1 Ss 0 0:00 heart -pid 5915 5938 5949 5938 5938 ? -1 Sl 0 0:00 \_ /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -heart 5949 5971 5971 5971 ? -1 Ss 0 0:00 \_ heart -pid 5949[root@Betty upu]# [root@Betty upu]# [root@Betty upu]# killall heart
补充: 很久之前写过一篇文章,《》,其中的 keepalive 功能和本文中 erlang 的 heart 功能类似,差别在于 erlang 中的实现为,业务作为父进程,heart 作为子进程;而我之前那篇文章中的实现是倒过来的~~