Archive

Posts Tagged ‘port’

Erlang open_port极度影响性能的因素

November 22nd, 2011 4 comments

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

本文链接地址: Erlang open_port极度影响性能的因素

Erlang的port相当于系统的IO,打开了Erlang世界通往外界的通道,可以很方便的执行外部程序。 但是open_port的性能对整个系统来讲非常的重要,我就带领大家看看open_port影响性能的因素。

首先看下open_port的文档:

{spawn, Command}

Starts an external program. Command is the name of the external program which will be run. Command runs outside the Erlang work space unless an Erlang driver with the name Command is found. If found, that driver will be started. A driver runs in the Erlang workspace, which means that it is linked with the Erlang runtime system.

When starting external programs on Solaris, the system call vfork is used in preference to fork for performance reasons, although it has a history of being less robust. If there are problems with using vfork, setting the environment variable ERL_NO_VFORK to any value will cause fork to be used instead.

For external programs, the PATH is searched (or an equivalent method is used to find programs, depending on operating system). This is done by invoking the shell och certain platforms. The first space separated token of the command will be considered as the name of the executable (or driver). This (among other things) makes this option unsuitable for running programs having spaces in file or directory names. Use {spawn_executable, Command} instead if spaces in executable file names is desired.

open_port一个外部程序的时候流程大概是这样的:beam.smp先vfork, 子进程调用child_setup程序,做进一步的清理操作。 清理完成后才真正exec我们的外部程序。

再来看下open_port实现的代码:
Read more…

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

Erlang新添加选项 +zerts_de_busy_limit 控制节点间通讯的数据量

September 21st, 2010 No comments

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

本文链接地址: Erlang新添加选项 +zerts_de_busy_limit 控制节点间通讯的数据量

erlang节点间通信默认是通过tcp通道进行的, 而且每对节点间只有一个tcp链接,所有的rpc和内置的类似monitor这样的消息也都是通过这个通道进行的. 当数据量过大的时候, 系统就会发出 busy distribution port警告, 同时限制数据的吞吐. 这个值默认是128k.

现在可以通过 erl +zerts_de_busy_limit size 来修改这个值了.
Set the value of erts_de_busy_limit. Larger values can help prevent busy distribution port system messages.
The default limit is 128 kilobytes.

如果在system monitor的时候发现busy dist port, 不妨改大这个值, 这个值的下限是4k.

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

节点间通讯的通道微调

September 23rd, 2009 No comments

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

本文链接地址: 节点间通讯的通道微调

erlang节点间通讯是可以配置的,默认的是inet_tcp 。当2个节点要沟通的时候,net_kernel模块会负责建立必要的连接。 inet_tcp会调用底层的gen_tcp进行数据发送接受。 rpc或者节点间的消息交互都是通过这个port出去的。

在分布节点间,有时候会有大量的消息流动,那么所有的消息都是通过这个port出去 进来,所以这个port的性能极大的影响了节点间通讯的效率。那么有时候, 我们会想微调这个port的参数,根据业务的特点实现效率最大化,但是port如何得到呢?

node_port(Node)->
    {_, Owner}=lists:keyfind(owner, 1, element(2, net_kernel:node_info(Node))),
    hd([P|| P<-erlang:ports(), erlang:port_info(P, connected) == {connected,Owner}])

有了Port, 那么我们就可以设置tcp port的水位线,buffer等等。

inet:setopts(node_port('xx@nd-desktop'), [{high_watermark, 131072}]).

另外要注意 nodeup nodedown可能会换了个tcp链接 要注意重新获取。

还有另外一种方法,设置所有gen_tcp的行为, 比如以下方法:

erl -kernel inet_default_connect_options '[{sndbuf, 1048576}, {high_watermark, 131072}]'

但是这个影响面非常大, 影响到正常tcp的参数了。

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

Categories: Erlang探索 Tags: , ,

高強度的port(Pipe)的性能測試

September 13th, 2009 1 comment

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

本文链接地址: 高強度的port(Pipe)的性能測試

在我的項目里面, 很多運算logic是由外部的程序來計算的 那么消息先透過pipe發到外部程序,外部程序讀到消息, 處理消息, 寫消息, erlang程序讀到消息, 這條鏈路很長,而且涉及到pipe讀寫,上下文切換,這個開銷是很大的.但是具體是多少呢?

我設計了個這樣的ring. 每個ring有N個環組成, 每個環開個port. 當ring收到個數字的時候 如果數字不為0, 那么把這個數字發到外部成程序,這個外部程序echo回來數字,收到echo回來的消息后,把數字減1,繼續傳遞.當數字減少到0的時候 銷毀整個ring.
/* 注意這個數字非常重要 它影響了Erlang程序3個地方 1. epoll的句柄集大小 2. MAX_PORT 以及port的表格大小 3. open_port的時候 子進程關閉的文件句柄大小*/

root@nd-desktop:~/test#ulimit -n 1024
root@nd-desktop:~/test# cat pipe_ring.erl
-module(pipe_ring). 

-export([start/1]).
-export([make_relay/1, run/3]). 

make_relay(Next)->
    Port = open_port({spawn, "/bin/cat"}, [in, out, {line, 128}]),
    relay_loop(Next, Port). 

relay_loop(Next, Port) ->
    receive
        {Port, {data, {eol, Line}}} ->
            Next ! (list_to_integer(Line) - 1),
            relay_loop(Next, Port);
        K when is_integer(K) andalso K > 0 ->
            port_command(Port, integer_to_list(K) ++ "\n"),
            relay_loop(Next, Port);
        K when is_integer(K) andalso K =:=0 ->
            port_close(Port),
            Next ! K
end. 

build_ring(K, Current, N, F) when N > 1 ->
    build_ring(K, spawn(?MODULE, make_relay, [Current]), N - 1, F); 

build_ring(_, Current, _, F) ->
    F(),
    make_relay(Current). 

run(N, K, Par) ->
    Parent = self(),
    Cs = [spawn(fun ()-> Parent!run1(N, K, P) end) || P<-lists:seq(1, Par)],
    [receive _-> ok end || _<-Cs]. 

run1(N, K, P)->
    T1 = now(),
    build_ring(K, self(), N, fun ()-> io:format("(ring~w setup time: ~ws)~n", [P, timer:now_diff(now(), T1) /1000]), self() ! K end). 

start(Args) ->
    Args1 = [N, K, Par] = [list_to_integer(atom_to_list(X)) || X<-Args],
    {Time, _} = timer:tc(?MODULE, run, Args1),
    io:format("(total run (N:~w K:~w Par:~w) ~wms ~w/s)~n", [N, K, Par, round(Time/1000), round(K*Par*1000000/Time)]),
    halt(0).
root@nd-desktop:~/test# erl +Bd -noshell +K true -smp disable -s pipe_ring start 10 100000 8
(ring1 setup time: 0.021s)
(ring2 setup time: 0.02s)
(ring3 setup time: 0.019s)
(ring4 setup time: 0.03s)
(ring5 setup time: 0.018s)
(ring6 setup time: 0.031s)
(ring7 setup time: 0.027s)
(ring8 setup time: 0.039s)
(total run (N:10 K:100000 Par:8) 23158ms 34546/s)

參數的意義:
N K Par
N:ring有幾個環 每個環開一個port
K:每個環傳遞多少消息
Par: 多少ring一起跑

總的消息數是 K * Par.

我們可以看到 每秒可以處理大概 3.4W個消息 我有2個核心. 也就是說每個消息的開銷大概是 30us. 每個port的創建時間不算多, 1ms一個.

root@nd-desktop:~/test# dstat
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw
33  18  50   0   0   1|   0     0 | 438B 2172B|   0     0 |5329    33k
42  11  48   0   0   0|   0     0 | 212B  404B|   0     0 |5729    58k
41  11  49   0   0   0|   0     0 | 244B 1822B|   0     0 |5540    59k
40  11  49   0   0   0|   0     0 | 304B  404B|   0     0 |4970    60k

注意上面的csw 達到6W每秒.

root@nd-desktop:~/test# pstree
├─sshd─┬─sshd─┬─bash───pstree
     │      │      └─bash───man───pager
     │      ├─sshd───bash─┬─beam─┬─80*[cat]
     │      │             │      └─{beam}
     │      │             └─emacs
     │      ├─sshd───bash───emacs
     │      └─sshd───bash───nmon

我們運行了80個echo程序(/bin/cat)

讀者有興趣的話可以用systemtap 詳細了解 pipe的讀寫花費,以及context_switch情況, 具體腳本可以向我索要.

root@nd-desktop:~# cat /proc/cpuinfo
processor       : 1
vendor_id       : GenuineIntel
cpu family      : 6
model           : 23
model name      : Pentium(R) Dual-Core  CPU      E5200  @ 2.50GHz
stepping        : 6
cpu MHz         : 1200.000
cache size      : 2048 KB
physical id     : 0
siblings        : 2
core id         : 1
cpu cores       : 2
apicid          : 1
initial apicid  : 1
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 10
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts pni dtes64 monitor ds_cpl em
bogomips        : 4987.44
clflush size    : 64
power management:

結論是: 用port的這種架構的開銷是可以接受的.

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

Categories: Erlang探索 Tags: , , ,