【问题标题】:Erlang accepting SSL connection is really slow (comparing to C++)Erlang 接受 SSL 连接真的很慢(与 C++ 相比)
【发布时间】:2025-12-18 22:55:02
【问题描述】:

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

我已经实现了learnyousomeerlang.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 个连接。 虽然接受 C++ 代码的 ssl 需要 10 秒才能接受所有这些(甚至没有多个接受待处理),但在 Erlang 中这是完全不同的。它每秒最多接受 20 个连接(根据 netstat 信息,而 C++ 每秒接受 1K 连接)

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

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

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

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

当我尝试手动连接 2 个控制台时,第一个完成的握手并不总是第一个尝试连接...我发现这很特别。

服务器配置为:

  • 2 个英特尔® 至强® E5620
  • 8x 2.4GHz
  • 24 转内存

我正在启动 Erlang shell:

$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 使用自定义驱动程序?

对此有什么想法吗?

【问题讨论】:

  • 我建议将此问题发布到 erlang 问题列表中,以便从 otp 团队(Ingela 等人)那里获得答案。
  • 我也考虑过......但是可能不是*团队的人我有答案,或者至少有一些线索......
  • 如果您不方便直接询问 OTP 团队,请尝试询问 RabbitMQ 或 EjabberD 的开发人员。他们现在应该为什么他们选择了各自的解决方案!
  • @EmilVikström:实际上我刚刚在 erlang 问题列表中提出了我的问题,还没有 OTP 团队回答。但我们正在努力。如果有有趣的事情发生,我当然会更新我的帖子。
  • @EmilVikström :根据 OTP 团队的 Ingela 的说法,他们已经这样做了,因为以前版本的 OTP(创建项目时)不支持 SSL/TLS 连接升级。

标签: sockets ssl erlang


【解决方案1】:

实际上,减缓整个过程的并不是 SSL 接受或握手。

我们在 erlang 问题列表中发现它是 backlog。

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

【讨论】: