aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjuhlig <[email protected]>2019-05-08 15:05:27 +0200
committerLoïc Hoguin <[email protected]>2019-05-08 16:38:47 +0200
commitd59eef5c737d0b08eb8c16c5316300e863bc935c (patch)
treebe6ab3327717f847677484edf027af9e21266045
parentaa64151149e947145728a1f1339c689f1100720e (diff)
downloadranch-d59eef5c737d0b08eb8c16c5316300e863bc935c.tar.gz
ranch-d59eef5c737d0b08eb8c16c5316300e863bc935c.tar.bz2
ranch-d59eef5c737d0b08eb8c16c5316300e863bc935c.zip
Add the num_conns_sups option
This new option allows configuring the number of connection supervisors. The old behavior can be obtained by setting this value to 1. A value larger than num_acceptors will result in some connection supervisors not being used as the acceptors currently only use one connection supervisor.
-rw-r--r--doc/src/guide/listeners.asciidoc26
-rw-r--r--doc/src/manual/ranch.asciidoc18
-rw-r--r--doc/src/manual/ranch.get_max_connections.asciidoc13
-rw-r--r--doc/src/manual/ranch.info.asciidoc2
-rw-r--r--doc/src/manual/ranch.set_max_connections.asciidoc12
-rw-r--r--src/ranch.erl1
-rw-r--r--src/ranch_acceptor.erl2
-rw-r--r--src/ranch_conns_sup.erl15
-rw-r--r--src/ranch_conns_sup_sup.erl9
-rw-r--r--src/ranch_listener_sup.erl7
-rw-r--r--src/ranch_server.erl33
-rw-r--r--test/acceptor_SUITE.erl56
12 files changed, 146 insertions, 48 deletions
diff --git a/doc/src/guide/listeners.asciidoc b/doc/src/guide/listeners.asciidoc
index 4885c6d..e7ecfec 100644
--- a/doc/src/guide/listeners.asciidoc
+++ b/doc/src/guide/listeners.asciidoc
@@ -182,9 +182,9 @@ socket and that it is operational.
=== Limiting the number of concurrent connections
The `max_connections` transport option allows you to limit the number
-of concurrent connections. It defaults to 1024. Its purpose is to
-prevent your system from being overloaded and ensuring all the
-connections are handled optimally.
+of concurrent connections per connection supervisor (see below).
+It defaults to 1024. Its purpose is to prevent your system from being
+overloaded and ensuring all the connections are handled optimally.
.Customizing the maximum number of concurrent connections
@@ -261,6 +261,26 @@ measure to find the best value for your application.
echo_protocol, []
).
+=== Customizing the number of connection supervisors
+
+By default Ranch will use one connection supervisor for each
+acceptor process (but not vice versa). Their task is to
+supervise the connection processes started by an acceptor.
+The number of connection supervisors can be tweaked.
+
+Note that the association between the individual acceptors and
+connection supervisors is fixed, meaning that acceptors will
+always use the same connection supervisor to start connection
+processes.
+
+.Specifying a custom number of connection supervisors
+
+[source,erlang]
+{ok, _} = ranch:start_listener(tcp_echo,
+ ranch_tcp, #{socket_opts => [{port, 5555}], num_conns_sups => 42}],
+ echo_protocol, []
+).
+
=== When running out of file descriptors
Operating systems have limits on the number of sockets
diff --git a/doc/src/manual/ranch.asciidoc b/doc/src/manual/ranch.asciidoc
index 01de75f..ca8a789 100644
--- a/doc/src/manual/ranch.asciidoc
+++ b/doc/src/manual/ranch.asciidoc
@@ -32,10 +32,10 @@ Connections:
Options:
-* link:man:ranch:get_max_connections(3)[ranch:get_max_connections(3)] - Get the max number of connections
+* link:man:ranch:get_max_connections(3)[ranch:get_max_connections(3)] - Get the max number of connections per connection supervisor
* link:man:ranch:get_protocol_options(3)[ranch:get_protocol_options(3)] - Get the current protocol options
* link:man:ranch:get_transport_options(3)[ranch:get_transport_options(3)] - Get the current transport options
-* link:man:ranch:set_max_connections(3)[ranch:set_max_connections(3)] - Set the max number of connections
+* link:man:ranch:set_max_connections(3)[ranch:set_max_connections(3)] - Set the max number of connections per connection supervisor
* link:man:ranch:set_protocol_options(3)[ranch:set_protocol_options(3)] - Set the protocol options
* link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)] - Set the transport options
@@ -56,7 +56,7 @@ Introspection:
max_conns() = non_neg_integer() | infinity
----
-Maximum number of connections allowed on this listener.
+Maximum number of connections allowed per connection supervisor.
This is a soft limit. The actual number of connections
might be slightly above the limit due to concurrency
@@ -91,6 +91,7 @@ opts() = any() | #{
max_connections => max_conns(),
logger => module(),
num_acceptors => pos_integer(),
+ num_conns_sups => pos_integer(),
shutdown => timeout() | brutal_kill,
socket_opts => any()
}
@@ -122,13 +123,18 @@ Maximum allowed time for the `ranch:handshake/1,2` call to finish.
max_connections (1024)::
-Maximum number of active connections. Soft limit.
-Use `infinity` to disable the limit entirely.
+Maximum number of active connections per connection supervisor.
+Soft limit. Use `infinity` to disable the limit entirely.
num_acceptors (10)::
Number of processes that accept connections.
+num_conns_sups - see below::
+
+Number of processes that supervise connection processes.
+If not specified, defaults to be equal to `num_acceptors`.
+
shutdown (5000)::
Maximum allowed time for children to stop on listener shutdown.
@@ -149,6 +155,8 @@ Unique name used to refer to a listener.
== Changelog
+* *2.0*: The option `max_connections` is now per connection supervisor.
+* *2.0*: The `num_conns_sup` option was added.
* *2.0*: The `socket` option was removed.
* *1.6*: The `logger` option was added.
* *1.6*: The `opt()` type was deprecated in favor of the new `opts()` type.
diff --git a/doc/src/manual/ranch.get_max_connections.asciidoc b/doc/src/manual/ranch.get_max_connections.asciidoc
index 3267c2d..d10c975 100644
--- a/doc/src/manual/ranch.get_max_connections.asciidoc
+++ b/doc/src/manual/ranch.get_max_connections.asciidoc
@@ -2,7 +2,7 @@
== Name
-ranch:get_max_connections - Get the max number of connections
+ranch:get_max_connections - Get the max number of connections per connection supervisor
== Description
@@ -12,7 +12,7 @@ get_max_connections(Ref :: ranch:ref())
-> MaxConns :: ranch:max_conns()
----
-Get the max number of connections.
+Get the max number of connections per connection supervisor.
== Arguments
@@ -22,11 +22,16 @@ The listener name.
== Return value
-The maximum number of connections is returned.
+The maximum number of connections per connection supervisor
+is returned.
+
+== Changelog
+
+* *2.0*: The maximum number of connections is now per connection supervisor.
== Examples
-.Get the max number of connections
+.Get the max number of connections per connection supervisor
[source,erlang]
----
MaxConns = ranch:get_max_connections(example).
diff --git a/doc/src/manual/ranch.info.asciidoc b/doc/src/manual/ranch.info.asciidoc
index 32cbefb..69a8818 100644
--- a/doc/src/manual/ranch.info.asciidoc
+++ b/doc/src/manual/ranch.info.asciidoc
@@ -32,7 +32,7 @@ status:: Listener status, either running or suspended.
ip:: Interface Ranch listens on.
port:: Port number Ranch listens on.
num_acceptors:: Number of acceptor processes.
-max_connections:: Maximum number of connections.
+max_connections:: Maximum number of connections per connection supervisor.
active_connections:: Number of active connections.
all_connections:: Number of connections, including those removed from the count.
transport:: Transport module.
diff --git a/doc/src/manual/ranch.set_max_connections.asciidoc b/doc/src/manual/ranch.set_max_connections.asciidoc
index 2559afe..cc1bb20 100644
--- a/doc/src/manual/ranch.set_max_connections.asciidoc
+++ b/doc/src/manual/ranch.set_max_connections.asciidoc
@@ -2,7 +2,7 @@
== Name
-ranch:set_max_connections - Set the max number of connections
+ranch:set_max_connections - Set the max number of connections per connection supervisor
== Description
@@ -13,7 +13,7 @@ set_max_connections(Ref :: ranch:ref(),
-> ok
----
-Set the max number of connections.
+Set the max number of connections per connection supervisor.
The change will be applied immediately. If the new value is
smaller than the previous one, Ranch will wait for the extra
@@ -28,15 +28,19 @@ The listener name.
MaxConns::
-The new maximum number of connections.
+The new maximum number of connections per connection supervisor.
== Return value
The atom `ok` is always returned. It can be safely ignored.
+== Changelog
+
+* *2.0*: The maximum number of connections is now per connection supervisor.
+
== Examples
-.Set the max number of connections
+.Set the max number of connections per connection supervisor
[source,erlang]
----
ranch:set_max_connections(example, 10000).
diff --git a/src/ranch.erl b/src/ranch.erl
index 2290dee..6649c10 100644
--- a/src/ranch.erl
+++ b/src/ranch.erl
@@ -65,6 +65,7 @@
max_connections => max_conns(),
logger => module(),
num_acceptors => pos_integer(),
+ num_conns_sups => pos_integer(),
shutdown => timeout() | brutal_kill,
socket_opts => any()
}.
diff --git a/src/ranch_acceptor.erl b/src/ranch_acceptor.erl
index cb34d75..2120788 100644
--- a/src/ranch_acceptor.erl
+++ b/src/ranch_acceptor.erl
@@ -17,7 +17,7 @@
-export([start_link/5]).
-export([loop/5]).
--spec start_link(ranch:ref(), non_neg_integer(), inet:socket(), module(), module())
+-spec start_link(ranch:ref(), pos_integer(), inet:socket(), module(), module())
-> {ok, pid()}.
start_link(Ref, AcceptorId, LSocket, Transport, Logger) ->
ConnsSup = ranch_server:get_connections_sup(Ref, AcceptorId),
diff --git a/src/ranch_conns_sup.erl b/src/ranch_conns_sup.erl
index 0ff12c6..171565e 100644
--- a/src/ranch_conns_sup.erl
+++ b/src/ranch_conns_sup.erl
@@ -34,7 +34,6 @@
-record(state, {
parent = undefined :: pid(),
ref :: ranch:ref(),
- acceptor_id :: non_neg_integer(),
conn_type :: conn_type(),
shutdown :: shutdown(),
transport = undefined :: module(),
@@ -47,10 +46,10 @@
%% API.
--spec start_link(ranch:ref(), non_neg_integer(), module(), module()) -> {ok, pid()}.
-start_link(Ref, AcceptorId, Transport, Protocol) ->
+-spec start_link(ranch:ref(), pos_integer(), module(), module()) -> {ok, pid()}.
+start_link(Ref, Id, Transport, Protocol) ->
proc_lib:start_link(?MODULE, init,
- [self(), Ref, AcceptorId, Transport, Protocol]).
+ [self(), Ref, Id, Transport, Protocol]).
%% We can safely assume we are on the same node as the supervisor.
%%
@@ -100,10 +99,10 @@ active_connections(SupPid) ->
%% Supervisor internals.
--spec init(pid(), ranch:ref(), non_neg_integer(), module(), module()) -> no_return().
-init(Parent, Ref, AcceptorId, Transport, Protocol) ->
+-spec init(pid(), ranch:ref(), pos_integer(), module(), module()) -> no_return().
+init(Parent, Ref, Id, Transport, Protocol) ->
process_flag(trap_exit, true),
- ok = ranch_server:set_connections_sup(Ref, AcceptorId, self()),
+ ok = ranch_server:set_connections_sup(Ref, Id, self()),
MaxConns = ranch_server:get_max_connections(Ref),
TransOpts = ranch_server:get_transport_options(Ref),
ConnType = maps:get(connection_type, TransOpts, worker),
@@ -112,7 +111,7 @@ init(Parent, Ref, AcceptorId, Transport, Protocol) ->
Logger = maps:get(logger, TransOpts, error_logger),
ProtoOpts = ranch_server:get_protocol_options(Ref),
ok = proc_lib:init_ack(Parent, {ok, self()}),
- loop(#state{parent=Parent, ref=Ref, acceptor_id=AcceptorId, conn_type=ConnType,
+ loop(#state{parent=Parent, ref=Ref, conn_type=ConnType,
shutdown=Shutdown, transport=Transport, protocol=Protocol,
opts=ProtoOpts, handshake_timeout=HandshakeTimeout,
max_conns=MaxConns, logger=Logger}, 0, 0, []).
diff --git a/src/ranch_conns_sup_sup.erl b/src/ranch_conns_sup_sup.erl
index 423c5db..142b9de 100644
--- a/src/ranch_conns_sup_sup.erl
+++ b/src/ranch_conns_sup_sup.erl
@@ -19,16 +19,17 @@
-export([start_link/4]).
-export([init/1]).
-start_link(Ref, NumAcceptors, Transport, Protocol) ->
+-spec start_link(ranch:ref(), pos_integer(), ranch:opts(), module()) -> {ok, pid()}.
+start_link(Ref, NumConnsSups, Transport, Protocol) ->
ok = ranch_server:cleanup_connections_sups(Ref),
supervisor:start_link(?MODULE, {
- Ref, NumAcceptors, Transport, Protocol
+ Ref, NumConnsSups, Transport, Protocol
}).
-init({Ref, NumAcceptors, Transport, Protocol}) ->
+init({Ref, NumConnsSups, Transport, Protocol}) ->
ChildSpecs = [
{{ranch_conns_sup, N}, {ranch_conns_sup, start_link,
[Ref, N, Transport, Protocol]},
permanent, infinity, supervisor, [ranch_conns_sup]}
- || N <- lists:seq(1, NumAcceptors)],
+ || N <- lists:seq(1, NumConnsSups)],
{ok, {{one_for_one, 1, 5}, ChildSpecs}}.
diff --git a/src/ranch_listener_sup.erl b/src/ranch_listener_sup.erl
index a4cc995..bf533a9 100644
--- a/src/ranch_listener_sup.erl
+++ b/src/ranch_listener_sup.erl
@@ -22,18 +22,19 @@
-> {ok, pid()}.
start_link(Ref, Transport, TransOpts, Protocol, ProtoOpts) ->
NumAcceptors = maps:get(num_acceptors, TransOpts, 10),
+ NumConnsSups = maps:get(num_conns_sups, TransOpts, NumAcceptors),
MaxConns = maps:get(max_connections, TransOpts, 1024),
ranch_server:set_new_listener_opts(Ref, MaxConns, TransOpts, ProtoOpts,
[Ref, Transport, TransOpts, Protocol, ProtoOpts]),
supervisor:start_link(?MODULE, {
- Ref, NumAcceptors, Transport, Protocol
+ Ref, NumAcceptors, NumConnsSups, Transport, Protocol
}).
-init({Ref, NumAcceptors, Transport, Protocol}) ->
+init({Ref, NumAcceptors, NumConnsSups, Transport, Protocol}) ->
ok = ranch_server:set_listener_sup(Ref, self()),
ChildSpecs = [
{ranch_conns_sup_sup, {ranch_conns_sup_sup, start_link,
- [Ref, NumAcceptors, Transport, Protocol]},
+ [Ref, NumConnsSups, Transport, Protocol]},
permanent, infinity, supervisor, [ranch_conns_sup_sup]},
{ranch_acceptors_sup, {ranch_acceptors_sup, start_link,
[Ref, NumAcceptors, Transport]},
diff --git a/src/ranch_server.erl b/src/ranch_server.erl
index 9116217..b77b935 100644
--- a/src/ranch_server.erl
+++ b/src/ranch_server.erl
@@ -88,22 +88,25 @@ cleanup_connections_sups(Ref) ->
ok.
-spec set_connections_sup(ranch:ref(), non_neg_integer(), pid()) -> ok.
-set_connections_sup(Ref, AcceptorId, Pid) ->
- gen_server:call(?MODULE, {set_connections_sup, Ref, AcceptorId, Pid}).
+set_connections_sup(Ref, Id, Pid) ->
+ gen_server:call(?MODULE, {set_connections_sup, Ref, Id, Pid}).
--spec get_connections_sup(ranch:ref(), non_neg_integer()) -> pid().
-get_connections_sup(Ref, AcceptorId) ->
- ets:lookup_element(?TAB, {conns_sup, Ref, AcceptorId}, 2).
+-spec get_connections_sup(ranch:ref(), pos_integer()) -> pid().
+get_connections_sup(Ref, Id) ->
+ ConnsSups = get_connections_sups(Ref),
+ NConnsSups = length(ConnsSups),
+ {_, Pid} = lists:keyfind((Id rem NConnsSups) + 1, 1, ConnsSups),
+ Pid.
--spec get_connections_sups(ranch:ref()) -> [{non_neg_integer(), pid()}].
+-spec get_connections_sups(ranch:ref()) -> [{pos_integer(), pid()}].
get_connections_sups(Ref) ->
- [{AcceptorId, Pid} ||
- [AcceptorId, Pid] <- ets:match(?TAB, {{conns_sup, Ref, '$1'}, '$2'})].
+ [{Id, Pid} ||
+ [Id, Pid] <- ets:match(?TAB, {{conns_sup, Ref, '$1'}, '$2'})].
--spec get_connections_sups() -> [{ranch:ref(), non_neg_integer(), pid()}].
+-spec get_connections_sups() -> [{ranch:ref(), pos_integer(), pid()}].
get_connections_sups() ->
- [{Ref, AcceptorId, Pid} ||
- [Ref, AcceptorId, Pid] <- ets:match(?TAB, {{conns_sup, '$1', '$2'}, '$3'})].
+ [{Ref, Id, Pid} ||
+ [Ref, Id, Pid] <- ets:match(?TAB, {{conns_sup, '$1', '$2'}, '$3'})].
-spec set_listener_sup(ranch:ref(), pid()) -> ok.
set_listener_sup(Ref, Pid) ->
@@ -165,8 +168,8 @@ count_connections(Ref) ->
%% gen_server.
init([]) ->
- ConnMonitors = [{{erlang:monitor(process, Pid), Pid}, {conns_sup, Ref, AcceptorId}} ||
- [Ref, AcceptorId, Pid] <- ets:match(?TAB, {{conns_sup, '$1', '$2'}, '$3'})],
+ ConnMonitors = [{{erlang:monitor(process, Pid), Pid}, {conns_sup, Ref, Id}} ||
+ [Ref, Id, Pid] <- ets:match(?TAB, {{conns_sup, '$1', '$2'}, '$3'})],
ListenerMonitors = [{{erlang:monitor(process, Pid), Pid}, {listener_sup, Ref}} ||
[Ref, Pid] <- ets:match(?TAB, {{listener_sup, '$1'}, '$2'})],
{ok, #state{monitors=ConnMonitors++ListenerMonitors}}.
@@ -177,8 +180,8 @@ handle_call({set_new_listener_opts, Ref, MaxConns, TransOpts, ProtoOpts, StartAr
ets:insert_new(?TAB, {{proto_opts, Ref}, ProtoOpts}),
ets:insert_new(?TAB, {{listener_start_args, Ref}, StartArgs}),
{reply, ok, State};
-handle_call({set_connections_sup, Ref, AcceptorId, Pid}, _, State0) ->
- State = set_monitored_process({conns_sup, Ref, AcceptorId}, Pid, State0),
+handle_call({set_connections_sup, Ref, Id, Pid}, _, State0) ->
+ State = set_monitored_process({conns_sup, Ref, Id}, Pid, State0),
{reply, ok, State};
handle_call({set_listener_sup, Ref, Pid}, _, State0) ->
State = set_monitored_process({listener_sup, Ref}, Pid, State0),
diff --git a/test/acceptor_SUITE.erl b/test/acceptor_SUITE.erl
index dce006a..386bf68 100644
--- a/test/acceptor_SUITE.erl
+++ b/test/acceptor_SUITE.erl
@@ -69,6 +69,10 @@ groups() ->
]}, {supervisor, [
connection_type_supervisor,
connection_type_supervisor_separate_from_connection,
+ supervisor_10_acceptors_1_conns_sup,
+ supervisor_9_acceptors_4_conns_sups,
+ supervisor_10_acceptors_10_conns_sups,
+ supervisor_1_acceptor_10_conns_sups,
supervisor_changed_options_restart,
supervisor_clean_child_restart,
supervisor_clean_restart,
@@ -967,6 +971,58 @@ connection_type_supervisor_separate_from_connection(_) ->
{'EXIT', _} = begin catch ranch:get_port(Name) end,
ok.
+supervisor_10_acceptors_1_conns_sup(_) ->
+ doc("Ensure that using 10 acceptors and 1 connection supervisor works."),
+ ok = do_supervisor_n_acceptors_m_conns_sups(10, 1).
+
+supervisor_9_acceptors_4_conns_sups(_) ->
+ doc("Ensure that using 9 acceptors and 4 connection supervisors works."),
+ ok = do_supervisor_n_acceptors_m_conns_sups(9, 4).
+
+supervisor_10_acceptors_10_conns_sups(_) ->
+ doc("Ensure that using 10 acceptors and 10 connection supervisors works."),
+ ok = do_supervisor_n_acceptors_m_conns_sups(10, 10).
+
+supervisor_1_acceptor_10_conns_sups(_) ->
+ doc("Ensure that using 1 acceptor and 10 connection supervisors works."),
+ ok = do_supervisor_n_acceptors_m_conns_sups(1, 10).
+
+do_supervisor_n_acceptors_m_conns_sups(NumAcceptors, NumConnsSups) ->
+ Name = name(),
+ {ok, Pid} = ranch:start_listener(Name,
+ ranch_tcp, #{num_conns_sups => NumConnsSups, num_acceptors => NumAcceptors},
+ notify_and_wait_protocol, [{msg, connected}, {pid, self()}]),
+ Port = ranch:get_port(Name),
+ ConnsSups = [ConnsSup || {_, ConnsSup} <- ranch_server:get_connections_sups(Name)],
+ NumConnsSups = length(ConnsSups),
+ {ranch_acceptors_sup, AcceptorsSup, supervisor, _} =
+ lists:keyfind(ranch_acceptors_sup, 1, supervisor:which_children(Pid)),
+ AcceptorIds = [AcceptorId ||
+ {{acceptor, _, AcceptorId}, _, worker, _} <- supervisor:which_children(AcceptorsSup)],
+ NumAcceptors = length(AcceptorIds),
+ AcceptorConnsSups0 = [ranch_server:get_connections_sup(Name, AcceptorId) ||
+ AcceptorId <- AcceptorIds],
+ AcceptorConnsSups1 = lists:usort(AcceptorConnsSups0),
+ if
+ NumAcceptors > NumConnsSups ->
+ NumConnsSups = length(AcceptorConnsSups1),
+ [] = ConnsSups -- AcceptorConnsSups1;
+ NumAcceptors < NumConnsSups ->
+ NumAcceptors = length(AcceptorConnsSups1),
+ [] = AcceptorConnsSups1 -- ConnsSups;
+ NumAcceptors =:= NumConnsSups ->
+ NumConnsSups = length(AcceptorConnsSups1),
+ NumAcceptors = length(AcceptorConnsSups1),
+ [] = ConnsSups -- AcceptorConnsSups1,
+ [] = AcceptorConnsSups1 -- ConnsSups
+ end,
+ ok = connect_loop(Port, 100, 0),
+ 100 = receive_loop(connected, 100),
+ 100 = ranch_server:count_connections(Name),
+ ok = ranch:stop_listener(Name),
+ {'EXIT', _} = begin catch ranch:get_port(Name) end,
+ ok.
+
supervisor_changed_options_restart(_) ->
doc("Ensure that a listener is restarted with changed transport options."),
Name = name(),