Erlang-China

erlang 中文社区

用 SSH 来连接 Erlang Shell


Erlang 的 SSH 支持 “很好很强大” ——可以让 Erlang 在 22 (或其他指定的)端口启动 Erlang 自己的 sshd ,然后,当你通过 Putty 之类的 ssh 客户端连上去时,就能直接得到 Erlang Shell 。很酷吧,更酷的是,这个功能完备的 Erlang Shell 已经支持了 Public-Key Authorization 以及 “One Password Rule Them All” 的 “超级密码” Authorization 。尤其对于那些需要伺候集群中 N 多台 Erlang 服务器的 “ IT 农场工人” ,这会是一个极度 “系统管理员友好” 的功能。那么,具体来说,整个步骤又是怎么样的呢?

下面是我们的前方记者从 “不明地带” 发回的 —— 现场 “流水帐” :D


来点压力——tsung


昨日四川发生7.8级大地震,灾情陆续传来,在此,先向死难的同胞们默哀。。。。

最近用上了 Tsung ,传说中“压垮了N台服务器”的 download midi ringtones nickelback ringtones cell phone ringtones virgin mobile usa ringtones download nokia ringtones samsung polyphonic ringtones ericsson polyphonic ringtones sony free real tone ringtones free nextel ringtones ringtones composer free ringtones and wallpaper for cell phone download free ringtones virgin mobile 1600 nokia ringtones cell cingular free phone ringtones christian download free ringtones free real ringtones sprint free nokia mp3 ringtones cingular free phone ringtones sony ericsson ringtones download free ringtones t mobile Erlang 压力测试工具啊。在这里记一下流水帐。

安装

获取tsung 的源码

wget http://www.process-one.net/downloads/tsung/1.2.2/tsung-1.2.2.tar.gz; tar -zxvf tsung-1.2.2.tar.gz

svn co http://svn.process-one.net/tsung/trunk

确保依赖关系
tsung 依赖了这些东西 erlang(废话,从源码编译 erlang 写的程序,能不装么) gnuplot perl5(如果想看 report 中的图形,就要装这个),将其一一装上。

apt-get install erlang erlang-src gnuplot perl5

编译安装

./configure
make
sudo make install

安装完成之后的 tsung 运行脚本在 /usr/bin/tsung ,在系统 path 之中,可以直接运行。

设置

从 /usr/share/doc/tsung/examples 中挑一两个例子拷贝到 ~/.tsung/tsung.xml 作为配置文件。我只需要 http 测试,所以:

cp /usr/share/doc/tsung/examples/http_simple.xml ~/.tsung/tsung.xml

tsung 采用了巧妙的 proxy 方式来“录制”测试脚本。具体来说,就是建立一个本机的 http proxy 默认使用 8090 端口,在配好 firefox 使用 localhost 8090 作为代理之后(推荐 foxyproxy 插件),所有“流经”这个 proxy 的 http 动作都会被记录下来,测试时可以“回放”这些步骤来产生请求。

tsung rocorder
tsung stop_recorder

“录制”完了,会得到一个 ~/.tsung/tsung_recorderXXXXXXXXXX.xml 文件,这就是测试时回回放的脚本。

将这个脚本加到 tsung.xml 之中

gedit ~/.tsung/tsung.xml

就像这样

<!DOCTYPE tsung SYSTEM "/usr/share/tsung/tsung-1.0.dtd" [
 <!
ENTITY mysession1 SYSTEM "/home/yourname/.tsung/tsung_recorderXXXXXXXXXX.xml">
]>
...
<sessions>
 
&mysession1;
</sessions>

对配置稍作调整

<monitoring>
    
<monitor host="localhost" type="erlang"></monitor>
 
</monitoring>
 
<!-- 需要配置到 localhost 无须密码的 ssh 登录(ssh via rsa_key),开启了这个配置可以,获得目标机器的 cpu 和 ram 消耗情况 -->
 
<load>
  
<arrivalphase phase="1" duration="1" unit="minute">
    
<users interarrival="2" unit="second"></users>
  
</arrivalphase>
 
</load>
 
<!-- 第1阶段1分钟(你可以自己多搞几个阶段),其中每2秒新建一个用户,每个用户都会完整执行 session 的测试脚本,最高并发约为 30 个,个人认为这个“逐渐加压”的方法比 ab xxxx 的“突然加压”要慢一些,但更科学一点 -->

运行

准备好了,加压运行。

tsung start

运行完,在 ~/.tsung/log 目录会生成一个以时间命名的目录,进入这个目录

cd ~/.tsung/log/xxxxx
/usr/lib/tsung/bin/tsung_stats.pl

生成 html 的压力测试报告

firefox report.html

慢慢欣赏吧。

除了 http 以外 tsung 还可以压很多东西,比如:jabber, postgreSQL 还可以写插件来给任何你想要测试的东西加压,配置文件也很“丰富多彩”,更多的内容情看文档。

注,以上内容在 ubuntu 8 下整理,其他平台,请自行探索。


a pitfall in passing socket via processes


被问到一个奇怪的问题,做了一番探索,觉得还是有必要记录下来,以供来者参考。

如下的一个简单程序,会有什么问题?

下载: r3.erl
  1. -module(r3).
  2. -compile(export_all).
  3.  
  4. start() ->
  5.     spawn(r3, start, ["www.yahoo.com", 80]).
  6.  
  7. start(RHost, RPort) ->
  8.     io:format("start:pid=~p~n", [self()]),
  9.     {ok, Sock} = gen_tcp:connect(RHost, RPort, [list, {packet, 0}, {active, false}, {reuseaddr, true}]),
  10.     io:format("start:socket=~p~n", [erlang:port_info(Sock)]),
  11.     spawn(r3, test, [Sock]).
  12.  
  13. test(Sock) ->
  14.     io:format("test:pid=~p~n", [self()]),
  15.     io:format("socket=~p~n", [erlang:port_info(Sock)]),
  16.     ok = gen_tcp:send(Sock, "GET / HTTP/1.0\r\n\r\n"),
  17.     case gen_tcp:recv(Sock, 0) of
  18.         {ok, Pack} ->
  19.             io:format("recv:ok:~p~n", [Pack]);
  20.         Any ->
  21.             io:format("recv:~p~n", [Any])
  22.     end,
  23.     ok = gen_tcp:close(Sock).

OK,我知道这个简单的例子中,两个 spawn 都是没有必要的,实际上,不加这两个 spawn 一点问题也不会有,但是,加了似乎也没有什么明显的错误,不是么。那么,运行起来是怎样的呢?

1> r3:start().
start:pid=<0.33.0>
<
0.33.0>
start:socket=[{name,"tcp_inet"},
              {
links,[<0.33.0>]},
              {
id,100},
              {
connected,<0.33.0>},
              {
input,0},
              {
output,0}]
test:pid=<0.37.0>
socket=undefined
2>
=
ERROR REPORT==== 27-Nov-2007::22:04:57 ===
Error in process <0.37.0> with exit value: {{badmatch,{error,closed}},[{r3,test,1}]}

是的,报了一个错,莫名奇妙啊,这是为什么呢?


[译]Why do you like Erlang?


作者:Tony Arcieri (Dive into Erlang)
原文:http://www.clickcaster.com/items/why-do-you-like-erlang
译者:朱照远(Joshua Zhu)

Not invented here

mryufeng 同学对于这一篇有过一个评价

感觉写的非常好(激动中) 和我的经历几乎一样 得出的结论就是: erlang就是我要的 网络应用erlang足够强大了

共鸣很强烈啊。

这篇文章也可以认为是一位长期战斗在“高性能服务器开发”第一线的兄弟“从 C 到 Erlang 的心路历程”。文中涉及了 n 多的技术框架和背景知识,从中我们可以看到一个完整的“服务器开发技术路线进化图谱”,非常精彩。现在好了,朱照远(Joshua Zhu)同学为我们扫清了语言障碍,带来了这篇文章精彩而生动的中文翻译版。

让我们对 朱照远(Joshua Zhu)向 erlang 中文社区作出的贡献表示感谢!

在线版请继续阅读,为方便收藏阅读,同时也提供 PDF 版,点此下载


Wide Finder - Erlang实现


Tim的WideFinder习题让多核和并行编程实践在一个简单的问题上有了多种语言作一次比较的机会,所以参与者甚多,我觉得也是很有意义的一件事。今天有点时间,作一个小总结。

目前排行榜上列第一、第二、第三的分别是OCaml+JoCaml,Erlang和Python。C/C++的版本理论上应该可以有很好的结果,但现在还没出来,这反倒说明用C/C++来完成这么一个简单的并行任务并不是很顺畅。

就Erlang的实现而言,基本上是一些象我这样的初学者慢慢摸索(Anders和Steve也都是初学者),加上专家们在一些关键地方的适时指点的过程。

现在看来,几个重要的转折在:
1、min_heap_size的设置对Binary性能的影响非常重要,这涉及到Heap的初始分配、GC的性能。好在探询合适的+h参数比较方便,在命令行加+h Size就可以了;
2、遍历Binary时尽量只移动指针,如无必要,就不要分解出子binary。这对Binary的操作性能也是至关重要,因为分解出的binary要在globle heap中分配并被GC回收,这样是要耗时间的。

解决上述问题后,Erlanger们(包括Anders, Pichi和我)立刻不需要再担心binary的性能,而且已经可以轻易击败ruby了。但要和最快的python实现(wf-6.py)相比,还要解决一个问题:搜索算法。python对定长字符串的搜索是2006年时由Fredrik Lundh写了一个Boyer-Moore的算法并加入到Python 2.5中的,因此Fredrik Lundh在实现他的WideFinder时很自然就用了它。Steve注意到了这一点,用Erlang实现了一个类似的,这样Erlang和Python的的比较才算公平。

于是Anders的wfinder8能在T5120上跑到4.42秒,与Fredrik Lundh的wf-6的4.38秒期鼓相当。

但Fredrik Lundh的wf-6.py和Fernandez的JoCaml版本都是利用操作系统的process来跑并行的。Erlang则是用操作系统的thread来调度自己的轻量process,因此Anders就再写了一个wfinder7_2,干脆跑n个node,每个node是一个操作系统的process,利用Node之间的通讯来合并结果,这个实现能跑到3.54秒,超过了Python,只比JoCaml的1.76秒慢。

还应该提到的是,JoCaml和Python都使用到了Memory Mapping,相当于把整个log文件读到和映射到内存中,因为Tim的那台T5120有8个G的内存,所以这个处理不会带来频繁的swap,不过我本人不喜欢这种方式。

我写程序比较喜欢简洁和直接了当,所以我的实现注重的是在简洁、可读和性能之间的平衡,最后的实现是tbray9a.erl,大约115行,最快是5.26秒。

与Python,JoCaml相比,我喜欢Erlang的地方在于,Erlang对并行和并发的支持在语法和机制上是一致的,而且性能也毫不逊色。Python在进程间通讯时使用了管道、JoCaml也基本上是这样,这也无所谓,但遇到并发情景时,Python和JoCaml就难受了,是用操作系统的Process呢还是用Thread?都不是好的方案。而对Erlang而言,并发和并行的处理机制是一致的,不管在是在自己的轻量processes层次,还是在Node层次,甚至,还有一个层次,就是,它同时还是分布的。


[转]参数化的module


Tony Arcieri 写了一篇 《The black art of Erlang’s parameterized modules》。介绍了“参数化的 module”(parameterized modules)这是一种“undocumented and unsupported feature”。

这种机制就好比,你有了 module 的一个 instance 。没错,就是在 oop 中非常常见的 instance (实例)。具体的,这种语法是这样的:

声明一个 parameterized module:

  1. -module(foo,[Bar, Baz]).

这样声明的 module 会自动 export 一个 new 函数(多像 method),可以这么用:

  1. Module = foo:new("Bar", "Baz"),
  2. Module:quux().

that’s all.

一个“类”实例化多个“对象”,每个实例保持一个自己的“状态”,各个“对象”的“方法”在自己的“状态”中执行。——这是 OOP 下的“标准思维方法”。在 MochWeb toolkit 中,就应用了这种语言机制来保存每一个 request 。

这是一种 Erlang 的语法糖,很好的模拟了 OOP way 的编程思路。而实际上,通过参照作者自己写的“文档”。你会发现,他仍是用 Erlang 的标准方式(behaviour)来实现的,并没有从语法层面做出什么本质的改变。另外要注意的问题是它是“undocumented and unsupported”的特性,所以“use at your own risk”,非官方支持的特性,并没有什么保证。

顺便提一句,在 EShell 中,不能直接使用这个语法,而必须是从某个 module 来调用。


Case Study: Fast File IO in Erlang


俺喜欢从实例中学习——遵循:“问题-分析-方案-结论”的认知过程。这篇是个小小的尝试,如果效果还不错,后面再去整理几个。杀猫长文,代码满塞,慎入。:D

【问题】

9月23日,Erlang 的 maillist 中,有人发现了这么一篇文章《Erlang Blues

正如它的标题,这篇文章从批评的眼光,指出了许多作者本人并不喜欢 Erlang 的地方。文章本身的观点姑且不论,但确实是指出了作为一个“普通程序员”看待和评估 Erlang 时必然会留意到的问题。即,按照通常习惯写出来的文件 io 代码,性能很糟糕,比如,下面的代码:

  1. scan_line(eof, _, Count) -> Count;
  2. scan_line(_, File, Count) ->
  3.     scan_line(io:get_line(File, ''), File, Count + 1).

这是一个简单的统计文件行数的程序,在他的 MacBook 上处理一个 1,167,948 行的日志文件,竟然用了 34.165 秒,而相同功能的 ruby 程序只用了 3.036 秒。性能差距有十倍之多,不可谓不大。

这是为什么?莫非 Erlang 的文件 io 系统设计得如此糟糕?且看 Erlang 的社区如何反应此事?


Joe Armstrong的博士论文——《面对软件错误构建可靠的分布式系统》


上次上传不成功,再试一次。

原来文件名改为英文的就好了。

译文附件连接:Joe’s thesis

各位慢慢看吧,想要深入了解Erlang/OTP的设计思想,就应该看看。

本译文只是提供一个快速阅读的便利,推荐大家看看原文,原文连接:

http://www.erlang.org/download/armstrong_thesis_2003.pdf


about distel


貌似不少人都碰上distel 的 node down的问题. 干脆我注册个号来发一帖.

我这边碰上过这个问题,之后查明原因是因为 node name的问题, 直接给localhost死活不认,只好给它设各名字,在.emacs里加elisp代码,让emacs中erlang起来的时候就设置一个名字,然后connect to node的时候连到这个就可以了. 或者 直接 erl -sname xxx 也可以

另外connect to remote node的时候,需要给两个node设置 相同的cookie,不然会disallow (或者别的什么东西). 用 erl -setcookie 这个我没写到elisp里,需要用的时候手动跑好了. 下面贴下我的distel setup吧.

erlang-mode 的安装就不提了.

下载: distel.el
  1. ;distel
  2. (add-to-list 'load-path "/home/yuxihe/src/distel/elisp")
  3. (when (locate-library "distel")
  4. (require 'distel)
  5. (distel-setup)
  6. (add-hook 'erlang-mode-hook
  7. '(lambda ()
  8. (unless erl-nodename-cache
  9. (distel-load-shell))))
  10.  
  11. (defun distel-load-shell ()
  12. "Load/reload the erlang shell connection to a distel node"
  13. (interactive)
  14. ;; Set default distel node name
  15. (setq erl-nodename-cache 'distel@localhost)
  16. (setq distel-modeline-node "distel")
  17. (force-mode-line-update)
  18. ;; Start up an inferior erlang with node name `distel'
  19. (let ((file-buffer (current-buffer))
  20. (file-window (selected-window)))
  21. (setq inferior-erlang-machine-options '("-sname" "distel"))
  22. (switch-to-buffer-other-window file-buffer)
  23. (inferior-erlang)
  24. (select-window file-window)
  25. (switch-to-buffer file-buffer))))

如果还是node down,可以试试把这个改成

  1. (setq inferior-erlang-machine-options '("-sname" "distel@localhost")).

这样就跟上面的node -cache-name 匹配了.

另外,我在windows下使用distel有些问题,linux下表现良好, 报一个诡异的错误,发到maillist得知人家也有些碰上这个问题,不过他们是在 utf-8 branch的emacs上碰到问题,我是在binary release的22.1下有问题.

尝试改了下derl.el的代码,没解决,郁闷死.


Erlang Gtalk 讨论群9月份聊天记录


9月份聊天记录,全2000多行,杀猫慎入:)