1. 程式人生 > >系統技術非業餘研究 » seq_trace叢集訊息鏈跟蹤利器

系統技術非業餘研究 » seq_trace叢集訊息鏈跟蹤利器

做過網路叢集伺服器的的同學都知道,叢集服務通常由不同的伺服器組成,這些不同角色的伺服器組合在一起共同完成了特定的服務。一個服務通常需要一個協調者,和不同的工作者。 協調者負責派發任務,接收工作者的完成情況,最終回饋給使用者。舉個例子來講,撥打電話:首先需要確認你的號碼是在有效的,同時還要看下你的帳號裡面有錢不,還要看下你撥打的電話號碼是不是由許可權,電話打的時候需要扣錢,等等。 這些服務中間的任何一個環節出問題了,服務就不正常了。那麼我們在服務出問題的時候,如何定位問題呢?通常的辦法是打日誌,在所有的參與服務的節點上開啟日誌記錄,之後到所有的節點上收集日誌,集中分析日誌,相當的麻煩。

這時候seq_trace來救助了,seq_trace的目標就是能夠跟蹤一條訊息經過的所有環節,最終把路徑展現給使用者。
鋪墊材料:
seq_trace工作原理,請參考

這裡
ttb對seq_trace的支援參考這裡
tdbg對seq_trace的支援參考這裡

我們來設計個案例來演示下這個過程:
該服務功能是對一個列表進行消重,翻倍,求和,這3個動作分別由不同的角色做。
叢集共有3個節點提供服務, [email protected], [email protected], [email protected],角色設計上比較簡單:y先上面提供消重服務,z提供翻倍, x負責最後的求和。

流程是這樣的:
1. 使用者給x發列表.
2. x收到列表後,轉發發給y.
3. y收到後先進行列表消重, 再發給z.
4. z收到後進行列表翻倍, 然後回給y.
5. y收到回給x.
6. x收到後進行最後的加和,回給使用者。

我們首先看下我們的測試程式碼:

$ cat test.erl
-module(test).
-export([start/0, stop/1, demo/2]).

x_fun(Y)->
    receive 
	{From, L} -> 
	    Y ! {self(), L},
	    receive 
		{Y, L1} ->
		    From ! {self(), lists:sum(L1)}
	    end,
	    x_fun(Y);
	quit ->
	    ok
    end.


y_fun(Z)->
    receive 
	{From, L} ->
	    Z ! {self(), sets:to_list(sets:from_list(L))},
	    receive 
		{Z, L1}->
		    From ! {self(), L1}
	    end,
	    y_fun(Z);
	quit ->
	    ok
    end.

z_fun()->
    receive 
	{From, L} ->
	    From ! {self(), [2 * R || R <-L]},
	    z_fun();
	quit ->
	    ok
    end.

start()->
    pong = net_adm:ping('
[email protected]
'), pong = net_adm:ping('[email protected]'), pong = net_adm:ping('[email protected]'), Z = spawn('[email protected]', fun() -> global:register_name(z_p, self()), z_fun() end), Y = spawn('[email protected]', fun() -> global:register_name(y_p, self()), y_fun(Z) end), X = spawn('[email protected]', fun() -> global:register_name(x_p, self()), x_fun(Y) end), global:sync(), {X, Y, Z}. stop({X,Y,Z})-> [P ! quit || P <- [X,Y,Z]], ok. demo(L, {X,_,_}) when is_list(L) -> X ! {self(), L}, %% io:format("sent ~p~n", [L]), receive {X, _Res} -> %% io:format("got ~p~n",[_Res]), _Res end.

我們首先準備下叢集環境,開3個節點Erlang節點:

#terminal 1
$ erl -name [email protected]
Erlang R14B04 (erts-5.8.5)  [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)
([email protected])1> 

#terminal 2
$ erl -name [email protected]
Erlang R14B04 (erts-5.8.5)  [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)
([email protected])1> 

#terminal 3
$ erl -name [email protected]
Erlang R14B04 (erts-5.8.5)  [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)
([email protected])1> 

好了,現在開始我們的測試:

$ erlc test.erl
$ erl -name [email protected]
Erlang R14B04 (erts-5.8.5)  [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)
([email protected])1> Ref=test:start().
{<6584.42.0>,<6585.42.0>,<6586.42.0>}
([email protected])2> test:demo([1,1,3,5],Ref).
18
([email protected])3> nodes().
['[email protected]','[email protected]','[email protected]']  
([email protected])4> global:registered_names().
[z_p,y_p,x_p]
([email protected])5> test:stop(Ref).          
ok

我們看到結果算出來了,參與的節點x,y,z也都看到了,服務的程序名z_p,y_p,x_p也都是正常的,可是我們無法看到訊息是如何在叢集裡面流通的。

神奇的ttb加上seq_trace可以幫我們的忙。原理是用ttb在呼叫test:demo的時候,給我們的程序設定個token,demo呼叫把列表通過訊息傳遞給X的時候,seq_trace會在後臺把這個token順著服務鏈條傳遞出去,最終訊息回到我們手裡,我們就知道這個訊息所走過的路徑,包括節點間的路徑。

我們來演示下如果操作:

$ erl -name [email protected]
Erlang R14B04 (erts-5.8.5)  [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)
([email protected])1> Ref=test:start(). 
{<6584.60.0>,<6585.60.0>,<6586.60.0>}
([email protected])2> 
([email protected])2> nodes().
['[email protected]','[email protected]','[email protected]']
([email protected])3> global:registered_names().
[z_p,y_p,x_p]
([email protected])5> ttb:tracer(all).
{ok,['[email protected]','[email protected]','[email protected]',
     '[email protected]']}
([email protected])6> ttb:p(self(),call).
{ok,[{<0.37.0>,[{matched,'[email protected]',1}]}]}
([email protected])7> ttb:tp(test,demo,ttb:seq_trigger_ms()).
{ok,[{matched,'[email protected]',1},
     {matched,'[email protected]',1},
     {matched,'[email protected]',1},
     {matched,'[email protected]',1},
     {saved,1}]}
([email protected])8> test:demo([1,1,3,5],Ref),seq_trace:reset_trace().
true
([email protected])9> ttb:stop([fetch]).
Stored logs in /Users/yufeng/ttb_upload-20111003-012347
stopped

到現在為止,日誌已經儲存下來了, 檔名是ttb_upload-20111003-012347, 我們先文字方式格式化下訊息流:

([email protected])10> ttb:format("ttb_upload-20111003-012347").
({<0.37.0>,{erlang,apply,2},'[email protected]'}) call test:demo([1,1,3,5],{<6584.60.0>,<6585.60.0>,<6586.60.0>})
SeqTrace {1317,576219,213176} [0]: ({<0.37.0>,{erlang,apply,2},'[email protected]'}) {<6584.60.0>,
                                                {global,z_p},
                                                '[email protected]'} ! {<0.37.0>,
                                                                  [1,1,3,5]} [Serial: {0,
                                                                                       1}]
SeqTrace {1317,576219,213398} [0]: ({<6584.60.0>,{global,z_p},'[email protected]'}) << {<0.37.0>,[1,1,3,5]} [Serial: {0,
                                                                             1}, From: {<0.37.0>,
                                                                                        {erlang,
                                                                                         apply,
                                                                                         2},
                                                                                        '[email protected]'}]
SeqTrace {1317,576219,213409} [0]: ({<6584.60.0>,{global,z_p},'[email protected]'}) {<6585.60.0>,
                                            {global,y_p},
                                            '[email protected]'} ! {<6584.60.0>,
                                                              [1,1,3,5]} [Serial: {1,
                                                                                   2}]
SeqTrace {1317,576219,213601} [0]: ({<6585.60.0>,{global,y_p},'[email protected]'}) << {<6584.60.0>,[1,1,3,5]} [Serial: {1,
                                                                                2}, From: {<6584.60.0>,
                                                                                           {global,
                                                                                            z_p},
                                                                                           '[email protected]'}]
SeqTrace {1317,576219,213640} [0]: ({<6585.60.0>,{global,y_p},'[email protected]'}) {<6586.60.0>,
                                            {global,x_p},
                                            '[email protected]'} ! {<6585.60.0>,
                                                              [3,5,1]} [Serial: {2,
                                                                                 3}]
SeqTrace {1317,576219,213814} [0]: ({<6586.60.0>,{global,x_p},'[email protected]'}) << {<6585.60.0>,[3,5,1]} [Serial: {2,
                                                                              3}, From: {<6585.60.0>,
                                                                                         {global,
                                                                                          y_p},
                                                                                         '[email protected]'}]
SeqTrace {1317,576219,213825} [0]: ({<6586.60.0>,{global,x_p},'[email protected]'}) {<6585.60.0>,
                                            {global,y_p},
                                            '[email protected]'} ! {<6586.60.0>,
                                                              [6,10,2]} [Serial: {3,
                                                                                  4}]
SeqTrace {1317,576219,213929} [0]: ({<6585.60.0>,{global,y_p},'[email protected]'}) << {<6586.60.0>,[6,10,2]} [Serial: {3,
                                                                               4}, From: {<6586.60.0>,
                                                                                          {global,
                                                                                           x_p},
                                                                                          '[email protected]'}]
SeqTrace {1317,576219,213935} [0]: ({<6585.60.0>,{global,y_p},'[email protected]'}) {<6584.60.0>,
                                            {global,z_p},
                                            '[email protected]'} ! {<6585.60.0>,
                                                              [6,10,2]} [Serial: {4,
                                                                                  5}]
SeqTrace {1317,576219,214054} [0]: ({<6584.60.0>,{global,z_p},'[email protected]'}) << {<6585.60.0>,[6,10,2]} [Serial: {4,
                                                                               5}, From: {<6585.60.0>,
                                                                                          {global,
                                                                                           y_p},
                                                                                          '[email protected]'}]
SeqTrace {1317,576219,214062} [0]: ({<6584.60.0>,{global,z_p},'[email protected]'}) {<0.37.0>,
                                            {erlang,apply,2},
                                            '[email protected]'} ! {<6584.60.0>,
                                                                 18} [Serial: {5,
                                                                               6}]
SeqTrace {1317,576219,214241} [0]: ({<0.37.0>,{erlang,apply,2},'[email protected]'}) << {<6584.60.0>,18} [Serial: {5,
                                                                             6}, From: {<6584.60.0>,
                                                                                        {global,
                                                                                         z_p},
                                                                                        '[email protected]'}]
ok
([email protected])11> 

透過訊息互動的文字,我們可以看到訊息在流動,整個過程都在掌握中,如果哪個環節出問題,也一目瞭然。

我們還可以用圖形方式顯示路徑,神奇的et可以幫忙,et可以參考這裡

演示下這個功能:

([email protected])12> ttb:format("ttb_upload-20111003-012347",[{handler,et}]).

圖形化得路徑看起來就更清楚了:

結論: seq_trace+ttb在跟蹤訊息方面真是無敵!

祝大家玩得開心!

Post Footer automatically generated by wp-posturl plugin for wordpress.

No related posts.

相關推薦

系統技術業餘研究 » seq_trace叢集訊息跟蹤利器

做過網路叢集伺服器的的同學都知道,叢集服務通常由不同的伺服器組成,這些不同角色的伺服器組合在一起共同完成了特定的服務。一個服務通常需要一個協調者,和不同的工作者。 協調者負責派發任務,接收工作者的完成情況,最終回饋給使用者。舉個例子來講,撥打電話:首先需要確認你的號碼是在有效的,同時還要看下你的帳

系統技術業餘研究 » Erlang叢集RPC通道擁塞問題及解決方案

Erlang的叢集預設情況下是全聯通的,也就是當一個節點加入叢集的時候,介紹人會推薦叢集裡面所有的節點主動來和新加入的節點建立聯絡, 效果如下圖: 我們這次不講如何避免全聯通而是來講這個節點間通道的問題。 我們知道erlang的訊息傳送是透明的,只要呼叫Pid!Msg, 虛擬機器和叢集的基礎設

系統技術業餘研究 » erlsnoop erlang訊息監聽器(除錯erlang網路程式利器,支援最新的R13B04)

由於R13B以後, Erlang的分佈協議修改了格式, 添加了Atom Cache, erlsnoop在新版本下無法使用, 我特地打了patch, 使得它支援最新的版本,原始碼在附件中下載. 在erlang的郵件列表上看到: Have you tried putting a snoop to se

系統技術業餘研究 » Erlang叢集未公開特性:IP網段限制

Erlang叢集二個節點之間的通訊是通過一個tcp長連線進行的,而且是全聯通的,一旦cookie論證通過了,任何一個節點就獲得全叢集的訪問權,可以參考Erlang分佈的核心技術淺析 。erlang的這個授權模式特定搞的這麼簡單,但是在實際使用中還是有安全性的問題。我們退而求其次,來個IP網段限制,

系統技術業餘研究 » Erlang叢集自動化新增節點指南

Erlang的叢集是由各個節點組成的,一個節點有一個名字來標識,而不管這個節點在網路的物理位置,所以在部署Erlang叢集的時候就很方便。只要在叢集裡新啟動一個節點,給個相對固定的引導的節點,讓新節點和這個引導節點取得聯絡,由引導節點把新節點介紹入叢集就OK了。 在實踐中,新採購的機器上通常配置好

系統技術業餘研究 » Erlang叢集全聯通問題及解決方案

Erlang的叢集預設情況下是全聯通的,也就是當一個節點加入叢集的時候,介紹人會推薦叢集裡面所有的節點主動來和新加入的節點建立聯絡, 效果如下圖: 具體點講那就是net_kernel模組負責節點間的通道的建立、檢查、斷開並提供monitor_node語義。 摘抄 http://www.erlan

系統技術業餘研究 » 調查伺服器響應時間的利器 tcprstat

我們在做伺服器程式的時候,經常要知道一個請求的響應時間,藉以優化或者定位問題。 通常的做法是在程式碼裡面加入日誌計算時間,這個方法有問題,時間不準確。因為資料從網絡卡到應用程式,從應用到網絡卡的時間沒有被計算在內。 而且這個時間隨著系統的負載有很大的變化。 那同學說,我wireshark, tcp

seq_trace叢集訊息跟蹤利器

做過網路叢集伺服器的的同學都知道,叢集服務通常由不同的伺服器組成,這些不同角色的伺服器組合在一起共同完成了特定的服務。一個服務通常需要一個協調者,和不同的工作者。 協調者負責派發任務,接收工作者的完成情況,最終回饋給使用者。舉個例子來講,撥打電話:首先需要確認你的號碼是在有效的,同時還要看下你的帳號裡面

系統技術業餘研究 » 叢集引入inet_dist_{listen,connect}_options更精細引數微調

Erlang 17.5版本引入了inet_dist_{listen,connect}_options,對於結點間的互聯socket可以有更精細的控制,RPC的時候效能可以微調: raimo/inet_tcp_dist-priority-option/OTP-12476: Document ke

系統技術業餘研究 » Erlang R15的記憶體delayed dealloc特性對訊息密集型程式的影響

在新的NUMA體系結構下,每個CPU都有自己的本地記憶體,如果要訪問其他CPU的記憶體,那算remote了,要走CPU之間的QPI通道,通常這樣速度會有40%的下降。 那麼對於多執行緒的程式來講,這個硬體的變化對軟體也有很大的影響。在多執行緒程式裡面,通常一個執行緒會為一個物件分配記憶體,然後把這

系統技術業餘研究 » gen_tcp呼叫程序收到{empty_out_q, Port}訊息奇怪行為分析

今天有同學在gmail裡面問了一個Erlang的問題,問題描述的非常好, 如下: 問題的背景是: 1、我開發了一個服務端程式,接收客戶端的連線。同一時刻會有多個客戶端來連線,連線後,接收客戶端請求後,再發送響應訊息,然後客戶端主動斷連。

系統技術業餘研究 » Shell Break模式下 ‘o’ 檢視port訊息

這是未公開的一個特性, 很方便檢視Erlang內部的port使用狀態. 演示下: [email protected]:~# erl Erlang R13B04 (erts-5.7.5) [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel

系統技術業餘研究 » R14A新增新指令優化Ref訊息的接收

Erlang的慣用法之一就是在訊息匹配的時候,如果需要唯一性,通常會通過make_ref搞個唯一的Ref來作為訊息的一部分來匹配。這個慣用法用在gen_server:call或者demonitor這樣的使用頻度很高的函式裡面。由於erlang的訊息匹配是再訊息佇列裡面挨個遍歷來匹配,特別是訊息佇列

系統技術業餘研究 » Erlang如何限制節點對叢集的訪問之net_kernel:allow

預設情況下Erlang的叢集訪問是全授權的,只要cookie認證過了後,新加入的節點可以訪問叢集裡面的任何機器,這給運維帶來很大風險。目前erlang有二種方法可以限制 1. IP網段限制,參看這裡 2. 節點名稱限制。這個是通過net_kernel:allow來實現的,參看: allow/1 L

系統技術業餘研究

ItPub寫的文章“2017 年度 DB-Engines 資料庫冠軍得主:PostgreSQL 封王!”, 點選 這裡 進一步閱讀 升的最快的幾個資料庫,我簡單的無責任點評: PG資料庫是很老的資料庫,不過這幾年冉冉升起,因為是學院派的,有很好的學術和智力的支援,一直以來在資料庫的體系結構,程式碼

系統技術業餘研究 » MySQL資料庫架構的演化觀察

MySQL資料庫架構的演化觀察 December 14th, 2017 Categories: 資料庫 Tags: mysql

系統技術業餘研究 » inet_dist_connect_options

Erlang 17.5版本引入了inet_dist_{listen,connect}_options,對於結點間的互聯socket可以有更精細的控制,RPC的時候效能可以微調: raimo/inet_tcp_dist-priority-option/OTP-12476: Document ke

系統技術業餘研究 » 推薦工作機會

最後更新時間:2014/11/28 請賜簡歷至:[email protected], 感謝您對加入我們公司有興趣,我們希望能早日和您共事。 以下幾個職位1年內有效,歡迎內部轉崗:
 資深資料工程師 公司:阿里(核心系統資料庫組) 工作地點:杭州(西溪園區) 崗位描述: 分析雲服務產生的海

系統技術業餘研究 » 新的工作和研究方向

和大家更新下: 做了將近8年資料庫後,我的工作和研究方向將會延伸到虛擬化和計算相關的雲服務,希望能夠和大家一起進步,Happy New Year! 預祝大家玩得開心! Post Footer automatically generated by wp-posturl plugin for w

系統技術業餘研究 » 2017升的最快的幾個資料庫無責任點評

ItPub寫的文章“2017 年度 DB-Engines 資料庫冠軍得主:PostgreSQL 封王!”, 點選 這裡 進一步閱讀 升的最快的幾個資料庫,我簡單的無責任點評: PG資料庫是很老的資料庫,不過這幾年冉冉升起,因為是學院派的,有很好的學術和智力的支援,一直以來在資料庫的體系結構,程式碼