Skip to content

Commit

Permalink
Add the count_process_dynamic service configuration option for dynami…
Browse files Browse the repository at this point in the history
…cally adjusting the number of processes used for a single service instance (i.e., single service_id) based on changes in the rate of incoming service requests. Add the rate-based hibernate service configuration option for internal services (a list of options for conditional hibernation). #57 #56
  • Loading branch information
okeuday committed Dec 13, 2013
1 parent b2ffb25 commit e4e5bff
Show file tree
Hide file tree
Showing 14 changed files with 1,633 additions and 287 deletions.
9 changes: 9 additions & 0 deletions src/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# -*- coding: utf-8; tab-width: 4; -*-
# ex: set fileencoding=utf-8 softtabstop=4 tabstop=4 expandtab:

2013-12-13 Michael Truog <mjtruog [at] gmail (dot) com>

* Add the count_process_dynamic service configuration option for
dynamically adjusting the number of processes used for a single
service instance (i.e., single service_id) based on changes in the
rate of incoming service requests
* Add the rate-based hibernate service configuration option for internal
services (a list of options for conditional hibernation)

2013-12-11 Michael Truog <mjtruog [at] gmail (dot) com>

* Add cloudi_service_http_cowboy:close/1 for forcing a cowboy
Expand Down
26 changes: 23 additions & 3 deletions src/cloudi.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,13 @@
"tests/http_req/http_req_c.py",
[],
none, tcp, default,
5000, 5000, 5000, [api], undefined, 1, 1, 5, 300, []},
5000, 5000, 5000, [api], undefined,
1.0, 1, 5, 300,
[{count_process_dynamic,
[{rate_request_max, 1.1},
{rate_request_min, 0.9},
{count_max, 4.0},
{count_min, 0.25}]}]},
{external,
"/tests/http_req/",
"@JAVA@",
Expand All @@ -304,14 +310,28 @@
[],
none,
4294967195, 4294967195, 4294967195, % test limits
[api], undefined, 1, 5, 300, []},
[api], undefined, 1.0, 5, 300,
[{hibernate,
[{rate_request_min, 0.9}]},
{count_process_dynamic,
[{rate_request_max, 1.1},
{rate_request_min, 0.9},
{count_max, 2.0},
{count_min, 0.25}]}]},
{internal,
"/tests/http_req/",
cloudi_service_http_req,
[],
none,
101, 101, 101, % test limits
[api], undefined, 1, 5, 300, []},
[api], undefined, 1.0, 5, 300,
[{hibernate,
[{rate_request_min, 0.9}]},
{count_process_dynamic,
[{rate_request_max, 1.1},
{rate_request_min, 0.9},
{count_max, 2.0},
{count_min, 0.25}]}]},
{internal,
"/tests/http_req/",
cloudi_service_filesystem,
Expand Down
226 changes: 149 additions & 77 deletions src/lib/cloudi_core/src/cloudi_configuration.erl

Large diffs are not rendered by default.

43 changes: 33 additions & 10 deletions src/lib/cloudi_core/src/cloudi_configuration.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,20 @@
% instead of a returned null response message
response_timeout_immediate_max = 20000 % milliseconds
:: cloudi_service_api:response_timeout_immediate_max_milliseconds(),
% should the process count be varied automatically based on the
% rate of service processing within a specific time period.
% the count max/min specify limits for the count_process changes
% as either floating point percentages (the result is rounded) or
% as integer absolutes.
count_process_dynamic = false
:: false |
list({period,
cloudi_rate_based_configuration:period_seconds()} |
{rate_request_max, number()} | % service reqs/second
{rate_request_min, number()} | % service reqs/second
{count_max, number()} | % float multiplier or
{count_min, number()}) | % integer absolute
tuple(),
% provide a scope for all subscribe/unsubscribe and messaging
% (i.e., all service name usage is within the scope). Using a
% different scope can help avoid contention when using an immediate
Expand All @@ -124,12 +138,17 @@
% checked during service startup (e.g., after service restarts).
% (all time parameters are specified in milliseconds)
monkey_latency = false
:: list({time_uniform_min, pos_integer()} |
{time_uniform_max, pos_integer()} |
{time_gaussian_mean, pos_integer()} |
:: list({time_uniform_min,
cloudi_runtime_testing:time_milliseconds()} |
{time_uniform_max,
cloudi_runtime_testing:time_milliseconds()} |
{time_gaussian_mean,
cloudi_runtime_testing:time_milliseconds()} |
{time_gaussian_stddev, float()} |
{time_absolute, pos_integer()}) |
system | false,
{time_absolute,
cloudi_runtime_testing:time_milliseconds()}) |
system | false |
tuple(),
% cause service termination based on the probability parameter
% (checked for each service request and info message, if necessary).
% If "system" is set, the cloudi_core Erlang application env value
Expand All @@ -139,7 +158,8 @@
monkey_chaos = false
:: list({probability_request, float()} |
{probability_day, float()}) |
system | false,
system | false |
tuple(),

% Only Relevant For Internal Services:

Expand Down Expand Up @@ -182,9 +202,14 @@
:: boolean(),
% should a mostly idle service hibernate automatically to conserve
% memory at the expense of extra garbage collections and an empty
% stack trace.
% stack trace. if a list is provided, hibernate will occur when
% the rate of service processing drops below the minimum specified.
hibernate = false
:: boolean(),
:: boolean() |
list({period,
cloudi_rate_based_configuration:period_seconds()} |
{rate_request_min, number()}) | % service reqs/second
tuple(),
% should the service be reloaded automatically when an Erlang module
% file changes? should only be used during service development.
reload = false
Expand All @@ -194,8 +219,6 @@
automatic_loading = true
:: boolean()
}).
-define(CONFIG_SERVICE_OPTIONS_EXTERNAL_SIZE,
(#config_service_options.application_name - 1)).

% internal service parameters
-record(config_service_internal,
Expand Down
43 changes: 14 additions & 29 deletions src/lib/cloudi_core/src/cloudi_configurator.erl
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,12 @@ service_start(#config_service_internal{
Error
end;

service_start(#config_service_external{count_process = Count} = Service,
service_start(#config_service_external{count_process = Count,
count_thread = CountThread} = Service,
Timeout) ->
service_start_external(concurrency(Count), Service, timeout_decr(Timeout)).
NewCountThread = concurrency(CountThread),
service_start_external(concurrency(Count), Service,
NewCountThread, timeout_decr(Timeout)).

service_stop(#config_service_internal{} = Service, Remove, Timeout)
when is_boolean(Remove) ->
Expand All @@ -199,7 +202,7 @@ concurrency(I)
when is_float(I) ->
if
I > 1.0 ->
ceil(I * erlang:system_info(schedulers));
cloudi_math:ceil(I * erlang:system_info(schedulers));
I > 0.0, I < 1.0 ->
erlang:max(1, erlang:round(I * erlang:system_info(schedulers)));
I == 1.0 ->
Expand Down Expand Up @@ -584,23 +587,21 @@ service_start_internal(Count0,
uuid = ID} = Service, Timeout) ->
Count1 = Count0 - 1,
case cloudi_services_monitor:monitor(cloudi_spawn, start_internal,
[Count1,
Module, Args, TimeoutInit,
[Module, Args, TimeoutInit,
Prefix, TimeoutAsync, TimeoutSync,
DestRefresh, DestListDeny,
DestListAllow, Options, ID],
MaxR, MaxT, ID, Timeout) of
Count1, 1, MaxR, MaxT, ID, Timeout) of
ok ->
service_start_internal(Count1, Service, Timeout);
{error, _} = Error ->
Error
end.

service_start_external(0, Service, _) ->
service_start_external(0, Service, _, _) ->
{ok, Service};
service_start_external(Count0,
#config_service_external{
count_thread = CountThread,
file_path = FilePath,
args = Args,
env = Env,
Expand All @@ -616,17 +617,19 @@ service_start_external(Count0,
options = Options,
max_r = MaxR,
max_t = MaxT,
uuid = ID} = Service, Timeout) ->
uuid = ID} = Service, CountThread, Timeout) ->
Count1 = Count0 - 1,
case cloudi_services_monitor:monitor(cloudi_spawn, start_external,
[concurrency(CountThread),
[CountThread,
FilePath, Args, Env,
Protocol, BufferSize, TimeoutInit,
Prefix, TimeoutAsync, TimeoutSync,
DestRefresh, DestListDeny,
DestListAllow, Options, ID],
Count1, CountThread,
MaxR, MaxT, ID, Timeout) of
ok ->
service_start_external(Count0 - 1, Service, Timeout);
service_start_external(Count1, Service, CountThread, Timeout);
{error, _} = Error ->
Error
end.
Expand Down Expand Up @@ -700,21 +703,3 @@ timeout_decr(infinity) ->
timeout_decr(Timeout) when is_integer(Timeout) ->
Timeout - ?TIMEOUT_DELTA.

ceil(X) ->
T = erlang:trunc(X),
if
X > T ->
T + 1;
true ->
T
end.

%floor(X) ->
% T = erlang:trunc(X),
% if
% X < T ->
% T - 1;
% true ->
% T
% end.

2 changes: 2 additions & 0 deletions src/lib/cloudi_core/src/cloudi_core.app.src.in
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
cloudi_lists,
cloudi_logger,
cloudi_logger_interface,
cloudi_math,
cloudi_nodes,
cloudi_os_spawn,
cloudi_pool,
cloudi_pool_sup,
cloudi_proplists,
cloudi_rate_based_configuration,
cloudi_request,
cloudi_response,
cloudi_runtime_testing,
Expand Down
93 changes: 93 additions & 0 deletions src/lib/cloudi_core/src/cloudi_math.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
%-*-Mode:erlang;coding:utf-8;tab-width:4;c-basic-offset:4;indent-tabs-mode:()-*-
% ex: set ft=erlang fenc=utf-8 sts=4 ts=4 sw=4 et:
%%%
%%%------------------------------------------------------------------------
%%% @doc
%%% ==Math operations==
%%% @end
%%%
%%% BSD LICENSE
%%%
%%% Copyright (c) 2009-2013, Michael Truog <mjtruog at gmail dot com>
%%% All rights reserved.
%%%
%%% Redistribution and use in source and binary forms, with or without
%%% modification, are permitted provided that the following conditions are met:
%%%
%%% * Redistributions of source code must retain the above copyright
%%% notice, this list of conditions and the following disclaimer.
%%% * Redistributions in binary form must reproduce the above copyright
%%% notice, this list of conditions and the following disclaimer in
%%% the documentation and/or other materials provided with the
%%% distribution.
%%% * All advertising materials mentioning features or use of this
%%% software must display the following acknowledgment:
%%% This product includes software developed by Michael Truog
%%% * The name of the author may not be used to endorse or promote
%%% products derived from this software without specific prior
%%% written permission
%%%
%%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
%%% CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
%%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
%%% OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
%%% DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
%%% CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
%%% SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
%%% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
%%% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
%%% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
%%% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
%%% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
%%% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
%%% DAMAGE.
%%%
%%% @author Michael Truog <mjtruog [at] gmail (dot) com>
%%% @copyright 2009-2013 Michael Truog
%%% @version 1.3.1 {@date} {@time}
%%%------------------------------------------------------------------------

-module(cloudi_math).
-author('mjtruog [at] gmail (dot) com').

%% external interface
-export([ceil/1, floor/1]).

%%%------------------------------------------------------------------------
%%% External interface functions
%%%------------------------------------------------------------------------

%%-------------------------------------------------------------------------
%% @doc
%% ===Provide a ceiling function.===
%% @end
%%-------------------------------------------------------------------------

-spec ceil(number()) -> integer().

ceil(X) ->
T = erlang:trunc(X),
if
X > T ->
T + 1;
true ->
T
end.

%%-------------------------------------------------------------------------
%% @doc
%% ===Provide a floor function.===
%% @end
%%-------------------------------------------------------------------------

-spec floor(number()) -> integer().

floor(X) ->
T = erlang:trunc(X),
if
X < T ->
T - 1;
true ->
T
end.

0 comments on commit e4e5bff

Please sign in to comment.