【发布时间】: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 连接升级。