接入Erlang控制台的幾種方法


     在window中調試的時候我們可以通過啟動多個cmd窗口運行Erlang節點,在生產環境中我們需要Erlang服務在Centos服務器上后台運行;這就需要在啟動的時候添加啟動參數detached來脫離終端:

     -detached Starts the Erlang runtime system detached from the system console. Useful for running daemons and backgrounds processes. Implies -noinput.

      對於我們自己的服務,即使部署到了生產環境一定要做到"像魔術師的飛刀,出手但並沒有脫手",還是需要一些方式進入到Erlang后台進程來做一些工作比如:查看某一個Erlang節點的運行時信息(內存,進程數等),讓服務優雅的退出而不是kill進程,或者做一下熱更新(參見:[Erlang 0010] Erlang 熱更新 當然熱更新可以使用reloader.erl的方案來簡化);一開始的時候服務器比較少,我們采用的是JCL的方式去處理的;

Erlang Shell JCL

JCL是Erlang Shell的一種運行模式,即Job Control Mode (JCL, in which jobs can be started, killed, detached and connected).我們啟動兩個節點來完成這個操作;

2012-11-14新增備注:下面的實驗是在Linux下完成的,Windows下JCL需要啟動werl.exe 

Node_1 添加了-detached選項,啟動之后直接在后台運行並沒有啟動Shell
erl -setcookie abc -name node_1@192.168.1.123 -detached 
Node_2 使用了和Node_1相同的cookie,啟動之后進入Erlang Shell界面
erl -setcookie abc -name node_2@192.168.1.123
下面我們開始在node_2@192.168.1.123演練JCL:

復制代碼
Eshell V5.9  (abort with ^G)
(node_2@192.168.1.123)1> node(). %當前這是在node_2
'node_2@192.168.1.123'
(node_2@192.168.1.123)2> %Ctrl + G 進入JCL模式
User switch command
--> h
c [nn] - connect to job
i [nn] - interrupt job
k [nn] - kill job
j - list all jobs
s [shell] - start local shell
r [node [shell]] - start remote shell
q - quit erlang
? | h - this message
--> r'node_1@192.168.1.123' %嘗試連接到node_1@192.168.1.123
--> j
1 {shell,start,[init]} %列出所有的Job
2* {'node_1@192.168.1.123',shell,start,[]}
--> c 2 %這里2是job的編號,切換到job 2
Eshell V5.9 (abort with ^G)
(node_1@192.168.1.123)1> node(). %注意提示符,現在已經是在node_1
'node_1@192.168.1.123'
(node_1@192.168.1.123)2> erlang:now().
{1326,801888,347570}
(node_1@192.168.1.123)3> %再一次Ctrl + G
User switch command
--> j
1 {shell,start,[init]}
2* {'node_1@192.168.1.123',shell,start,[]}
--> c 1 %切換到job 1
(node_2@192.168.1.123)2> node(). %注意提示符,我們已經回到了node_2
'node_2@192.168.1.123'
(node_2@192.168.1.123)3>
復制代碼

這樣來來回回切換是不是有點盜夢空間的意思?是不是可以更簡單一點,比如直接進入node_1呢?借助-remsh參數就可以做到

看看-remsh的說明恰好是我們需要的:

If you want an Erlang node to have a remote job active from the start (rather than the default local job), you start Erlang with the -remsh flag. Example: erl -sname this_node -remsh other_node@other_host

動手試一下:
erl -setcookie abc -name node_3@192.168.1.123 -remsh node_1@192.168.1.123 %%這樣就直接進入了node_1節點
注意:直接進入到了node_1,執行完操作了想要退出怎么辦? 你要是在這里執行一下q(). node_1這個節點就直接死掉了;
正確的方法還是Ctrl+G進入JCL模式然后執行q命令退出;使用ps aux|grep node查看一下進程是不是還在

ejabberd網站上提到了這個方法 
[1] Attach an Erlang Shell to an Already Running ejabberd Process http://www.ejabberd.im/tricks
[2] Interconnecting Erlang Nodes http://www.ejabberd.im/interconnect-erl-nodes

 

 另一種實用的接入erlang控制台的方法

地址:http://mryufeng.iteye.com/blog/362394  Powered by mryufeng

按照mryufeng老大的方法操練了一番,成功,中間 /usr/local/lib/erlang/bin/start 啟動失敗,同樣是目錄和配置文件缺失的問題
mkdir /usr/local/lib/erlang/log
echo "[]." > /usr/local/lib/erlang/releases/R15B/sys.config

Stackoverflow的相關問題: How to create deamon program with erlang? http://stackoverflow.com/questions/5972811/how-to-create-deamon-program-with-erlang

題外話:在embedded模式下是沒有交互式shell可用的,能夠接入Erlang VM的方法就是to_erl

 

原理見下圖:

 

erl_call

  隨着服務器增多,登錄一台台服務器然后使用JCL去做熱更新之類的就有點麻煩了,取而代之的解決方案就是ssh登錄到每台服務器然后向該服務器上的Erlang節點發送消息,執行熱更新(當然不限於熱更新了);
  這里有一個很強大的工具可以用:erl_call;erl_call模塊的設計目標就是使用Unix Shell腳本與分布式Erlang節點進行交互,erl_call可以啟動或者連接到一個分布式的Erlang節點進行簡單的方法調用甚至執行表達式序列;erl_call構建在erl_interface之上,通過標准的RPC調用方式與Erlang的rex server交互,並不需要額外的工具支持.注意Erlang節點的RPC服務啟動的時候注冊的名字是rex http://www.google.com/codesearch#dNzC48WMK6w/lib/kernel/src/rpc.erl&q=rpc%20lang:erlang&type=cs 
看一下erl_call的幫助,注意Erlang版本不同erl_call的路徑也有所不同:
Usage: /usr/local/lib/erlang/lib/erl_interface-3.7.6/bin/erl_call [-[demqrsv]] [-c Cookie] [-h HiddenName]
            [-x ErlScript] [-a [Mod [Fun [Args]]]]
            (-n Node | -sname Node | -name Node)

  where: -a  apply(Mod,Fun,Args) (e.g -a 'erlang length [[a,b,c]]'
         -c  cookie string; by default read from ~/.erlang.cookie
         -d  direct Erlang output to ~/.erl_call.out.<Nodename>
         -e  evaluate contents of standard input (e.g echo "X=1,Y=2,{X,Y}."|erl_call -e ...)
         -h  specify a name for the erl_call client node
         -m  read and compile Erlang module from stdin
         -n  name of Erlang node, same as -name
         -name  name of Erlang node, expanded to a fully qualified
         -sname name of Erlang node, short form will be used
         -q  halt the Erlang node (overrides the -s switch)
         -r  use a random name for the erl_call client node
         -s  start a new Erlang node if necessary
         -v  verbose mode, i.e print some information on stderr
         -x  use specified erl start script, default is erl
簡單翻譯一下:
-a    執行erlang:apply/3,需要提供的就是m f a,m是必須的,f默認值start,a默認值[],注意這個flag只接受一個參數,所以最好通過添加括號把m f a組織起來.
-c 執行cookie值如果沒有指定就會使用  ~/.erlang.cookie 文件中定義的cookie,Erlang 節點之間通信必須要有相同的cookie
-d 調試模式;所有的IO都會輸出到~/.erl_call.out.Nodename文件,其中NodeName就是我們要處理的erlang節點名;
-e 讀一系列的Erlang表達式並返回最后一個表達式的結果,這些表達式用','分隔,'.'結束,這個Erlang Shell是一致的,Ctrl+D組合鍵結束輸入,如果成功返回結果{ok,Result}.
-h HiddenName 隱藏erl_call代表的節點
-m 讀入並編譯一個module
-n  -name  -sname 這三個參數三選一,name和n是同樣的含義是為了兼容依然保留,sname代碼短名稱
-q 停止Erlang 節點
-r 為erl_call生一個隨機name
-s 必要的話啟動一個Erlang的分布式節點,意思是自由第一個調用會啟動一個Erlang節點后續的調用就會快很多.
-v  多打印一些冗余信息
-x ErlScript:指定Erlang啟動腳本如果不指定就是用erl start-up腳本
 
比如我們現在要獲取節點node_1的內存信息
/usr/local/lib/erlang/lib/erl_interface-3.7.6/bin/erl_call -s -a 'erlang memory ' -name node_1@192.168.1.123 -c abc
 
實踐中遇到兩個問題:
問題一:當name里面包含ip地址的時候執行會報錯,這個erlang論壇里面有人也提到了:
erl_call can now use an IP address for remote node name  http://erlang.org/pipermail/erlang-patches/2010-October/001533.html
我的解決方案就是把name換成了sname並去掉了ip地址就OK了;
 
問題二:在使用-e參數的時候怎么結束掉輸入並查看結果
這個問題的確挺二的,就因為沒有仔細閱讀文檔,結束的時候需要用Ctrl+D, http://www.erlang.org/doc/man/erl_call.html
 
/usr/local/lib/erlang/lib/erl_interface-3.7.6/bin/erl_call -e -name node_1@192.168.1.123 -c abc
A=1,
B=2,
C=A+B.
%Ctrl + D 
{ok, 3}
 
 

SSH

  如果是在沒有Erlang的機器接入怎么辦?使用ssh即可,直接關閉SSH即可正常退出,如果接入有問題可以添加 -oLogLevel=DEBUG 輸出debug信息看一下
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ mkdir /tmp/ssh
$ ssh-keygen -t rsa -f /tmp/ssh/ssh_host_rsa_key
$ ssh-keygen -t rsa1 -f /tmp/ssh/ssh_host_key
$ ssh-keygen -t dsa -f /tmp/ssh/ssh_host_dsa_key
$ erl
1> application:ensure_all_started(ssh).
{ok,[crypto,asn1,public_key,ssh]}
2> ssh:daemon(8989, [{system_dir,  "/tmp/ssh" },
2> {user_dir,  "/home/ferd/.ssh" }]).
{ok,<0.52.0>}
 
$ ssh -p 8989 ferd@127.0.0.1
Eshell Vx.x.x (abort with ^G)
1>

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM