Erlang 接受 SSL 连接真的很慢(与C++相比)



我目前正在用 Erlang 编写的一段代码上测试极端条件。

我已经实现了学习优素朗.com的主管技术,使其具有多重接受能力。

这里的代码略有修改,以处理管理引擎的SSL连接:

-module(mymodule).
-behaviour(supervisor).
-export([start/0, start_socket/0]).
-define(SSL_OPTIONS, [{active, true},
              {mode, list},
              {reuseaddr, true},
              {cacertfile, "./ssl_key/server/gd_bundle.crt"},
              {certfile, "./ssl_key/server/cert.pem"},
              {keyfile, "./ssl_key/server/key.pem"},
              {password, "********"}
             ]).
-export([init/1]).
start_link() ->
    application:start(crypto),
    crypto:start(),
    application:start(public_key),
    application:start(ssl),
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
    {ok, LSocket} = ssl:listen(4242, ?SSL_OPTIONS),
    spawn_link(fun empty_listeners/0),
    {ok, {{simple_one_for_one, 60, 3600},
      [{socket,
        {mymodule_serv, start_link, [LSocket]}, % pass the socket!
        temporary, 1000, worker, [mymodule_serv]}
      ]}}.
empty_listeners() ->
    [start_socket() || _ <- lists:seq(1,100)],
    ok.
start_socket() ->
    supervisor:start_child(?MODULE, []).

这是gen_server的代码,它将代表每个客户端连接:

-module(mymodule_serv).
-behaviour(gen_server).
-export([start_link/1]).
-export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3, handle_info/2]).
start_link(Socket) ->
    gen_server:start_link(?MODULE, Socket, []).
init(Socket) ->
    gen_server:cast(self(), accept),
    {ok, #client{socket=Socket, pid=self()}}.
handle_call(_E, _From, Client) ->
    {noreply, Client}.
handle_cast(accept, C = #client{socket=ListenSocket}) ->
    {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
    mymodule:start_socket(),
    ssl:ssl_accept(AcceptSocket),
    ssl:setopts(AcceptSocket, [{active, true}, {mode, list}]),
    {noreply, C#client{socket=AcceptSocket, state=connecting}}.
[...]

我能够从多个服务器一次启动近 10.000 个连接。虽然 SSL C++接受一点代码需要 10 秒才能接受所有代码(甚至没有多个接受挂起),但在 Erlang 中,这是完全不同的。它每秒最多接受 20 个连接(根据 netstat 信息,而C++每秒接受 1K 个连接)

当 10K 连接正在等待接受时,我也在手动尝试连接。

openssl s_client -ssl3 -ign_eof -connect myserver.com:4242

当我这样做时会发生 3 种情况:

  • 连接只是超时
  • 连接
  • 将在等待至少 30 秒后连接。
  • 连接将几乎直接发生

当我尝试使用 2 个控制台手动连接时,第一次握手并不总是第一个尝试连接......我发现特别。

服务器配置为:

  • 2 x 英特尔®至强® E5620
  • 8x 2.4千兆赫
  • 24 去内存

我用 Erlang 外壳开始:

$erl +S 8:8

编辑 1:

我什至尝试接受与gen_tcp的连接,然后将连接升级到SSL连接。仍然是同样的问题,它每秒不会接受超过 10 个连接......ssl:ssl_accept在这样做吗?它是否锁定了任何会阻止 Erlang 扩展此内容的内容?

编辑2:

查看了在erlang中创建的其他SSL服务器之后,似乎他们使用某种驱动程序进行SSL/TLS连接,我的例子是RabbitMQ和EjabberD。他们的 Erlang 代码中没有 ssl:ssl_accept,我没有进行很多调查,但似乎他们已经创建了自己的驱动程序,以便将 TCP 套接字升级到 SSL/TLS 套接字。那是因为 Erlang 的模块 SSL 有问题吗?有谁知道他们为什么使用 SSL/TLS 的自定义驱动程序?

对此有什么想法吗?

实际上,

并不是SSL接受或握手减慢了整个事情的速度。

我们在 erlang 问题列表中发现这是积压。

默认情况下,积压工作设置为 5。我已将其设置为SOMAXCONN,现在一切正常!

最新更新