[Erlang33]使用recon從網頁查看Erlang運行狀態


0.需求分析

Erlang最好的賣點之一就是提供了一個非常強大的shell來查看Node運行時的各種狀態,可以進行各種各樣的內部查看,在運行時調試和分析,熱更新代碼。
 
但是總有一些在生產環境下要慎用的狀態查看函數。比如:
1.在進程數達到10w級以上的Node調用erlang:processes()來得到所有的進程Pid.然后算長度blabla...;
2. 當某個進程的信箱被堵塞了上萬個消息隊列時調用erlang:process_info(Pid,messages)來查看所有的消息。
為了避免在shell中進行這些危險的操作,就有了recon這個項目。它保證在生產環境下可以調用安全。
項目地址github: recon,     文檔可見: fred
 
Erlang in anger食用更佳。
然而在體會到一段時間的recon的強大之后,突然感覺為了查看狀態每次檢查時都要 在shell中輸入相同的命令集是一件非常枯燥的事情,於是就想要一個可以直接用網頁直接查看狀態的工具。並且加上圖表顯示。讓分析問題變得更加快速,易懂。
recon_web是一個可以通過web 查看Eralng節點各種狀態的工具。
它與observer的區別:
recon_web observer
web頁面查看,不需求wx GUI 需要Erlang安裝wx GUI application
保證可以在生產環境中被安全調用 如果對於ets非常多或進程達到一定數量時會崩潰掉,不適合大多數在Node已出狀況時使用

1. 項目介紹

項目地址github: recon_web.
使用的框架:
cowboy 1.0.1 websocket 用於server通信
recon   用於查看Node狀態
jsx   用於json轉換
lager   日志記錄
socket.io.client  web端的websocket維護
highcharts web端繪制圖表
   
 
上手也非常簡單,make&&make shell然后打開127.0.0.1:8080就可以看到效果啦,還不快來試試~。其它命令詳見Readme。
 

2.recon_web 實現

說明:
2.1.為什么要分成system_info 和recon_info?
  system_info是指Node中基本不會變化的那些指標:
  
  因為他們基本不會變化,所以只會在連接建立時傳一次就行了。
  recon_info是用recon得到的Memory, Scheduler, Port的情況,它們會一直變化,所以在每個Heartbeat都會更新一次給Client.
 
2.2. 如果大量的(比如1000個)連接上來查看。每個連接的心跳都會去用recon得到新的Node信息,會不會造成CPU在這上面消耗過多?
  這就是recon_server的職責,它是一個獨立的gen_server,存着上次使用recon計算出的Node信息和計算時間:
  {ReconInfo, LastUpdateTime}.每個連接上來的點都會向recon_server請求ReconInfo,如果Now - LastUpdateTime >
  規則的時間就會重新計算一份ReconInfo存起來。所以大量的連接在同時請求ReconInfo,recon_server也只會計算一次。
 
2.3.為什么不直接使用handler 同步call recon_server得到recon_info,然后回傳給Client?
  現在實現是:
  2.3.1 handler 同步call session_gen_server ;
  2.3.2 session_gen_server再異步info recon_server;
  2.3.3 recon_server再異步info recon_info 給session_gen_server,
  2.3.4 session_gen_server得到recon_info后異步info handler有新的消息在我這,你快來取;
  2.3.5 handller得知3.4后,再同步call session_gen_server拿到recon_info,然后encode 通過websocket發給Client.
 
  這種方式就是多了session_gen_server這個中間緩沖層。
  好處是:可以把要傳給client的多條消息都緩沖在這里,然后一次性發給Client。
  當然對於現在只有recon_info這一種消息來說,沒有什么優勢。可是考慮到擴展性(那些不需要及時發給Client的消息),加個緩沖層明顯是好得多。 
 

3. recon_web中各種圖表說明 

1> recon_web_status:get_recon_info(node_stats_list).
[{process_summary,[{process_count,86},
                   {run_queue,0},
                   {error_logger_queue_len,0},
                   {memory_total,20032952},
                   {memory_procs,6067544},
                   {memory_atoms,330312},
                   {memory_bin,467040},
                   {memory_ets,465936}]},
 {mem_summary,[{bytes_in,0},
               {bytes_out,0},
               {gc_count,2},
               {gc_words_reclaimed,256},
               {reductions,130454},
               {scheduler_usage,[{1,0.9252873563218391},
                                 {2,0.147239263803681},
                                 {3,0.13218390804597702},
                                 {4,0.14285714285714285}]}]}]

3.1. 根據 error_logger_queue_len process_count run_queue繪制以下表:

3.2. 根據上面的memory_total,memory_procs,memory_atoms,memory_bin,memory_ets繪制:

3. 3.根據scheduler_usage繪制:

3.4 根據bytes_in,bytes_out繪制:

2> recon_web_status:get_recon_info(proc_count).
[{proc_count,[{memory,[{<<"application_controller">>,602096},
                       {<<"0.26.0">>,372368},
                       {<<"recon_server">>,372328},
                       {<<"code_server">>,284656},
                       {<<"kernel_sup">>,197384},
                       {<<"0.159.0">>,88632},
                       {<<"erl_prim_loader">>,88552},
                       {<<"error_logger">>,75904},
                       {<<"init">>,67896},
                       {<<"0.45.0">>,55064}]},
              {bin_memory,[{<<"kernel_sup">>,396661},
                           {<<"erl_prim_loader">>,27958},
                           {<<"0.26.0">>,7408},
                           {<<"0.159.0">>,5527},
                           {<<"0.45.0">>,1264},
                           {<<"application_controller">>,947},
                           {<<"user">>,852},
                           {<<"recon_server">>,454},
                           {<<"lager_event">>,278},
                           {<<"cowboy_clock">>,203}]},
              {reductions,[{<<"recon_server">>,43125661},
                           {<<"erl_prim_loader">>,1328265},
                           {<<"0.159.0">>,243664},
                           {<<"code_server">>,196114},
                           {<<"application_controller">>,56899},
                           {<<"timer_server">>,53145},
                           {<<"kernel_sup">>,48774},
                           {<<"cowboy_clock">>,30740},
                           {<<"file_server_2">>,24547},
                           {<<"init">>,17949}]},
              {total_heap_size,[{<<"application_controller">>,75112},
                                {<<"recon_server">>,46421},
                                {<<"0.26.0">>,46421},
                                {<<"code_server">>,35462},
                                {<<"kernel_sup">>,24503},
                                {<<"0.159.0">>,10958},
                                {<<"erl_prim_loader">>,10957},
                                {<<"error_logger">>,9358},
                                {<<"init">>,8370},
                                {<<"0.45.0">>,6771}]}]}]

 

3.5根據上面的memory, bin_memory,reductions, total_heap_size繪制:

3> recon_web_status:get_recon_info(port).
[{port_summary,[{<<"efile">>,5},
                {<<"tcp_inet">>,2},
                {<<"2/2">>,1},
                {<<"tty_sl -c -e">>,1}]}]

 

3.6.根據 port_summary繪制:

4> recon_web_status:get_recon_info(inet_count).
[{inet_count,[{sent_oct,[]},
              {recv_oct,[{<<"Port0.4012">>,1205},{<<"Port0.3695">>,0}]},
              {sent_cnt,[]},
              {recv_cnt,[{<<"Port0.4012">>,72},{<<"Port0.3695">>,0}]}]}]

 

3. 7.根據sent_oct, recv_oct, sent_cnt, recv_cnt繪制:

5>recon_web_status:get_recon_info(alloc_memory).
[{used,20804344},
 {allocated,32247216},
 {unused,11269856},
 {allocated_types,[{binary_alloc,2786160},
                   {driver_alloc,164720},
                   {eheap_alloc,6763376},
                   {ets_alloc,1475440},
                   {fix_alloc,426864},
                   {ll_alloc,19923784},
                   {sl_alloc,164720},
                   {std_alloc,934768},
                   {temp_alloc,655960}]},
 {allocated_instances,[{0,9094640},
                       {1,6305264},
                       {2,1246704},
                       {3,15664624},
                       {4,984560}]}]

 

3.8根據alloc_memory繪制:

6> recon_web_status:get_recon_info(cache_hit_rates).
[{cache_hit_rates,[{<<"instance1">>,[602,1113]},
                   {<<"instance3">>,[148,213]},
                   {<<"instance0">>,"OV"},
                   {<<"instance2">>,[7,13]},
                   {<<"instance4">>,[0,0]}]}]

 

3.9 根據cache_hit_rates繪制:

 

4. 參考文檔

cowboy 建立websocket:http://ninenines.eu/docs/en/cowboy/HEAD/guide/ws_handlers/

highcharts: http://www.highcharts.com/

 ---------------------------------------------------------------------------------------------------------------------

inside the beam scheduler 


免責聲明!

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



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