В настоящее время я проверяю экстремальные условия на фрагменте кода, написанного на 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 соединений одновременно с нескольких серверов. В то время как ssl, принимающий бит кода C++, займет 10 секунд, чтобы принять их все (которые даже не имеют нескольких ожидающих принятия), в Erlang это совсем другое. Он будет принимать не более 20 подключений в секунду (согласно информации netstat, в то время как C++ принимает больше, чем 1K подключений в секунду)
Хотя 10K подключений ожидают подтверждения, я также пытаюсь подключиться вручную.
openssl s_client -ssl3 -ign_eof -connect myserver.com:4242
3 случая, когда я это делаю:
Когда я пытаюсь подключиться вручную с 2 консолей, первое рукопожатие не всегда будет первым, которое попыталось подключиться... Что я обнаружил особенно.
Конфигурация сервера:
Я запускаю оболочку Erlang с помощью:
$erl +S 8:8
РЕДАКТИРОВАТЬ 1:
Я даже пытался принять соединение с gen_tcp, а затем обновить соединение до SSL.Все та же проблема, он не будет принимать более 10 подключений в секунду ... Это делает ssl: ssl_accept? блокирует ли он что-нибудь, что помешало бы Erlang масштабировать это?
РЕДАКТИРОВАТЬ 2:
Посмотрев на другой сервер SSL, созданный в erlang, кажется, что они используют какой-то драйвер для соединения SSL/TLS, мои примеры — RabbitMQ и EjabberD. Нигде в их коде Erlang нет ssl:ssl_accept, я мало исследовал, но, похоже, они создали свой собственный драйвер, чтобы обновить TCP-сокет до SSL/TLS. Это потому, что есть проблема с модулем SSL Erlang? Кто-нибудь знает, почему они используют специальный драйвер для SSL/TLS?
Есть мысли по этому поводу?