当我的 Erlang TCP 代理收到很多并发请求时,为什么性能下降这么多?

Jan*_*ard 4 erlang performance proxy networking tcp

出于学习目的,我在 Erlang 中编写了一个简单的 TCP 代理。它可以工作,但是当我使用 ab (Apache Bench) 发出许多并发请求时,我遇到了奇怪的性能下降。让我感到疑惑的不是性能下降本身,而是下降的规模。后端是 nginx 作为 Web 服务器。我的代理位于 ab 和 nginx 之间。

这是我的代理的代码。

-module(proxy).
-export([start/3]).

start(InPort, OutHost, OutPort) ->
  {ok, Listen} = gen_tcp:listen(InPort, [binary, {packet, 0}, {active, once}]),
  spawn(fun() -> connect(Listen, OutHost, OutPort) end).

connect(Listen, OutHost, OutPort) ->
  {ok, Client} = gen_tcp:accept(Listen),
  spawn(fun() -> connect(Listen, OutHost, OutPort) end),
  {ok, Server} = gen_tcp:connect(OutHost, OutPort, [binary, {packet, 0}, {active, once}]),
  loop(Client, Server).

loop(Client, Server) ->
  receive
    {tcp, Client, Data} ->
      gen_tcp:send(Server, Data),
      inet:setopts(Client, [{active, once}]),
      loop(Client, Server);
    {tcp, Server, Data} ->
      gen_tcp:send(Client, Data),
      inet:setopts(Server, [{active, once}]),
      loop(Client, Server);
    {tcp_closed, _} ->
      ok
  end.
Run Code Online (Sandbox Code Playgroud)

在我的代理上发出 64 个连续请求,我得到了非常好的结果。

ab -n 64 127.0.0.1:80/

Concurrency Level:      1
Time taken for tests:   0.097 seconds
Complete requests:      64
Failed requests:        0
Write errors:           0
Total transferred:      23168 bytes
HTML transferred:       9664 bytes
Requests per second:    659.79 [#/sec] (mean)
Time per request:       1.516 [ms] (mean)
Time per request:       1.516 [ms] (mean, across all concurrent requests)
Transfer rate:          233.25 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      0       1
Processing:     1    1   0.5      1       2
Waiting:        0    1   0.4      1       2
Total:          1    1   0.5      1       2

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      2
  75%      2
  80%      2
  90%      2
  95%      2
  98%      2
  99%      2
 100%      2 (longest request)
Run Code Online (Sandbox Code Playgroud)

它只是比直接对 nginx 使用 Apache Bench 慢一点。

但是在代理上发出 64 个并发请求,性能下降得非常疯狂

ab -n 64 -c 64 127.0.0.1:80/

Concurrency Level:      64
Time taken for tests:   2.011 seconds
Complete requests:      64
Failed requests:        0
Write errors:           0
Total transferred:      23168 bytes
HTML transferred:       9664 bytes
Requests per second:    31.82 [#/sec] (mean)
Time per request:       2011.000 [ms] (mean)
Time per request:       31.422 [ms] (mean, across all concurrent requests)
Transfer rate:          11.25 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   31 121.7      0     501
Processing:     3 1135 714.4   1001    2006
Waiting:        3 1134 714.3   1000    2005
Total:          3 1167 707.8   1001    2006

Percentage of the requests served within a certain time (ms)
  50%   1001
  66%   1502
  75%   2003
  80%   2004
  90%   2005
  95%   2005
  98%   2005
  99%   2006
 100%   2006 (longest request)
Run Code Online (Sandbox Code Playgroud)

什么/哪里有问题?我预计性能会降低,但为什么会这么高?看看每秒的请求数!

我是否使用 +A 给 erl 很多线程似乎并不重要。我什至尝试过 SMP,但结果几乎相同。

我的设置:Windows 7 64、Intel QuadCore、8GB RAM。我在使用 128 个并发请求的 Ubuntu 上得到了类似的结果。

编辑:包括新的见解。请求的总数无关紧要。这只是并发请求的计数。

Hyn*_*dil 5

这部分connect/3是连续的:

connect(Listen, OutHost, OutPort) ->
  {ok, Client} = gen_tcp:accept(Listen),
  spawn(fun() -> connect(Listen, OutHost, OutPort) end),
Run Code Online (Sandbox Code Playgroud)

在新生成的进程gen_tcp:accept/1准备就绪之前,您无法接受新连接。它可能涉及您的代码的瓶颈。在这种情况下,您可以尝试使用“接受者”池来提高性能。我还会尝试添加 catch all 子句loop/2 receive以避免偶然出现邮箱填充。

还有你的erl参数是什么?是否有+A 线程+K true参与?