为什么Elixir.Phoenix.Codeloader.Server位于此:observer屏幕的顶部?

时间:2018-03-09 09:57:53

标签: erlang elixir phoenix-framework

我正在寻找我的凤凰应用程序花费CPU周期的地方。人们建议我看看:observer工具,但是我无法解释它的输出。请参阅以下屏幕:

observer process screen

应用程序的简要描述:它接受使用JWT的REST调用,并根据JWT中的用户将调用转发给后端服务器。

我假设'Reds'列或多或少对应于cpu使用情况。所以:

  • 什么是CodeReloader服务器,为什么它在顶部?
  • 什么是file_server进程,为什么它如此之高,我没有做任何文件I / O
  • 为什么Elixir.Logger如此之高?我没有得到任何记录输出 在我的测试期间,我正在使用懒惰的日志记录。
  • 我的测试运行期间代码服务器进程在做什么?
  • 为什么所有那些cowboy_protocol.init进程如此之高,我希望初始化很快,但其他功能更昂贵。
  • jose_server是我唯一能理解的东西,它解密了JWTs

作为参考,这里是类似testrun的etop输出,如何让它显示时间值而不是' - '?我想要那个吗?

Pid            Name or Initial Func    Time    Reds  Memory    MsgQ Current Function
----------------------------------------------------------------------------------------
<0.247.0>      'Elixir.Phoenix.Code     '-'24468015 2178040      13 gen:do_call/4
<0.46.0>       file_server_2            '-'14085904  197128       0 gen_server:loop/7
<0.642.0>      hackney_pool:init/1      '-'  795169   14368       0 gen_server:loop/7
<0.416.0>      jose_server              '-'  483301   18728       0 gen_server:loop/7
<0.323.0>      'Elixir.Logger'          '-'  254592   30680       0 gen_event:fetch_msg/
<0.96.0>       'Elixir.Mix.ProjectS     '-'  184593  689560       0 gen_server:loop/7
<0.374.0>      hackney_manager          '-'  155632  125504       0 gen_server:loop/7
<0.3121.0>     cowboy_protocol:init     '-'  132982   47368       0 gen:do_call/4
<0.3117.0>     cowboy_protocol:init     '-'  132979   47368       0 gen:do_call/4
<0.3119.0>     cowboy_protocol:init     '-'  132978   47368       0 gen:do_call/4
<0.3120.0>     cowboy_protocol:init     '-'  132978   47368       0 gen:do_call/4

1 个答案:

答案 0 :(得分:-1)

总结我的发现:

原来我运行的是:dev模式,在开发模式下配置不同。例如,您可以编辑源代码,在下一个HTTP请求中,代码重新加载器将检测更改并快速重新编译代码。因此,当我使用请求对服务器进行攻击时,Code Reloader会不断检查我的所有源文件,这也解释了为什么file_server正好在它下面。我切换到生产模式(MIX_ENV = prod)并且性能增加了三倍。

关于Logger:我已将loglevel设置为:error并且未显示输出。但是,我喜欢做很多日志记录,而我的日志语句几乎描述了程序中做出的所有决策,因此对于每个HTTP请求,代码中都存在数十个日志语句。这往往会加起来,特别是如果你每秒发出数百个请求。

值得庆幸的是,您可以告诉Elixir编译器从生产中完全删除这些语句:在记录器配置中使用compile_time_purge_level标志(在config/prod.exs中):

# Do not print debug messages in production
config :logger, level: :warn, compile_time_purge_level: :info

最后我使用fprof分析器,它确定JWT处理是罪魁祸首,我决定停在那里。

以下是如何做到这一点:

iex(5)> :fprof.trace([:start, {:procs, :all}])
:ok
iex(6)> :fprof.trace(:stop)
:ok
iex(7)> :fprof.profile
...................................,
(and a whole lot more lines)
End of trace!
:ok
iex(8)> :fprof.analyse([callers: true, sort: :own, totals: true, details: true])
(followed by > 1000 lines of output)
Done!
:ok

请注意,fprof会生成大量输出文件(当前目录中的fprof.trace),即使只跟踪一分钟也是如此。

这是fprof.analyse()调用的第一部分:

iex(5)> :fprof.analyse([callers: true,sort: :own,totals: true,details: true])
Processing data...
Creating output...
%% Analysis results:
{  analysis_options,
 [{callers, true},
  {sort, own},
  {totals, true},
  {details, true}]}.
%                                               CNT       ACC       OWN
[{ totals,                                     4774694,17162.356,14837.297}].  %%%
{[{{base64url,'-decode/1-lbc$^0/2-0-',2},      206492,    0.000,  829.718},
  {{base64url,decode,1},                       1083, 1191.294,    5.680}],
 { {base64url,'-decode/1-lbc$^0/2-0-',2},      207575, 1191.294,  835.398},     %  <----------
 [{{base64url,'-decode/1-lbc$^0/2-0-',2},      206492,    0.000,  829.718},
  {{base64url,urldecode_digit,1},              206492,  350.686,  348.324},
  {garbage_collect,                             620,    5.210,    5.210}]}.
{[{{hackney_bstr,'-to_lower/1-lbc$^0/2-0-',2}, 170031,    0.000,  685.779},
  {{hackney_bstr,to_lower,1},                  14079, 1070.261,   62.526}],
 { {hackney_bstr,'-to_lower/1-lbc$^0/2-0-',2}, 184110, 1070.261,  748.305},     %  <----------
 [{{hackney_bstr,'-to_lower/1-lbc$^0/2-0-',2}, 170031,    0.000,  685.779},
  {{hackney_bstr,char_to_lower,1},             170031,  306.065,  305.583},
  {garbage_collect,                             970,   15.891,   15.891}]}.

ACC列表示累计时间,这是每个函数在此函数中花费的总时间,包括子函数。 OWN列是相同的,但没有子功能。通常,您希望按OWN排序以检查哪些功能占用了大部分CPU。

注意输出被分成块,并且在每个块的中间有一行以'%'符号结尾。这是每个块正在讨论的功能,其他行是父项,以及此功能的子项。从这里开始,你就是自己。

在我的情况下,fprof输出显示没有更多关于性能的异常值,所以这就是我停止的地方。