1. 程式人生 > >Erlang虛擬機器基礎設施dtrace探測點介紹和使用

Erlang虛擬機器基礎設施dtrace探測點介紹和使用

最新的Erlang虛擬機器(R15B01)很大的一個改進就是加入了對dtrace探測點的支援了, 具體參見這裡, 主要目標是方便在生產實踐中定位複雜的效能問題。

目前Erlang的虛擬機器的探測點支援Linux的systemtap和freebsd的dtrace,我們剛好能夠享受的到。

作者Scott Lystig Fritchie在去年的euc中做了個很有意思的報告,參見這裡,該PPT很詳細的介紹了利用dtrace的探測點可以觀察到erlang的行為如下:

Processes: spawn, exit, hibernate, scheduled, …
Messages: send, queued, received, exit signals
Memory: GC minor & major, proc heap grow & shrink
Data copy: within heap, across heaps
Function calls: function & BIF & NIF, entry & return
Network distribution: monitor, port busy, output events
Ports: open, command, control, busy/not busy
Drivers: callback API 100% instrumented
efile_drv.c fifile I/O driver: 100% instrumented

這些探測點基本上屬於IO,程序排程,訊息傳送,driver等虛擬機器最底層的和作業系統耦合的部分,對效能的影響巨大。

目前Erlang自己的基礎設施並沒有涵蓋到這部分內容,如dbg,trace機制都無法瞭解到這些資料,導致在大型的集群系統裡面一旦發現效能問題無法很好的展開調查,所以這些探測點剛好填補了空白。

目前這些dtrace probe點是用static marker實現的,細節可以參看這裡 和 這裡,好處是不用這些特性的時候,不會對效能有任何的影響,只需要為使用付代價。目前支援這種機制的語言和系統有java,python,mysql,pgsql等,可見威力強勁。

好拉,廢話少說,我們來體驗下。

下載最新的otp, 目前是R15B01, 簡單的執行:

$ uname -r
2.6.32-131.21.1.tb477.el6.x86_64
$ git clone git://github.com/erlang/otp.git
$ cd otp

原始碼目錄下有個README.systemtap.md,會簡單的教你如何編譯和使用。

由於我們用的是RHEL 6U2, 在編譯之前你要確保你的systemtap和systemtap-sdt-devel已經安裝, 直接執行

yum -y install systemtap systemtap-sdt-devel

就搞定了,實在搞不懂的可以參考作者的這篇教程

我簡單的演示下:

$ ./otp_build autoconf
$ ./configure --with-dynamic-trace=systemtap
$ make
...

#出錯

由於這個版本的實現存在bug, 在實現DTRACE_GLOBAL_CALL功能的時候,沒搞好細節,編譯的時候會出錯:
beam_emu.c:L1562, L1578, L1592,簡單的把這幾行註釋掉,繼續編譯就好了,就是global函式的trace功能不能使用而已,無傷大雅。

好了,如果不出意外,帶dtrace功能的beam就生成了,我們如何確認呢?

$ stap -L 'process("bin/x86_64-unknown-linux-gnu/beam").mark("*")'
process("bin/x86_64-unknown-linux-gnu/beam").mark("aio_pool__add") $arg1:long $arg2:long
process("bin/x86_64-unknown-linux-gnu/beam").mark("aio_pool__get") $arg1:long $arg2:long
process("bin/x86_64-unknown-linux-gnu/beam").mark("bif__entry") $arg1:long $arg2:long
process("bin/x86_64-unknown-linux-gnu/beam").mark("bif__return") $arg1:long $arg2:long
process("bin/x86_64-unknown-linux-gnu/beam").mark("copy__object") $arg1:long $arg2:long
...
#或者
$ bin/erl
Erlang R16B (erts-5.10) 1 [64-bit] [smp:16:16] [async-threads:0] [hipe] [kernel-poll:false] [systemtap]
 
Eshell V5.10  (abort with ^G)
1> %%在shell的能力裡面看到 [systemtap]

這樣就說明DTRACE的功能已經啟用,接著演示下如何使用.
該發行版帶了不少的例子程式位於:

$ ls lib/runtime_tools/examples/*.systemtap
lib/runtime_tools/examples/dist.systemtap                lib/runtime_tools/examples/messages.systemtap
lib/runtime_tools/examples/driver1.systemtap             lib/runtime_tools/examples/port1.systemtap
lib/runtime_tools/examples/efile_drv.systemtap           lib/runtime_tools/examples/process-scheduling.systemtap
lib/runtime_tools/examples/function-calls.systemtap      lib/runtime_tools/examples/spawn-exit.systemtap
lib/runtime_tools/examples/garbage-collection.systemtap  lib/runtime_tools/examples/user-probe.systemtap
lib/runtime_tools/examples/memory1.systemtap
#執行我們的指令碼,開始體驗
$ PATH=bin/x86_64-unknown-linux-gnu/:$PATH sudo stap lib/runtime_tools/examples/spawn-exit.systemtap
pid  mfa otp_ring0:start/2
pid  mfa erlang:apply/2
pid  mfa erlang:apply/2
pid  mfa erlang:apply/2
pid  mfa heart:init/2
pid  reason normal
pid  mfa proc_lib:init_p/5
pid  mfa erlang:apply/2
pid  mfa application_controller:init_starter/4
pid  mfa proc_lib:init_p/5
pid  mfa application_master:start_it/4
pid  mfa proc_lib:init_p/5
pid  mfa proc_lib:init_p/5
pid  mfa proc_lib:init_p/5
pid  mfa erlang:apply/2
pid  mfa erlang:apply/2
pid  mfa proc_lib:init_p/5
pid  mfa proc_lib:init_p/5
pid  mfa proc_lib:init_p/5
pid  mfa erlang:apply/2
pid  mfa proc_lib:init_p/5
pid  mfa erlang:apply/2
pid  mfa proc_lib:init_p/5
pid  mfa user_drv:server/2
pid  mfa group:server/3
pid  mfa group:server/3
pid  mfa erlang:apply/2
pid  mfa proc_lib:init_p/5
pid  mfa proc_lib:init_p/5
pid  reason on_load_done
pid  reason normal
sender  -> pid  reason normal
pid  mfa application_controller:init_starter/4
pid  reason normal
sender  -> pid  reason normal
pid  mfa erlang:apply/2
pid  reason enoent
sender  -> pid  reason enoent
pid  mfa erlang:apply/2
pid  reason enoent
sender  -> pid  reason enoent
pid  reason normal
sender  -> pid  reason normal
pid  mfa erlang:apply/2
pid  mfa erlang:apply/2

在另外一個shell裡面執行我們的erlang虛擬機器,模擬我們的應用系統,我們就可以看到上面的輸出。

$ bin/erl -smp disable
Erlang R16B (erts-5.10) 1 [64-bit] [async-threads:0] [hipe] [kernel-poll:false] [systemtap]
 
Eshell V5.10  (abort with ^G)
1> os:getpid().
"7149"

這裡要注意的是我們使用的-smp disable引數,使用的是beam的plain版本,它的程序名是beam

$ pstree -p |grep 7149
|-sshd(1847)-+-sshd(7081)—sshd(7101)—bash(7102)-+-beam(7149)

如果使用多處理器版本,那麼程序名是beam.smp,需要修改相應的systemtap腳本里面的程序名。

小結:systemtap無敵,erlang與時俱進!

祝玩得開心!