seq_trace集群消息链跟踪利器

标签: Erlang探索 dbg et seq_trace ttb | 发表时间:2011-10-03 01:55 | 作者:Yu Feng KnightE
出处:http://blog.yufeng.info

原创文章,转载请注明: 转载自Erlang非业余研究

本文链接地址: seq_trace集群消息链跟踪利器

做过网络集群服务器的的同学都知道,集群服务通常由不同的服务器组成,这些不同角色的服务器组合在一起共同完成了特定的服务。一个服务通常需要一个协调者,和不同的工作者。 协调者负责派发任务,接收工作者的完成情况,最终回馈给用户。举个例子来讲,拨打电话:首先需要确认你的号码是在有效的,同时还要看下你的帐号里面有钱不,还要看下你拨打的电话号码是不是由权限,电话打的时候需要扣钱,等等。 这些服务中间的任何一个环节出问题了,服务就不正常了。那么我们在服务出问题的时候,如何定位问题呢?通常的办法是打日志,在所有的参与服务的节点上打开日志记录,之后到所有的节点上收集日志,集中分析日志,相当的麻烦。

这时候seq_trace来救助了,seq_trace的目标就是能够跟踪一条消息经过的所有环节,最终把路径展现给用户。
铺垫材料:
seq_trace工作原理,请参考这里
ttb对seq_trace的支持参考这里
tdbg对seq_trace的支持参考这里

我们来设计个案例来演示下这个过程:
该服务功能是对一个列表进行消重,翻倍,求和,这3个动作分别由不同的角色做。
集群共有3个节点提供服务, x@127.0.0.1, y@127.0.0.1, z@127.0.0.1,角色设计上比较简单: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('x@127.0.0.1'),
    pong = net_adm:ping('y@127.0.0.1'),
    pong = net_adm:ping('z@127.0.0.1'),
    Z = spawn('z@127.0.0.1', fun() -> global:register_name(z_p, self()), z_fun() end),
    Y = spawn('y@127.0.0.1', fun() -> global:register_name(y_p, self()), y_fun(Z) end),
    X = spawn('x@127.0.0.1', 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 x@127.0.0.1
Erlang R14B04 (erts-5.8.5) 1 [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)
(x@127.0.0.1)1> 

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

Eshell V5.8.5  (abort with ^G)
(y@127.0.0.1)1> 

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

Eshell V5.8.5  (abort with ^G)
(z@127.0.0.1)1>

好了,现在开始我们的测试:

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

Eshell V5.8.5  (abort with ^G)
(test@127.0.0.1)1> Ref=test:start().
{<6584.42.0>,<6585.42.0>,<6586.42.0>}
(test@127.0.0.1)2> test:demo([1,1,3,5],Ref).
18
(test@127.0.0.1)3> nodes().
['x@127.0.0.1','y@127.0.0.1','z@127.0.0.1']
(test@127.0.0.1)4> global:registered_names().
[z_p,y_p,x_p]
(test@127.0.0.1)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 test@127.0.0.1
Erlang R14B04 (erts-5.8.5) 1 [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

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

到现在为止,日志已经保存下来了, 文件名是ttb_upload-20111003-012347, 我们先文本方式格式化下消息流:

(test@127.0.0.1)10> ttb:format("ttb_upload-20111003-012347").
({<0.37.0>,{erlang,apply,2},'test@127.0.0.1'}) 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},'test@127.0.0.1'}) {<6584.60.0>,
                                                {global,z_p},
                                                'x@127.0.0.1'} ! {<0.37.0>,
                                                                  [1,1,3,5]} [Serial: {0,
                                                                                       1}]
SeqTrace {1317,576219,213398} [0]: ({<6584.60.0>,{global,z_p},'x@127.0.0.1'}) << {<0.37.0>,[1,1,3,5]} [Serial: {0,
                                                                             1}, From: {<0.37.0>,
                                                                                        {erlang,
                                                                                         apply,
                                                                                         2},
                                                                                        'test@127.0.0.1'}]
SeqTrace {1317,576219,213409} [0]: ({<6584.60.0>,{global,z_p},'x@127.0.0.1'}) {<6585.60.0>,
                                            {global,y_p},
                                            'y@127.0.0.1'} ! {<6584.60.0>,
                                                              [1,1,3,5]} [Serial: {1,
                                                                                   2}]
SeqTrace {1317,576219,213601} [0]: ({<6585.60.0>,{global,y_p},'y@127.0.0.1'}) << {<6584.60.0>,[1,1,3,5]} [Serial: {1,
                                                                                2}, From: {<6584.60.0>,
                                                                                           {global,
                                                                                            z_p},
                                                                                           'x@127.0.0.1'}]
SeqTrace {1317,576219,213640} [0]: ({<6585.60.0>,{global,y_p},'y@127.0.0.1'}) {<6586.60.0>,
                                            {global,x_p},
                                            'z@127.0.0.1'} ! {<6585.60.0>,
                                                              [3,5,1]} [Serial: {2,
                                                                                 3}]
SeqTrace {1317,576219,213814} [0]: ({<6586.60.0>,{global,x_p},'z@127.0.0.1'}) << {<6585.60.0>,[3,5,1]} [Serial: {2,
                                                                              3}, From: {<6585.60.0>,
                                                                                         {global,
                                                                                          y_p},
                                                                                         'y@127.0.0.1'}]
SeqTrace {1317,576219,213825} [0]: ({<6586.60.0>,{global,x_p},'z@127.0.0.1'}) {<6585.60.0>,
                                            {global,y_p},
                                            'y@127.0.0.1'} ! {<6586.60.0>,
                                                              [6,10,2]} [Serial: {3,
                                                                                  4}]
SeqTrace {1317,576219,213929} [0]: ({<6585.60.0>,{global,y_p},'y@127.0.0.1'}) << {<6586.60.0>,[6,10,2]} [Serial: {3,
                                                                               4}, From: {<6586.60.0>,
                                                                                          {global,
                                                                                           x_p},
                                                                                          'z@127.0.0.1'}]
SeqTrace {1317,576219,213935} [0]: ({<6585.60.0>,{global,y_p},'y@127.0.0.1'}) {<6584.60.0>,
                                            {global,z_p},
                                            'x@127.0.0.1'} ! {<6585.60.0>,
                                                              [6,10,2]} [Serial: {4,
                                                                                  5}]
SeqTrace {1317,576219,214054} [0]: ({<6584.60.0>,{global,z_p},'x@127.0.0.1'}) << {<6585.60.0>,[6,10,2]} [Serial: {4,
                                                                               5}, From: {<6585.60.0>,
                                                                                          {global,
                                                                                           y_p},
                                                                                          'y@127.0.0.1'}]
SeqTrace {1317,576219,214062} [0]: ({<6584.60.0>,{global,z_p},'x@127.0.0.1'}) {<0.37.0>,
                                            {erlang,apply,2},
                                            'test@127.0.0.1'} ! {<6584.60.0>,
                                                                 18} [Serial: {5,
                                                                               6}]
SeqTrace {1317,576219,214241} [0]: ({<0.37.0>,{erlang,apply,2},'test@127.0.0.1'}) << {<6584.60.0>,18} [Serial: {5,
                                                                             6}, From: {<6584.60.0>,
                                                                                        {global,
                                                                                         z_p},
                                                                                        'x@127.0.0.1'}]
ok
(test@127.0.0.1)11>

透过消息交互的文本,我们可以看到消息在流动,整个过程都在掌握中,如果哪个环节出问题,也一目了然。

我们还可以用图形方式显示路径,神奇的et可以帮忙,et可以参考这里

演示下这个功能:

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

图形化得路径看起来就更清楚了:

结论: seq_trace+ttb在跟踪消息方面真是无敌!

祝大家玩得开心!

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

相关 [seq trace 集群] 推荐:

oracle 打开trace,并分析trace

- - CSDN博客数据库推荐文章
2、跟踪session事件. 作者:huzia 发表于2014-4-22 17:33:55 原文链接. 阅读:71 评论:0 查看评论.

Oracle Trace文件的生成及查看

- - 数据库 - ITeye博客
1.Trace file简介: Trace file(追踪文件)是以trc为后续的文本文件,它记录了各种sql操作及所消耗的时间等,根据trace文件我们就可以了解哪些sql导致了系统的性能瓶颈,进而采取恰当的方式调优. 2.怎么生成trace file: 1. 首先用sqlplus登陆Oracle.

Wireshark抓包工具--TCP数据包seq ack等解读

- - CSDN博客互联网推荐文章
1、Wireshark的数据包详情窗口,如果是用中括号[]括起来的,表示注释,在数据包中不占字节. 2、在二进制窗口中,如“DD 3D”,表示两个字节,一个字节8位. 3、TCP数据包中,seq表示这个包的序号,注意,这个序号不是按1递增的,而是按tcp包内数据字节长度加上,如包内数据是21字节,而当前IP1发到IP2的包的seq是10的话,那下个IP1发到IP2的包的seq就是10+21=31.

Wireshark抓包工具--TCP数据包seq ack等解读

- - 研发管理 - ITeye博客
1、Wireshark的数据包详情窗口,如果是用中括号[]括起来的,表示注释,在数据包中不占字节. 2、在二进制窗口中,如“DD 3D”,表示两个字节,一个字节8位. 3、TCP数据包中,seq表示这个包的序号,注意,这个序号不是按1递增的,而是按tcp包内数据字节长度加上,如包内数据是21字节,而当前IP1发到IP2的包的seq是10的话,那下个IP1发到IP2的包的seq就是10+21=31.

Oracle EBS SQL Trace日志收集的方法

- - CSDN博客推荐文章
Raw Trace的收集方法. 打开Trace,Help > Diagnostics > Trace > Trace > Trace with Binds and Waits. Trace项代表的意思. 3.关闭Trace,Help > Diagnostics > Trace > Trace > No Trace.

pystack--python stack trace--让python打印线程栈信息

- - BlogJava-首页技术区
类似java中的jstack功能. https://pypi.python.org/pypi/pdbx/0.3.0 下载, 或者直接通过easyinstall安装. python scripts中, import pdbx; pdbx.enable_pystack(); 开启pystack功能. kill -30 pid , 就可以打印stack信息了. .

集群概念

- - 开源软件 - ITeye博客
        集群是一组协同工作的服务实体,用以提供比单一服务实体更具扩展性与可用性的服务平台. 在客户端看来,一个集群就象是一个服务实体,但 事实上集群由一组服务实体组成.         与单一服务实体相比较,集群提供了以下两个关键特性:.        1.可扩展性--集群的性能不限于单一的服务实体,新的服 务实体可以动态地加入到集群,从而增强集群的性能.

MYSQL集群介绍

- - 企业架构 - ITeye博客
MySQL Proxy是一个处于你的client端和MySQL server端之间的简单程序,它可以监测、分析或改变它们的通信. 它使用灵活,没有限制,常见的用途包括:负载平衡,故障、查询分析,查询过滤和修改等等. MySQL Proxy就是这么一个中间层代理,简单的说,MySQL Proxy就是一个连接池,负责将前台应用的连接请求转发给后台的数据库,并且通过使用lua脚本,可以实现复杂的连接控制和过滤,从而实现读写分离和负载平衡.

openfire3.9.1集群配置

- - 开源软件 - ITeye博客
1.CentOS-6.5-x86_64位服务器2台(虚拟机). 二: 安装CentOS-6.5-x86_64位服务器配置如下. 三:服务器安装完毕后配置:. [root@openfireS01 ~]# service network restart 或 # /etc/init.d/network restart.

hadoop2.2.0集群安装

- - CSDN博客云计算推荐文章
说明:目前官方hadoop2.2只有32位的版本,安装到64位肯定有问题,比如执行jar包会提示没有本地库. 如果要安装64位的,需要自己编译,这里不做阐述,一下都以32位说明. 环境:试验使用的虚拟机ubuntu12.04(32位). Jdk使用的1.7(1.6也可以). 网络配置好,相互可以ping通,java环境安装完毕.