Skip to content

Commit 983b4cd

Browse files
Merge pull request #2 from fernandoareias/feature/add-ranch
Feature/add ranch
2 parents d54254b + afeb91a commit 983b4cd

14 files changed

Lines changed: 375 additions & 148 deletions

load-tests/test-script.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import http from 'k6/http';
22
import { check } from 'k6';
33

44
export let options = {
5-
vus: 10, // Número de usuários virtuais
6-
duration: '60s',
5+
vus: 1000, // Número de usuários virtuais
6+
duration: '300s',
77
};
88

99
export default function () {

rebar.config

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{erl_opts, [debug_info]}.
2-
{deps, []}.
2+
{deps, [
3+
{ranch, "2.1.0"}
4+
]}.
35

46
{shell, [
57
%% {config, "config/sys.config"},

rebar.lock

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
[].
1+
{"1.2.0",
2+
[{<<"ranch">>,{pkg,<<"ranch">>,<<"2.1.0">>},0}]}.
3+
[
4+
{pkg_hash,[
5+
{<<"ranch">>, <<"2261F9ED9574DCFCC444106B9F6DA155E6E540B2F82BA3D42B339B93673B72A3">>}]},
6+
{pkg_hash_ext,[
7+
{<<"ranch">>, <<"244EE3FA2A6175270D8E1FC59024FD9DBC76294A321057DE8F803B1479E76916">>}]}
8+
].

src/lib/stage_behaviour.erl

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
-define(is_false(X), ((X) == false)).
1313

14+
-define(BACKPRESSURE_THRESHOLD, 50).
15+
-define(BACKPRESSURE_ATTEMPTS, 5).
16+
1417
-callback handle_command(Command :: term()) ->
1518
{ok, Result :: term()} | {error, Reason :: term()} |
1619
{forward, NextStagePid :: pid(), NewCommand :: term()}.
@@ -39,8 +42,12 @@ loop(StageModule, _) ->
3942
{command, Command, From} ->
4043
StageKey = list_to_atom(atom_to_list(StageModule) ++ "_workers"),
4144
[{StageKey, WorkersList}] = ets:lookup(erlda_workers_table, StageKey),
42-
WorkerPid = pick_random_worker(WorkersList),
43-
WorkerPid ! {work, Command, From},
45+
case pick_worker_under_threshold(WorkersList, ?BACKPRESSURE_THRESHOLD, ?BACKPRESSURE_ATTEMPTS) of
46+
{ok, WorkerPid} ->
47+
WorkerPid ! {work, Command, From};
48+
busy ->
49+
From ! {stage_error, busy}
50+
end,
4451
loop(StageModule, true);
4552
{worker_ready, _WorkerPid} ->
4653
loop(StageModule, true);
@@ -72,13 +79,30 @@ start_workers(StageModule, Count) when Count > 0 ->
7279
[spawn_worker(StageModule) || _ <- lists:seq(1, Count)].
7380

7481
spawn_worker(StageModule) ->
75-
worker:spawn_worker(StageModule).
82+
stage_worker:spawn_worker(StageModule).
7683

7784
pick_random_worker(Workers) ->
7885
N = length(Workers),
7986
Index = rand:uniform(N),
8087
lists:nth(Index, Workers).
8188

89+
pick_worker_under_threshold(_Workers, _Threshold, Attempts) when Attempts =< 0 ->
90+
busy;
91+
pick_worker_under_threshold([], _Threshold, _Attempts) ->
92+
busy;
93+
pick_worker_under_threshold(Workers, Threshold, Attempts) ->
94+
WorkerPid = pick_random_worker(Workers),
95+
case queue_len(WorkerPid) < Threshold of
96+
true -> {ok, WorkerPid};
97+
false -> pick_worker_under_threshold(Workers, Threshold, Attempts - 1)
98+
end.
99+
100+
queue_len(Pid) when is_pid(Pid) ->
101+
case process_info(Pid, message_queue_len) of
102+
{message_queue_len, N} -> N;
103+
_ -> 0
104+
end.
105+
82106

83107
add_worker(StageModule) ->
84108
StageKey = list_to_atom(atom_to_list(StageModule) ++ "_workers"),

src/lib/stage_controller.erl

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,22 @@
55
-record(controller_state, {
66
stage_module,
77
stage_pid,
8-
min_workers = 1,
9-
max_workers = 20,
10-
scale_up_threshold = 10,
11-
scale_down_threshold = 2,
12-
check_interval = 5000 % 5s
8+
min_workers = 10,
9+
max_workers = 200,
10+
scale_up_threshold = 100,
11+
scale_down_threshold = 10,
12+
check_interval = 1000, % 1s
13+
consecutive_hot = 0,
14+
consecutive_cold = 0,
15+
last_action_ms = 0,
16+
action_cooldown_ms = 2000,
17+
min_samples_to_act = 1
1318
}).
1419

1520
spawn_controller(StageModule, StagePid) ->
1621
State = #controller_state{stage_module = StageModule, stage_pid = StagePid},
1722
Pid = spawn(?MODULE, loop, [State]),
18-
ControllerName = list_to_atom(atom_to_list(StageModule) ++ "_controler"),
23+
ControllerName = list_to_atom(atom_to_list(StageModule) ++ "_controller"),
1924
register(ControllerName, Pid),
2025
Pid.
2126

@@ -42,25 +47,60 @@ check_stage_balance(State) ->
4247

4348
case is_process_alive(StagePid) of
4449
true ->
45-
{message_queue_len, QLen} = process_info(StagePid, message_queue_len),
50+
MaxWorkerQLen = max_worker_queue(StageModule),
4651
NumWorkers = stage_behaviour:count_workers(StageModule),
4752

48-
io:format("[+][~p][~p] - Analisando métricas: QLen=~p, Workers=~p, Up=~p, Down=~p~n",
49-
[calendar:local_time(), self(), QLen, NumWorkers, Up, Down]),
53+
io:format("[+][~p][~p] - Métricas: MaxWorkerQLen=~p, Workers=~p, Up=~p, Down=~p~n",
54+
[calendar:local_time(), self(), MaxWorkerQLen, NumWorkers, Up, Down]),
5055

51-
if
52-
QLen > Up andalso NumWorkers < Max ->
53-
io:format("[+][~p][~p] - Aumento workers para ~p. QLen: ~p, Workers: ~p~n", [calendar:local_time(), self(), StageModule, QLen, NumWorkers]),
54-
stage_behaviour:add_worker(StageModule, self());
55-
56-
QLen < Down andalso NumWorkers > Min ->
57-
io:format("[-][~p][~p] - Diminuindo workers para ~p. QLen: ~p, Workers: ~p~n", [calendar:local_time(), self(), StageModule, QLen, NumWorkers]),
58-
stage_behaviour:remove_worker(StageModule, any);
59-
true ->
60-
io:format("[+][~p][~p] - Workers estáveis para ~p. QLen: ~p, Workers: ~p~n", [calendar:local_time(), self(), StageModule, QLen, NumWorkers])
61-
end;
56+
NewState1 =
57+
if MaxWorkerQLen > Up -> incr_hot(reset_cold(State));
58+
MaxWorkerQLen < Down -> incr_cold(reset_hot(State));
59+
true -> reset_hot(reset_cold(State))
60+
end,
61+
NewState2 = maybe_scale(StageModule, NumWorkers, Min, Max, NewState1),
62+
NewState2;
6263
false ->
6364
io:format("[-][~p][~p] - Stage ~p não está mais vivo~n", [calendar:local_time(), self(), StageModule])
6465
end,
6566
State.
67+
68+
max_worker_queue(StageModule) ->
69+
StageKey = list_to_atom(atom_to_list(StageModule) ++ "_workers"),
70+
case ets:lookup(erlda_workers_table, StageKey) of
71+
[{StageKey, Workers}] when is_list(Workers), Workers =/= [] ->
72+
lists:max([queue_len(W) || W <- Workers]);
73+
_ -> 0
74+
end.
75+
76+
queue_len(Pid) when is_pid(Pid) ->
77+
case process_info(Pid, message_queue_len) of
78+
{message_queue_len, N} -> N;
79+
_ -> 0
80+
end.
81+
82+
now_ms() -> erlang:monotonic_time(millisecond).
83+
84+
cooldown_over(#controller_state{ last_action_ms = T, action_cooldown_ms = C }) ->
85+
now_ms() - T >= C.
86+
87+
incr_hot(S = #controller_state{ consecutive_hot = H }) -> S#controller_state{ consecutive_hot = H + 1 }.
88+
incr_cold(S = #controller_state{ consecutive_cold = C }) -> S#controller_state{ consecutive_cold = C + 1 }.
89+
reset_hot(S) -> S#controller_state{ consecutive_hot = 0 }.
90+
reset_cold(S) -> S#controller_state{ consecutive_cold = 0 }.
91+
92+
maybe_scale(StageModule, NumWorkers, Min, Max, S = #controller_state{ consecutive_hot = H, consecutive_cold = C, min_samples_to_act = K }) ->
93+
CanAct = cooldown_over(S),
94+
case true of
95+
_ when H >= K andalso NumWorkers < Max andalso CanAct ->
96+
io:format("[+][~p][~p] - Scale UP ~p (consecutive_hot=~p)~n", [calendar:local_time(), self(), StageModule, H]),
97+
stage_behaviour:add_worker(StageModule),
98+
S#controller_state{ consecutive_hot = 0, last_action_ms = now_ms() };
99+
_ when C >= K andalso NumWorkers > Min andalso CanAct ->
100+
io:format("[-][~p][~p] - Scale DOWN ~p (consecutive_cold=~p)~n", [calendar:local_time(), self(), StageModule, C]),
101+
stage_behaviour:remove_worker(StageModule, any),
102+
S#controller_state{ consecutive_cold = 0, last_action_ms = now_ms() };
103+
_ ->
104+
S
105+
end.
66106

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-module(worker).
1+
-module(stage_worker).
22

33
-export([spawn_worker/1, loop/1]).
44

@@ -9,12 +9,16 @@ loop(StageModule) ->
99
receive
1010
{work, Command, From} ->
1111
case StageModule:handle_command(Command) of
12-
{ok, _} ->
12+
{ok, Result} ->
13+
From ! {stage_result, Result},
1314
ok;
1415
{error, Reason} ->
15-
io:format("[-][~p][~p] - Erro motivo ~p ~n", [calendar:local_time(), self(), Reason]);
16+
io:format("[-][~p][~p] - Erro motivo ~p ~n", [calendar:local_time(), self(), Reason]),
17+
From ! {stage_error, Reason};
1618
{forward, NextStagePid, NewCommand} ->
1719
NextStagePid ! {command, NewCommand, From}
1820
end,
1921
loop(StageModule)
2022
end.
23+
24+

src/poc.app.src

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,18 @@
22
[
33
{description, "POC Application"},
44
{vsn, "0.1.0"},
5-
{modules, [poc_app]},
5+
{modules, [
6+
poc_app,
7+
stage_behaviour,
8+
stage_controller,
9+
stage_worker,
10+
http_server,
11+
http_server_parser_stage,
12+
http_server_cache_stage,
13+
http_server_get_stage,
14+
http_server_response_writer_stage
15+
]},
616
{registered, []},
717
{mod, {poc_app, []}},
8-
{applications, [kernel, stdlib]}
18+
{applications, [kernel, stdlib, ranch]}
919
]}.

src/poc_app.erl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
-export([start/2, stop/1]).
66

77
start(_Type, _Args) ->
8-
get_stage:start_link(),
9-
http_parser_stage:start_link(),
8+
http_server_cache_stage:start_link(),
9+
http_server_response_writer_stage:start_link(),
10+
http_server_get_stage:start_link(),
11+
http_server_parser_stage:start_link(),
1012
http_server:start(),
1113
{ok, self()}.
1214

src/web-server/get_stage.erl

Lines changed: 0 additions & 71 deletions
This file was deleted.

0 commit comments

Comments
 (0)