рдзреВрдордХреЗрддреБ - 1,000,000 рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рднрд╛рд░ рдХреЗ рд╕рд╛рде рдореЛрдЪреАрд╡реЗрдм рдХреЗ рд▓рд┐рдП рдЖрд╡реЗрджрдиред рднрд╛рдЧ 3/3

рд▓реЗрдЦреЛрдВ рдХреА рдЗрд╕ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдореЗрдВ рднрд╛рдЧ 1 рдФрд░ рднрд╛рдЧ 2 рдореЗрдВ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдореЛрдЪреАрд╡реЗрдм рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рдП, рдФрд░ рдХрдиреЗрдХреНрдЯреЗрдб рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рд╕рдВрджреЗрд╢ рдХреИрд╕реЗ рднреЗрдЬреЗрдВред рд╣рдордиреЗ рдкреНрд░рддреНрдпреЗрдХ рдХрдиреЗрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдореЗрдореЛрд░реА рдХреА рдЦрдкрдд рдХреЛ 8 KB рддрдХ рдШрдЯрд╛ рджрд┐рдпрд╛ред рд╣рдордиреЗ c10k рдкрд░реАрдХреНрд╖рдг рджреЛрд╣рд░рд╛рдпрд╛ред рд╣рдордиреЗ рд╢реЗрдбреНрдпреВрд▓ рдмрдирд╛рдпрд╛ред рдпрд╣ рдордЬреЗрджрд╛рд░ рдерд╛, рд▓реЗрдХрд┐рди рдЕрдм 1 рдорд┐рд▓рд┐рдпрди рдХрдиреЗрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рд╕рдм рдХреБрдЫ рджреЛрд╣рд░рд╛рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред



рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╢рд╛рдорд┐рд▓ рд╣реИрдВ:

тАв рдорд╛рдиреЗрд╕рд┐рдпрд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ;

тАв рдПрдХ рдорд┐рд▓рд┐рдпрди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдлрд╝реЙрд░реНрдо "рдорд┐рддреНрд░реЛрдВ" рдХреЗ рдПрдХ рдкреНрд░рд╢рдВрд╕рдиреАрдп рдбреЗрдЯрд╛ рд╕реЗрдЯ рдХреА рдкреАрдврд╝реА;

тАв Mnesia рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ рдФрд░ рд╣рдорд╛рд░реЗ рдбреЗрдЯрд╛ рдХреЛ рджрд░реНрдЬ рдХрд░реЗрдВ;

тАв рдПрдХ рдорд╢реАрди рд╕реЗ рдПрдХ рд▓рд╛рдЦ рдХрдиреЗрдХреНрд╢рдиреЛрдВ рдХреА рдЦреЛрдЬ;

тАв 1 рдорд┐рд▓рд┐рдпрди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛рддреНрдордХ рдкрд░реАрдХреНрд╖рдг;

тАв рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрдиреЗрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рд▓рд┐рдмрд╡реЗрдВрдЯ + рд╕реА;

тАв рдЕрдВрддрд┐рдо рдирд┐рд╖реНрдХрд░реНрд╖ред



рдЗрд╕ рдкрд░реАрдХреНрд╖рдг рдХрд╛ рдПрдХ рд╣рд┐рд╕реНрд╕рд╛ рдПрдХрд▓ рдкрд░реАрдХреНрд╖рдг рдорд╢реАрди рд╕реЗ 1,000,000 рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рд╣реИред рдПрдХ рд╕рд░реНрд╡рд░ рд▓рд┐рдЦрдирд╛ рдЬреЛ 1,000,000 рдХрдиреЗрдХреНрд╢рди рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИ, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ 1,000,000 рдХрдиреЗрдХреНрд╢рди рдмрдирд╛рдирд╛ рдЖрд╕рд╛рди рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЗрд╕ рд▓реЗрдЦ рдХреА рдПрдХ рдЙрдЪрд┐рдд рд░рд╛рд╢рд┐ рдПрдХрд▓ рдорд╢реАрди рд╕реЗ 1,000,000 рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рддрд░реАрдХреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИред



рд╣рдорд╛рд░реЗ Pubsub рдХрд╛ рд╢реБрднрд╛рд░рдВрднред



рднрд╛рдЧ 2 рдореЗрдВ, рд╣рдордиреЗ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рд╕рдВрджреЗрд╢ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд░рд╛рдЙрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдпрд╣ рдЪреИрдЯ / рдЖрдИрдПрдо рдкреНрд░рдгрд╛рд▓реА рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдФрд░ рднреА рдЙрдкрдпреЛрдЧреА рдЪреАрдЬреЗрдВ рд╣реИрдВ рдЬреЛ рд╣рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдмрдбрд╝реЗ рдкреИрдорд╛рдиреЗ рдкрд░ рдкрд░реАрдХреНрд╖рдг рд╢реБрд░реВ рдХрд░реЗрдВ, рдЪрд▓реЛ рдПрдХ рдФрд░ рдореЙрдбреНрдпреВрд▓ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ - рдЧреНрд░рд╛рд╣рдХ рдбреЗрдЯрд╛рдмреЗрд╕ред рд╣рдо рдЖрдкрдХреЗ рджреЛрд╕реНрддреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдмрдирд╛рдПрдВрдЧреЗ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдЖрдкрдХреЛ рдЖрдкрдХреЗ рджреЛрд╕реНрддреЛрдВ рдХреА рд╕реВрдЪреА рдХреЗ рд▓реЛрдЧреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЙрддреНрдкрдиреНрди рд╕рднреА рдШрдЯрдирд╛рдУрдВ рдХреЗ рд╕рд╛рде рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддрд╛ рд╣реИред



рдореЗрд░рд╛ рдЗрд░рд╛рджрд╛ Last.fm рдХреЗ рд▓рд┐рдП рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИред рдЗрд╕ рддрд░рд╣, рдореИрдВ рдЙрди рдЧреАрддреЛрдВ рдХрд╛ рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдЪреИрдирд▓ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ рдЬреЛ рдореЗрд░реЗ рдорд┐рддреНрд░ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рд╕реБрди рд░рд╣реЗ рд╣реИрдВред рдпрд╣ рд╕рд╛рдорд╛рдЬрд┐рдХ рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рдЙрддреНрдкрдиреНрди рдЕрдиреНрдп рдШрдЯрдирд╛рдУрдВ рдкрд░ рд╕рдорд╛рди рд░реВрдк рд╕реЗ рд▓рд╛рдЧреВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдлрд╝реНрд▓рд┐рдХрд░, рдлреЗрд╕рдмреБрдХ, рдЯреНрд╡рд┐рдЯрд░, рдЖрджрд┐ рдХреЗ рддрддреНрд╡реЛрдВ рдХреЛ рдЕрдкрд▓реЛрдб рдХреА рдЧрдИ рддрд╕реНрд╡реАрд░реЗрдВ рд╕рдорд╛рдЪрд╛рд░ рдлрд╝реАрдб FriendFeed рдореЗрдВ рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдмреАрдЯрд╛ API рднреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╣реИред



рдПрдХ рд╕рджрд╕реНрдпрддрд╛ рдкреНрд░рдмрдВрдзрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛



рд╣рдо рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╕рджрд╕реНрдпрддрд╛ рдкреНрд░рдмрдВрдзрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╣рдо рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЕрдкрдиреЗ рд╕рднреА рджреЛрд╕реНрддреЛрдВ рдХреЛ рд▓реЛрдЧреЛрдВ рдХреА рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрдВрдЧреЗред



рдПрдкреАрдЖрдИ:

тАв add_subsults ([{рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдмрд░, рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдмрд░}, ...])

тАв remove_subsults ([{рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдмрд░, рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдмрд░}, ...])

тАв get_subscribers (рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛)



-module(subsmanager). -behaviour(gen_server). -include("/usr/local/lib/erlang/lib/stdlib-1.15.4/include/qlc.hrl"). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([add_subscriptions/1, remove_subscriptions/1, get_subscribers/1, first_run/0, stop/0, start_link/0]). -record(subscription, {subscriber, subscribee}). -record(state, {}). % state is all in mnesia -define(SERVER, global:whereis_name(?MODULE)). start_link() -> gen_server:start_link({global, ?MODULE}, ?MODULE, [], []). stop() -> gen_server:call(?SERVER, {stop}). add_subscriptions(SubsList) -> gen_server:call(?SERVER, {add_subscriptions, SubsList}, infinity). remove_subscriptions(SubsList) -> gen_server:call(?SERVER, {remove_subscriptions, SubsList}, infinity). get_subscribers(User) -> gen_server:call(?SERVER, {get_subscribers, User}). %% init([]) -> ok = mnesia:start(), io:format("Waiting on mnesia tables..\n",[]), mnesia:wait_for_tables([subscription], 30000), Info = mnesia:table_info(subscription, all), io:format("OK. Subscription table info: \n~w\n\n",[Info]), {ok, #state{}}. handle_call({stop}, _From, State) -> {stop, stop, State}; handle_call({add_subscriptions, SubsList}, _From, State) -> % Transactionally is slower: % F = fun() -> % [ ok = mnesia:write(S) || S <- SubsList ] % end, % mnesia:transaction(F), [ mnesia:dirty_write(S) || S <- SubsList ], {reply, ok, State}; handle_call({remove_subscriptions, SubsList}, _From, State) -> F = fun() -> [ ok = mnesia:delete_object(S) || S <- SubsList ] end, mnesia:transaction(F), {reply, ok, State}; handle_call({get_subscribers, User}, From, State) -> F = fun() -> Subs = mnesia:dirty_match_object(#subscription{subscriber='_', subscribee=User}), Users = [Dude || #subscription{subscriber=Dude, subscribee=_} <- Subs], gen_server:reply(From, Users) end, spawn(F), {noreply, State}. handle_cast(_Msg, State) -> {noreply, State}. handle_info(_Msg, State) -> {noreply, State}. terminate(_Reason, _State) -> mnesia:stop(), ok. code_change(_OldVersion, State, _Extra) -> io:format("Reloading code for ?MODULE\n",[]), {ok, State}. %% first_run() -> mnesia:create_schema([node()]), ok = mnesia:start(), Ret = mnesia:create_table(subscription, [ {disc_copies, [node()]}, {attributes, record_info(fields, subscription)}, {index, [subscribee]}, %index subscribee too {type, bag} ]), Ret.
      
      







рдЙрд▓реНрд▓реЗрдЦрдиреАрдп:

тАв рдореИрдВрдиреЗ рдкреВрд░реНрдг рдкрде рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП Mnesia рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ qlc.hrl рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ред рдпрд╣ рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдЕрд▓рдЧ рддрд░реАрдХреЗ рд╕реЗ рдореИрдВ рд╕рдлрд▓ рдирд╣реАрдВ рд╣реБрдЖред

тАв get_subscribers рдПрдХ рдЕрдиреНрдп рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдЬрдиреНрдо рджреЗрддрд╛ рд╣реИ рдФрд░ gen_server рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрд╕реА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рдкреНрд░рддрд┐ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЛ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ: рдЙрддреНрддрд░ред рдЗрд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдЕрдЧрд░ рд╣рдо рдЕрдХреНрд╕рд░ рд▓реБрдХрдЕрдк рдХрд╣рддреЗ рд╣реИрдВ рддреЛ gen_server рд▓реВрдк рдЗрд╕ рдХреЙрд▓ рдкрд░ рдмреНрд▓реЙрдХ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред

тАв рдЖрд░рдЖрд░ ("рд╕рдмрдордирдЧрд░.рдПрд▓рдЖрд░")ред рдиреАрдЪреЗ рджрд┐рдпрд╛ рдЧрдпрд╛ рдЙрджрд╛рд╣рд░рдг рдЖрдкрдХреЛ erl рд╢реЗрд▓ рдореЗрдВ рд░рд┐рдХреЙрд░реНрдб рдкрд░рд┐рднрд╛рд╖рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред Record.hrl рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЕрдкрдиреА рдкрд░рд┐рднрд╛рд╖рд╛рдПрдБ рд░рдЦрдирд╛ рдФрд░ рдЗрд╕реЗ рдЕрдкрдиреЗ рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд░рдирд╛ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫреА рд╢реИрд▓реА рд╣реИред рдореИрдВрдиреЗ рд╢реЙрд░реНрдЯ рдХреЗ рд▓рд┐рдП рдРрд╕рд╛ рдХрд┐рдпрд╛ред



рдЕрдм рдЬрд╛рдВрдЪ рдХрд░реЗрдВред first_run () Mnesia рд╕реНрдХреАрдорд╛ рдмрдирд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдкрд╣рд▓реЗ рдХреЙрд▓ рдХрд░рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред рдордиреЗрд╕рд┐рдпрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рдФрд░ рд╕рдВрднрд╛рд╡рд┐рдд рдЧрдбрд╝рдмрдбрд╝ рдпрд╣ рд╣реИ рдХрд┐ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ) рдХреЗрд╡рд▓ рдиреЛрдб рдЬреЛ рдЗрд╕реЗ рдмрдирд╛рддрд╛ рд╣реИ рд╡рд╣ рдбреЗрдЯрд╛рдмреЗрд╕ рддрдХ рдкрд╣реБрдВрдЪ рд╕рдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЦреЛрд▓ рдХреЛ рдПрдХ рдирд╛рдо рджреЗрдВред

 $ mkdir /var/mnesia $ erl -boot start_sasl -mnesia dir '"/var/mnesia_data"' -sname subsman (subsman@localhost)1> c(subsmanager). {ok,subsmanager} (subsman@localhost)2> subsmanager:first_run(). ... {atomic,ok} (subsman@localhost)3> subsmanager:start_link(). Waiting on mnesia tables.. OK. Subscription table info: [{access_mode,read_write},{active_replicas,[subsman@localhost]},{arity,3},{attributes,[subscriber,subscribee]},{checkpoints,[]},{commit_work,[{index,bag,[{3,{ram,57378}}]}]},{cookie,{{1224,800064,900003},subsman@localhost}},{cstruct,{cstruct,subscription,bag,[],[subsman@localhost],[],0,read_write,[3],[],false,subscription,[subscriber,subscribee],[],[],{{1224,863164,904753},subsman@localhost},{{2,0},[]}}},{disc_copies,[subsman@localhost]},{disc_only_copies,[]},{frag_properties,[]},{index,[3]},{load_by_force,false},{load_node,subsman@localhost},{load_order,0},{load_reason,{dumper,create_table}},{local_content,false},{master_nodes,[]},{memory,288},{ram_copies,[]},{record_name,subscription},{record_validation,{subscription,3,bag}},{type,bag},{size,0},{snmp,[]},{storage_type,disc_copies},{subscribers,[]},{user_properties,[]},{version,{{2,0},[]}},{where_to_commit,[{subsman@localhost,disc_copies}]},{where_to_read,subsman@localhost},{where_to_write,[subsman@localhost]},{wild_pattern,{subscription,'_','_'}},{{index,3},57378}] {ok,<0.105.0>} (subsman@localhost)4> rr("subsmanager.erl"). [state,subscription] (subsman@localhost)5> subsmanager:add_subscriptions([ #subscription{subscriber=alice, subscribee=rj} ]). ok (subsman@localhost)6> subsmanager:add_subscriptions([ #subscription{subscriber=bob, subscribee=rj} ]). ok (subsman@localhost)7> subsmanager:get_subscribers(rj). [bob,alice] (subsman@localhost)8> subsmanager:remove_subscriptions([ #subscription{subscriber=bob, subscribee=rj} ]). ok (subsman@localhost)8> subsmanager:get_subscribers(rj). [alice] (subsman@localhost)10> subsmanager:get_subscribers(charlie). []
      
      





рд╣рдо рдкреВрд░реНрдгрд╛рдВрдХ Ids рдХрд╛ рдЙрдкрдпреЛрдЧ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░реЗрдВрдЧреЗ - рд▓реЗрдХрд┐рди рдЗрд╕ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдореИрдВрдиреЗ рдкрд░рдорд╛рдгреБрдУрдВ (rj, alice, bob) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдФрд░ рдпрд╣ рдорд╛рди рд▓рд┐рдпрд╛ рдХрд┐ alice рдФрд░ bob rj рдХреЗ рдорд┐рддреНрд░ рд╣реИрдВред рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИ рдХрд┐ рдорд╛рдиреЗрд╕рд┐рдпрд╛ (рдФрд░ ets / dets) рдкрд░рд╡рд╛рд╣ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЖрдкрдиреЗ рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ - рдХреЛрдИ рднреА рдЗрд░рд▓рдВрдЧ рд╢рдмреНрдж рдорд╛рдиреНрдп рд╣реИред рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрджреНрдпрддрди рдХрд░рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред



рд░рд╛рдЙрдЯрд░ рдмрджрд▓реЗрдВ



рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рд╕рдВрджреЗрд╢ рднреЗрдЬрдиреЗ рдХреЗ рдмрдЬрд╛рдп, рд╡рд╣ рд╣реИ: рд░рд╛рдЙрдЯрд░: рднреЗрдЬреЗрдВ (123, "рд╣реИрд▓реЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 123"), рд╣рдо рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ "рдЪрд┐рд╣реНрдирд┐рдд" рдХрд░рддреЗ рд╣реИрдВ - рд╕рдВрджреЗрд╢ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рд╡реНрдпрдХреНрддрд┐ - рдФрд░ рдПрдХ рд░рд╛рдЙрдЯрд░ рд╣реИ рдЬреЛ рдкреНрд░рддреНрдпреЗрдХ рд╣рд╕реНрддрд╛рдХреНрд╖рд░рд┐рдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рд╕рдВрджреЗрд╢ рднреЗрдЬрддрд╛ рд╣реИред рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдПрдкреАрдЖрдИ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░реЗрдЧрд╛: рд░рд╛рдЙрдЯрд░: рд╕реЗрдВрдб (123, "рд╣реЗрд▓реЛ рд╣рд░ рдпреВрдЬрд░ рд╕рдмреНрд╕реНрдХреНрд░рд╛рдЗрдм рдЯреВ 123")ред

 -module(router). -behaviour(gen_server). -export([start_link/0]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([send/2, login/2, logout/1]). -define(SERVER, global:whereis_name(?MODULE)). % will hold bidirectional mapping between id <тАУ> pid -record(state, {pid2id, id2pid}). start_link() -> gen_server:start_link({global, ?MODULE}, ?MODULE, [], []). % sends Msg to anyone subscribed to Id send(Id, Msg) -> gen_server:call(?SERVER, {send, Id, Msg}). login(Id, Pid) when is_pid(Pid) -> gen_server:call(?SERVER, {login, Id, Pid}). logout(Pid) when is_pid(Pid) -> gen_server:call(?SERVER, {logout, Pid}). %% init([]) -> % set this so we can catch death of logged in pids: process_flag(trap_exit, true), % use ets for routing tables {ok, #state{ pid2id = ets:new(?MODULE, [bag]), id2pid = ets:new(?MODULE, [bag]) } }. handle_call({login, Id, Pid}, _From, State) when is_pid(Pid) -> ets:insert(State#state.pid2id, {Pid, Id}), ets:insert(State#state.id2pid, {Id, Pid}), link(Pid), % tell us if they exit, so we can log them out %io:format("~w logged in as ~w\n",[Pid, Id]), {reply, ok, State}; handle_call({logout, Pid}, _From, State) when is_pid(Pid) -> unlink(Pid), PidRows = ets:lookup(State#state.pid2id, Pid), case PidRows of [] -> ok; _ -> IdRows = [ {I,P} || {P,I} <- PidRows ], % invert tuples ets:delete(State#state.pid2id, Pid), % delete all pid->id entries [ ets:delete_object(State#state.id2pid, Obj) || Obj <- IdRows ] % and all id->pid end, %io:format("pid ~w logged out\n",[Pid]), {reply, ok, State}; handle_call({send, Id, Msg}, From, State) -> F = fun() -> % get users who are subscribed to Id: Users = subsmanager:get_subscribers(Id), io:format("Subscribers of ~w = ~w\n",[Id, Users]), % get pids of anyone logged in from Users list: Pids0 = lists:map( fun(U)-> [ P || { _I, P } <- ets:lookup(State#state.id2pid, U) ] end, [ Id | Users ] % we are always subscribed to ourselves ), Pids = lists:flatten(Pids0), io:format("Pids: ~w\n", [Pids]), % send Msg to them all M = {router_msg, Msg}, [ Pid ! M || Pid <- Pids ], % respond with how many users saw the message gen_server:reply(From, {ok, length(Pids)}) end, spawn(F), {noreply, State}. % handle death and cleanup of logged in processes handle_info(Info, State) -> case Info of {'EXIT', Pid, _Why} -> handle_call({logout, Pid}, blah, State); Wtf -> io:format("Caught unhandled message: ~w\n", [Wtf]) end, {noreply, State}. handle_cast(_Msg, State) -> {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}.
      
      







рдереЛрдбрд╝рд╛ рдкрд░реАрдХреНрд╖рдг - рдореИрдВрдиреЗ рдЖрдИрдбреА рдХреЗ рдмрдЬрд╛рдп рдкрд░рдорд╛рдгреБрдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред

 (subsman@localhost)1> c(subsmanager), c(router), rr("subsmanager.erl"). (subsman@localhost)2> subsmanager:start_link(). (subsman@localhost)3> router:start_link(). (subsman@localhost)4> Subs = [#subscription{subscriber=alice, subscribee=rj}, #subscription{subscriber=bob, subscribee=rj}]. [#subscription{subscriber = alice,subscribee = rj}, #subscription{subscriber = bob,subscribee = rj}] (subsman@localhost)5> subsmanager:add_subscriptions(Subs). ok (subsman@localhost)6> router:send(rj, "RJ did something"). Subscribers of rj = [bob,alice] Pids: [] {ok,0} (subsman@localhost)7> router:login(alice, self()). ok (subsman@localhost)8> router:send(rj, "RJ did something"). Subscribers of rj = [bob,alice] Pids: [<0.46.0>] {ok,1} (subsman@localhost)9> receive {router_msg, M} -> io:format("~s\n",[M]) end. RJ did something ok
      
      





рдпрд╣ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдПрд▓рд┐рд╕ рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдЬрдм рдХреЛрдИ рд╡реНрдпрдХреНрддрд┐ рдЬрд┐рд╕реЗ рд╡рд╣ рд╕рджрд╕реНрдпрддрд╛ рджреЗ рд░рд╣рд╛ рд╣реИ рд╡рд╣ рдПрдХ рд╕рдВрджреЗрд╢ рднреЗрдЬрддрд╛ рд╣реИ, рднрд▓реЗ рд╣реА рд╕рдВрджреЗрд╢ рд╕реАрдзреЗ рдПрд▓рд┐рд╕ рдХреЛ рдирд╣реАрдВ рднреЗрдЬрд╛ рдЧрдпрд╛ рд╣реЛред рдирд┐рд╖реНрдХрд░реНрд╖ рд╕реЗ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рд░рд╛рдЙрдЯрд░ рдиреЗ рд╕рдВрднрд╛рд╡рд┐рдд рд▓рдХреНрд╖реНрдпреЛрдВ рдХреА рдкрд╣рдЪрд╛рди [alice, bob] рдХреЗ рд░реВрдк рдореЗрдВ рдХреА, рд▓реЗрдХрд┐рди рдПрдХ рд╡реНрдпрдХреНрддрд┐ рдХреЛ, alice, рдХреНрдпреЛрдВрдХрд┐ bob рдХреЛ рдЕрдзрд┐рдХреГрдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдХреЛ рд╕рдВрджреЗрд╢ рднреЗрдЬ рджрд┐рдпрд╛ред



рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдбреЗрдЯрд╛рд╕реЗрдЯ рдмрдирд╛рдирд╛



рд╣рдо рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдкрд░ рдмрд╣реБрдд рд╕рд╛рд░реЗ рд╕рдВрдмрдВрдз рдЙрддреНрдкрдиреНрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдпрдерд╛рд░реНрдерд╡рд╛рджреА рдирд╣реАрдВ рд╣реИред рд╕рд╛рдорд╛рдЬрд┐рдХ рдиреЗрдЯрд╡рд░реНрдХ рдореЗрдВ рдЖрдорддреМрд░ рдкрд░ рдХреБрдЫ рд╕реБрдкрд░ рд▓реЛрдХрдкреНрд░рд┐рдп рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╣реЛрддреЗ рд╣реИрдВ (рдХреБрдЫ рдЯреНрд╡рд┐рдЯрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ 100,000 рд╕реЗ рдЕрдзрд┐рдХ рдЕрдиреБрдпрд╛рдпреА рд╣реИрдВ), рдФрд░ рдмрд╣реБрдд рд╕реЗ рд▓реЛрдЧ рдХреЗрд╡рд▓ рдХреБрдЫ рдореБрдЯреНрдареА рднрд░ рджреЛрд╕реНрдд рд╣реИрдВред

рдбреЗрдЯрд╛рд╕реЗрдЯ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЙрддреНрдХреГрд╖реНрдЯ igraph рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реЗ рдкрд╛рдпрдерди рдореЙрдбреНрдпреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛:

 import igraph g = igraph.Graph.Barabasi(1000000, 15, directed=False) print "Edges: " + str(g.ecount()) + " Verticies: " + str(g.vcount()) g.write_edgelist("fakefriends.txt")
      
      







Mnesia рдореЗрдВ рдбреЗрдЯрд╛ рдЕрдкрд▓реЛрдб рдХрд░рдирд╛



рдпрд╣ рдЫреЛрдЯрд╛ рдореЙрдбреНрдпреВрд▓ рдирдХрд▓реА рдЧрд░реНрд▓рдлреНрд░реЗрдВрдб.рдЯреИрдХреНрд╕ рдлрд╛рдЗрд▓ рдХреЛ рдкрдврд╝рддрд╛ рд╣реИ рдФрд░ рд╕рджрд╕реНрдпрддрд╛ рдХреА рд╕реВрдЪреА рдмрдирд╛рддрд╛ рд╣реИред

 -module(readfriends). -export([load/1]). -record(subscription, {subscriber, subscribee}). load(Filename) -> for_each_line_in_file(Filename, fun(Line, Acc) -> [As, Bs] = string:tokens(string:strip(Line, right, $\n), " "), {A, _} = string:to_integer(As), {B, _} = string:to_integer(Bs), [ #subscription{subscriber=A, subscribee=B} | Acc ] end, [read], []). % via: http://www.trapexit.org/Reading_Lines_from_a_File for_each_line_in_file(Name, Proc, Mode, Accum0) -> {ok, Device} = file:open(Name, Mode), for_each_line(Device, Proc, Accum0). for_each_line(Device, Proc, Accum) -> case io:get_line(Device, "") of eof -> file:close(Device), Accum; Line -> NewAccum = Proc(Line, Accum), for_each_line(Device, Proc, NewAccum) end.
      
      





рдЕрдм рд╕рдмрд╕рдореИрди рд╢реЗрд▓ рдореЗрдВ рдЖрдк рдПрдХ рдЯреЗрдХреНрд╕реНрдЯ рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╕рджрд╕реНрдпрддрд╛рдПрдБ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ:

 $ erl -name router@minifeeds4.gs2 +K true +A 128 -setcookie secretcookie -mnesia dump_log_write_threshold 50000 -mnesia dc_dump_limit 40 erl> c(readfriends), c(subsmanager). erl> subsmanager:first_run(). erl> subsmanager:start_link(). erl> subsmanager:add_subscriptions( readfriends:load("fakefriends.txt") ).
      
      





рдЕрддрд┐рд░рд┐рдХреНрдд рдорд╛рдкрджрдВрдбреЛрдВ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВ - рд╡реЗ "** рдЪреЗрддрд╛рд╡рдиреА ** рдорд╛рдиреЗрд╕рд┐рдпрд╛ рдЕрддрд┐рднрд╛рд░рд┐рдд рд╣реИрдВ" рд╕рдВрджреЗрд╢реЛрдВ рд╕реЗ рдмрдЪрдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдВрдЧреЗред рдореЗрдиреНрд╕рд┐рдпрд╛ рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рдХрдИ рдЕрдиреНрдп рдЙрд▓реНрд▓реЗрдЦрдиреАрдп рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред



1000000



рдПрдХ рдореЗрдЬрдмрд╛рди рд╕реЗ рдПрдХ рдорд┐рд▓рд┐рдпрди рдЯреАрд╕реАрдкреА рдХрдиреЗрдХреНрд╢рди рдмрдирд╛рдирд╛ рддреБрдЪреНрдЫ рдирд╣реАрдВ рд╣реИред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЬреЛ рд▓реЛрдЧ рдирд┐рдпрдорд┐рдд рд░реВрдк рд╕реЗ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдпреМрдЧрд┐рдХреЛрдВ рдХреЗ рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдкрд┐рдд рдЫреЛрдЯреЗ рд╕рдореВрд╣реЛрдВ рдкрд░ рдРрд╕рд╛ рдХрд░рддреЗ рд╣реИрдВ, рд╡реЗ рд╢рд╛рдпрдж рддреНрд╕реБрдВрдЧ рдЬреИрд╕реЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЙрдкрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рднрд╛рдЧ 1 рд╕реЗ рд╡рд┐рдиреНрдпрд╛рд╕ рдХреЗ рд╕рд╛рде, рд╣рдо рдЕрднреА рднреА рдПрдХ рдХрдард┐рди рдмрдВрджрд░рдЧрд╛рд╣ рд╕реАрдорд╛ рдореЗрдВ рдЪрд▓рддреЗ рд╣реИрдВред Tcp рдХрдиреЗрдХреНрд╢рди рдмрдирд╛рддреЗ рд╕рдордп, рдХреНрд▓рд╛рдЗрдВрдЯ рдкреЛрд░реНрдЯ рдХреЛ / proc / sys / net / ipv4 / ip_local_port_range рдореЗрдВ рд░реЗрдВрдЬ рд╕реЗ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрджрд┐ рдЖрдк рдЗрд╕реЗ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ рдпрд╛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдкреЛрд░реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдХреЛрдИ рдмрд╛рдд рдирд╣реАрдВ рд╣реИред рднрд╛рдЧ 1 рдореЗрдВ, рд╣рдордиреЗ "1024 65535" рдкрд░ рд╕реАрдорд╛ рддрдп рдХреА, рдЕрд░реНрдерд╛рдд рд╣рдорд╛рд░реЗ рдкрд╛рд╕ 65535-1024 = 64511 рдЕрдирдкреЗрдХреНрд╖рд┐рдд рдЙрдкрд▓рдмреНрдз рдкреЛрд░реНрдЯ рд╣реИрдВред рдЙрдирдореЗрдВ рд╕реЗ рдХреБрдЫ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЕрдиреНрдп рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рджреНрд╡рд╛рд░рд╛ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рд▓реЗрдХрд┐рди рд╣рдо рдХрднреА рднреА 64511 рд╕реЗ рдЕрдзрд┐рдХ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЛ рдкрд╛рд╕ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдмрдВрджрд░рдЧрд╛рд╣реЛрдВ рд╕реЗ рдмрд╛рд╣рд░ рднрд╛рдЧ рдЬрд╛рдПрдВрдЧреЗред

рд╕реНрдерд╛рдиреАрдп рдкреЛрд░реНрдЯ рд░реЗрдВрдЬ рдЖрдИрдкреА рд╕реЗ рдЬреБрдбрд╝рд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рд╣рдо рд╡рд┐рднрд┐рдиреНрди рд╕реНрдерд╛рдиреАрдп рдЖрдИрдкреА рдкрддреЗ рд╕реЗ рдЖрдЙрдЯрдЧреЛрдЗрдВрдЧ рдХрдиреЗрдХреНрд╢рди рдмрдирд╛рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо 64511 рд╕реЗ рдЕрдзрд┐рдХ рдЖрдЙрдЯрдЧреЛрдЗрдВрдЧ рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓ рдкрд╛рдПрдВрдЧреЗред



рддреЛ рдЖрдЗрдП рдкреНрд░рддреНрдпреЗрдХ рд╕реЗ 62,000 рдХрдиреЗрдХреНрд╢рди рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП 17 рдирдП рдЖрдИрдкреА рдкрддреЗ рдмрдирд╛рдПрдВ - рдпрд╣ рд╣рдореЗрдВ рдХреБрд▓ 1,054,000 рдХрдиреЗрдХреНрд╢рди рджреЗрдЧрд╛:

 $ for i in `seq 1 17`; do echo sudo ifconfig eth0:$i 10.0.0.$i up ; done
      
      





рдпрджрд┐ рдЖрдк ifconfig рдХреЛ рдЕрднреА рдЪреЗрдХ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдЕрдкрдирд╛ рд╡рд░реНрдЪреБрдЕрд▓ рдЗрдВрдЯрд░рдлреЗрд╕ рджреЗрдЦрдирд╛ рдЪрд╛рд╣рд┐рдП: eth0: 1, eth0: 2 ... eth0: 17, рдкреНрд░рддреНрдпреЗрдХ рдПрдХ рдЕрд▓рдЧ IP рдкрддреЗ рдХреЗ рд╕рд╛рдеред



рд╕реНрдерд╛рдиреАрдп рдЖрдИрдкреА рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдм рдЬреЛ рдХреБрдЫ рдмрдЪрддрд╛ рд╣реИ рд╡рд╣ рднрд╛рдЧ 1 рд╕реЗ рдмрд╛рдврд╝ рдХреЛ рдмрджрд▓рдирд╛ рд╣реИред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, erlang http рдХреНрд▓рд╛рдЗрдВрдЯ рдЖрдкрдХреЛ рд╕реНрд░реЛрдд IP рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред



рдЗрд╕ рдмрд┐рдВрджреБ рдкрд░, рдореИрдВ рдПрдХ рдФрд░ рд╕рдВрднрд╛рд╡рдирд╛ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░ рд░рд╣рд╛ рдерд╛: 17 рдЖрдИрдкреА рдЬреЛрдбрд╝реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП - рдПрдХ рд╕рд░реНрд╡рд░ рдкрд░ рдФрд░ рдПрдХ рдХреНрд▓рд╛рдЗрдВрдЯ рдкрд░ - рдкреНрд░рддреНрдпреЗрдХ рдЬреЛрдбрд╝реА рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдкреГрдердХ / 30 рд╕рдмрдиреЗрдЯ рдореЗрдВред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдореИрдВрдиреЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдХрд┐рд╕реА рднреА рдЖрдИрдкреА рд╕рд░реНрд╡рд░ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд┐рдпрд╛, рддреЛ рдпрд╣ рд╕реНрдерд╛рдиреАрдп рдкрддреЗ рдХреЛ рдЬреЛрдбрд╝реА рдХреЗ рджреВрд╕рд░реЗ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд░реЗрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рд╕реНрдерд╛рдиреАрдп рдЖрдИрдкреА рдореЗрдВ рд╕реЗ рдХреЗрд╡рд▓ рдПрдХ рд╣реА рдЗрд╕ рд╕рдмрдиреЗрдЯ рдкрд░ рдЖрдИрдкреА рд╕рд░реНрд╡рд░ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдЧрд╛ред рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реЛрдЧрд╛ рдХрд┐ рдЧреНрд░рд╛рд╣рдХ рдорд╢реАрди рдкрд░ рдПрдХ рд╕реНрдерд╛рдиреАрдп рд╕реНрд░реЛрдд рдЖрдИрдкреА рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реЛрдЧрд╛ (рд╣рд╛рд▓рд╛рдВрдХрд┐ рд╕рд░реНрд╡рд░ рдХреЗ рдЖрдИрдкреА рдкрддреЗ рдХреА рд╕реАрдорд╛ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛)ред рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рдпрд╣ рдХрд╛рдо рдХрд░реЗрдЧрд╛ рдпрд╛ рдирд╣реАрдВ - рдЗрд╕ рд╕рдордп рдЗрд╕рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдереАред рдЕрдВрдд рдореЗрдВ, рдореИрдВрдиреЗ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдХрд┐ рдпрд╣ рдмрд╣реБрдд рд╡рд┐рдХреГрдд рд╣реЛрдЧрд╛ред



gen_tcp рдЖрдкрдХреЛ рд╕реНрд░реЛрдд рдкрддрд╛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдПрдХ рдХрдЪреНрдЪреЗ рдЧреНрд░рд╛рд╣рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдорд╛рдкреНрдд рдХрд┐рдпрд╛:

 -module(floodtest2). -compile(export_all). -define(SERVERADDR, "10.1.2.3"). % where mochiweb is running -define(SERVERPORT, 8000). % Generate the config in bash like so (chose some available address space): % EACH=62000; for i in `seq 1 17`; do echo "{{10,0,0,$i}, $((($i-1)*$EACH+1)), $(($i*$EACH))}, "; done run(Interval) -> Config = [ {{10,0,0,1}, 1, 62000}, {{10,0,0,2}, 62001, 124000}, {{10,0,0,3}, 124001, 186000}, {{10,0,0,4}, 186001, 248000}, {{10,0,0,5}, 248001, 310000}, {{10,0,0,6}, 310001, 372000}, {{10,0,0,7}, 372001, 434000}, {{10,0,0,8}, 434001, 496000}, {{10,0,0,9}, 496001, 558000}, {{10,0,0,10}, 558001, 620000}, {{10,0,0,11}, 620001, 682000}, {{10,0,0,12}, 682001, 744000}, {{10,0,0,13}, 744001, 806000}, {{10,0,0,14}, 806001, 868000}, {{10,0,0,15}, 868001, 930000}, {{10,0,0,16}, 930001, 992000}, {{10,0,0,17}, 992001, 1054000}], start(Config, Interval). start(Config, Interval) -> Monitor = monitor(), AdjustedInterval = Interval / length(Config), [ spawn(fun start/5, [Lower, Upper, Ip, AdjustedInterval, Monitor]) || {Ip, Lower, Upper} <- Config ], ok. start(LowerID, UpperID, _, _, _) when LowerID == UpperID -> done; start(LowerID, UpperID, LocalIP, Interval, Monitor) -> spawn(fun connect/5, [?SERVERADDR, ?SERVERPORT, LocalIP, "/test/"++LowerID, Monitor]), receive after Interval -> start(LowerID + 1, UpperID, LocalIP, Interval, Monitor) end. connect(ServerAddr, ServerPort, ClientIP, Path, Monitor) -> Opts = [binary, {packet, 0}, {ip, ClientIP}, {reuseaddr, true}, {active, false}], {ok, Sock} = gen_tcp:connect(ServerAddr, ServerPort, Opts), Monitor ! open, ReqL = io_lib:format("GET ~s\r\nHost: ~s\r\n\r\n", [Path, ServerAddr]), Req = list_to_binary(ReqL), ok = gen_tcp:send(Sock, [Req]), do_recv(Sock, Monitor), (catch gen_tcp:close(Sock)), ok. do_recv(Sock, Monitor)-> case gen_tcp:recv(Sock, 0) of {ok, B} -> Monitor ! {bytes, size(B)}, io:format("Recvd ~s\n", [ binary_to_list(B)]), io:format("Recvd ~w bytes\n", [size(B)]), do_recv(Sock, Monitor); {error, closed} -> Monitor ! closed, closed; Other -> Monitor ! closed, io:format("Other:~w\n",[Other]) end. % Monitor process receives stats and reports how much data we received etc: monitor() -> Pid = spawn(?MODULE, monitor0, [{0,0,0,0}]), timer:send_interval(10000, Pid, report), Pid. monitor0({Open, Closed, Chunks, Bytes}=S) -> receive report -> io:format("{Open, Closed, Chunks, Bytes} = ~w\n",[S]); open -> monitor0({Open + 1, Closed, Chunks, Bytes}); closed -> monitor0({Open, Closed + 1, Chunks, Bytes}); chunk -> monitor0({Open, Closed, Chunks + 1, Bytes}); {bytes, B} -> monitor0({Open, Closed, Chunks, Bytes + B}) end.
      
      





рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдореИрдВ рднрд╛рдЧ 1 рд╕реЗ рдореЛрдЪреАрд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕реЗ рдЬреБрдбрд╝рд╛ - рдпрд╣ рд╕рд┐рд░реНрдл рдкреНрд░рддреНрдпреЗрдХ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдкреНрд░рддреНрдпреЗрдХ 10 рд╕реЗрдХрдВрдб рдореЗрдВ рдПрдХ рд╕рдВрджреЗрд╢ рднреЗрдЬрддрд╛ рд╣реИред

 erl> c(floodtest2), floodtest2:run(20).
      
      







рдпрд╣ рдЬрд▓реНрджреА рд╕реЗ рдореЗрд░реА рд╕рд╛рд░реА рдореЗрдореЛрд░реА рдЦрд╛ рдЧрдпрд╛



рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ gen_tcp рдХреЗ рд╕рд╛рде рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓рдиреЗ рд╕реЗ рдмрд╣реБрдд рд╕рд╛рд░реА рдореЗрдореЛрд░реА рдЦрддреНрдо рд╣реЛ рдЬрд╛рддреА рд╣реИред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП ~ 36 рдЬреАрдмреА рд▓реЗ рдЬрд╛рдПрдЧрд╛ред рдореБрдЭреЗ рдЕрдкрдиреЗ erlang http рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдСрдкреНрдЯрд┐рдорд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдореЗрдВ рдХреЛрдИ рджрд┐рд▓рдЪрд╕реНрдкреА рдирд╣реАрдВ рдереА, рдФрд░ 32GB рд╕реЗ рдЕрдзрд┐рдХ рдореЗрдореЛрд░реА рд╡рд╛рд▓реА рдПрдХрдорд╛рддреНрд░ рдорд╢реАрди рдЬреЛ рдореБрдЭреЗ рдорд┐рд▓ рд╕рдХрддреА рдереА, рд╡рд╣ рд╣рдорд╛рд░реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╕реЗ рдПрдХ рдереА, рдФрд░ рдореБрдЭреЗ Last.fm рдХреЛ рдмрдВрдж рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рдмрд╣рд╛рдирд╛ рдирд╣реАрдВ рдорд┐рд▓рд╛, рдЬрдмрдХрд┐ рдореИрдВ рдЖрд╕рдкрд╛рд╕ рдЧрдбрд╝рдмрдбрд╝ рдХрд░ рд░рд╣рд╛ рдерд╛ :)



рдЗрд╕ рдмрд┐рдВрджреБ рдкрд░, рдореИрдВрдиреЗ рдХреЛрд╢рд┐рд╢ рдХреА рдФрд░ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдП рдЧрдП рдкрд░рд┐рд╡рд╛рдж рдХреЛ рдпрд╛рдж рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рдЬрд┐рд╕рдореЗрдВ рдПрдХ HTTP рдПрдкреАрдЖрдИ рд╣реИред рдирдП рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдореЗрдВ http рдПрдкреАрдЖрдИ рдореЗрдВ evhttp_connection_set_local_address рдлрд╝рдВрдХреНрд╢рди рднреА рд╣реИред



рдпрд╣рд╛рдБ рд╕реА http рдХреНрд▓рд╛рдЗрдВрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реИ libevent:

 #include <sys/types.h> #include <sys/time.h> #include <sys/queue.h> #include <stdlib.h> #include <err.h> #include <event.h> #include <evhttp.h> #include <unistd.h> #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <time.h> #include <pthread.h> #define BUFSIZE 4096 #define NUMCONNS 62000 #define SERVERADDR "10.103.1.43" #define SERVERPORT 8000 #define SLEEP_MS 10 char buf[BUFSIZE]; int bytes_recvd = 0; int chunks_recvd = 0; int closed = 0; int connected = 0; // called per chunk received void chunkcb(struct evhttp_request * req, void * arg) { int s = evbuffer_remove( req->input_buffer, &buf, BUFSIZE ); //printf("Read %d bytes: %s\n", s, &buf); bytes_recvd += s; chunks_recvd++; if(connected >= NUMCONNS && chunks_recvd%10000==0) printf(">Chunks: %d\tBytes: %d\tClosed: %d\n", chunks_recvd, bytes_recvd, closed); } // gets called when request completes void reqcb(struct evhttp_request * req, void * arg) { closed++; } int main(int argc, char **argv) { event_init(); struct evhttp *evhttp_connection; struct evhttp_request *evhttp_request; char addr[16]; char path[32]; // eg: "/test/123" int i,octet; for(octet=1; octet<=17; octet++){ sprintf(&addr, "10.224.0.%d", octet); for(i=1;i<=NUMCONNS;i++) { evhttp_connection = evhttp_connection_new(SERVERADDR, SERVERPORT); evhttp_connection_set_local_address(evhttp_connection, &addr); evhttp_set_timeout(evhttp_connection, 864000); // 10 day timeout evhttp_request = evhttp_request_new(reqcb, NULL); evhttp_request->chunk_cb = chunkcb; sprintf(&path, "/test/%d", ++connected); if(i%100==0) printf("Req: %s\t->\t%s\n", addr, &path); evhttp_make_request( evhttp_connection, evhttp_request, EVHTTP_REQ_GET, path ); evhttp_connection_set_timeout(evhttp_request->evcon, 864000); event_loop( EVLOOP_NONBLOCK ); if( connected % 200 == 0 ) printf("\nChunks: %d\tBytes: %d\tClosed: %d\n", chunks_recvd, bytes_recvd, closed); usleep(SLEEP_MS*1000); } } event_dispatch(); return 0; }
      
      





рдЕрдзрд┐рдХрд╛рдВрд╢ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ #define рдХреЗ рд░реВрдк рдореЗрдВ рдХреЛрдбрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдк рдЗрд╕реЗ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдкреБрди: рдкреНрд░рд╕реНрддреБрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

 $ gcc -o httpclient httpclient.c -levent $ ./httpclient
      
      







рдпрд╣ рдЕрднреА рднреА 64,500 рд╕реЗ рдЕрдзрд┐рдХ рдмрдВрджрд░рдЧрд╛рд╣реЛрдВ рдХреЛ рдЦреЛрд▓рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрде рд╣реИред



64,500 рд╕реЗ рдЕрдзрд┐рдХ рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд╕реНрдерд╛рдиреАрдп рдкрддрд╛ рдФрд░ рд╕реНрдерд╛рдиреАрдп рдкреЛрд░реНрдЯ рдХреЛ рд╕реНрд╡рдпрдВ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдФрд░ рдЙрдирдХреЗ рдЕрдиреБрд╕рд╛рд░ рдкреНрд░рдмрдВрдзрди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред



рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, libevent HTTP API рдореЗрдВ рдПрдХ рд╕реНрдерд╛рдиреАрдп рдкреЛрд░реНрдЯ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХрд╛ рд╡рд┐рдХрд▓реНрдк рдирд╣реАрдВ рд╣реИред рдореИрдВ рдЗрд╕ рддрд░рд╣ рдПрдХ рд╕рдорд╛рд░реЛрд╣ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП libevent рддрдп:

 void evhttp_connection_set_local_port(struct evhttp_connection *evcon, u_short port);.
      
      





рдпрд╣ рдПрдХ рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рд╕реБрдЦрдж рдЕрдиреБрднрд╡ рдерд╛: рдХрд╛рдордЪрд▓рд╛рдК рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд▓рд┐рдЦрд╛ рд╣реБрдЖ рд▓рдЧрддрд╛ рд╣реИ, рдФрд░ рдкреНрд░рд▓реЗрдЦрди рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИред



рдЗрд╕ рд╕рдВрд╢реЛрдзрд┐рдд рдкрд░рд┐рд╡рд╛рдж рдХреЗ рд╕рд╛рде, рдореИрдВ рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЬреЛрдбрд╝рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдерд╛:

 evhttp_connection_set_local_port(evhttp_connection, 1024+i);
      
      





рдЕрдм рд╡рд┐рднрд┐рдиреНрди рдкрддреЛрдВ рд╕реЗ рдХрдИ рдХрдиреЗрдХреНрд╢рди рд╕реНрдерд╛рдиреАрдп рдкрддреЗ рдХреЗ рд▓рд┐рдП рдкрд░рд┐рднрд╛рд╖рд┐рдд рдПрдХ рд╣реА рд╕реНрдерд╛рдиреАрдп рдкреЛрд░реНрдЯ рдирдВрдмрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдереЗред рдореИрдВрдиреЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдкреБрди: рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛, рдФрд░ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдереЛрдбрд╝реА рджреЗрд░ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рдиреЗ рджрд┐рдпрд╛ рдХрд┐ рдпрд╣ рдмрд╛рдзрд╛ рдХреЛ рдкрд╛рд░ рдХрд░реЗрдЧрд╛ред



Netstat рдЗрд╕рдХреА рдкреБрд╖реНрдЯрд┐ рдХрд░рддрд╛ рд╣реИ:

 # netstat -n | awk '/^tcp/ {t[$NF]++}END{for(state in t){print state, t[state]}}' TIME_WAIT 8 ESTABLISHED 118222
      
      





рдЗрд╕рд╕реЗ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рд╡рд┐рднрд┐рдиреНрди рд░рд╛рдЬреНрдпреЛрдВ рдореЗрдВ рдХрд┐рддрдиреЗ рдмрдВрджрд░рдЧрд╛рд╣ рдЦреБрд▓реЗ рд╣реИрдВред рд╣рдо рдЖрдЦрд┐рд░рдХрд╛рд░ 2 ^ 16 рд╕реЗ рдЕрдзрд┐рдХ рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓рдиреЗ рдореЗрдВ рдХрд╛рдордпрд╛рдм рд░рд╣реЗред



рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдЙрдкрдХрд░рдг рд╣реИ рдЬреЛ рдПрдХ рдПрдХрд▓ рдХрдВрдкреНрдпреВрдЯрд░ рд╕реЗ рдПрдХ рд▓рд╛рдЦ http рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдкреНрд░рддреНрдпреЗрдХ рдХрдиреЗрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рд▓рдЧрднрдЧ 2 KB рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рдХрд░реНрдиреЗрд▓ рдХреНрдпрд╛ рд░рдЦрддрд╛ рд╣реИред рдпрд╣ рд╣рдорд╛рд░реЗ рдореЛрдЪреАрд╡реЗрдм рд╕рд░реНрд╡рд░ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред



C1024K



рдЗрд╕ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ 4 рд╡рд┐рднрд┐рдиреНрди рд╕рд░реНрд╡рд░реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдЗрд╕ рдкрд░реАрдХреНрд╖рдг рдФрд░ рдкрд┐рдЫрд▓реЗ рд╡рд╛рд▓реЗ рдХреЗ рдмреАрдЪ рдореБрдЦреНрдп рдЕрдВрддрд░ рд╕реА рдореЗрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдПрдХ рд╕рдВрд╢реЛрдзрд┐рдд рдЧреНрд░рд╛рд╣рдХ рд╣реИред

рд╕рд░реНрд╡рд░ 1 - рдХреНрд╡рд╛рдб-рдХреЛрд░ 2GHz CPU, 16GB RAM

тАв рдЙрдкрдкреНрд░рдмрдВрдзрдХ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ

тАв рдбреЗрдЯрд╛ рд▓реЛрдб рд╣реЛ рд░рд╣рд╛ рд╣реИ

тАв рд░рд╛рдЙрдЯрд░ рд▓реЙрдиреНрдЪ

рд╕рд░реНрд╡рд░ 2 - рджреЛрд╣рд░реА рдХреНрд╡рд╛рдб-рдХреЛрд░ 2.8GHz рд╕реАрдкреАрдпреВ, 32 рдЬреАрдмреА рд░реИрдо

тАв рд▓реЙрдиреНрдЪ Mochiweb рдЖрд╡реЗрджрди

рд╕рд░реНрд╡рд░ 3 - рдХреНрд╡рд╛рдб-рдХреЛрд░ 2GHz CPU, 16GB RAM

тАв 17 рдЖрднрд╛рд╕реА рдЖрдИрдкреА рдкрддреЛрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг

тАв рдкрд░рд┐рд╡рд╛рдж рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ

тАв рдХреНрд▓рд╛рдЗрдВрдЯ рд╕реНрдЯрд╛рд░реНрдЯрдЕрдк: ./httpclient (рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб 100 рдХрдиреЗрдХреНрд╢рди)

рд╕рд░реНрд╡рд░ 4 - рдбреБрдЕрд▓-рдХреЛрд░ 2GHz, 2GB рд░реИрдо

тАв рд╕рдВрджреЗрд╢ рдХрд╛ рдПрдХ рдЧреБрдЪреНрдЫрд╛ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП msggen рдЪрд▓ рд░рд╣рд╛ рд╣реИ



рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓рдиреЗ рдХреЗ рджреМрд░рд╛рди рдФрд░ рдХреБрдЫ рд╕рдордп рдХреЗ рд▓рд┐рдП рдореЗрдореЛрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ:



HttpClient рдореЗрдВ рдХрдиреЗрдХреНрд╢рди рдХреЗ рдмреАрдЪ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд 10ms рджреЗрд░реА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдПрдХ рд▓рд╛рдЦ рдХрдиреЗрдХреНрд╢рди рдЦреЛрд▓рдиреЗ рдореЗрдВ рд▓рдЧрднрдЧ 3 рдШрдВрдЯреЗ рд▓рдЧрддреЗ рд╣реИрдВред рдЗрд╕рдореЗрдВ рд▓рдЧрднрдЧ 25GB рдореЗрдореЛрд░реА рд▓рдЧреА рдереАред рдпрд╣рд╛рдБ рдЧрдВрдЧрд╛рд▓рд┐рдпрд╛ рдХреА рдирдЬрд╝рд░ рд╕реЗ рдореЗрд░рд╛ рд╕рд░реНрд╡рд░ рдХреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИ:



рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдЗрд╕рдореЗрдВ рд▓рдЧрднрдЧ 38GB рд▓рдЧрддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рд╕реНрд╡реИрдкрд┐рдВрдЧ рд╢реБрд░реВ рд╣реЛрддреА рд╣реИред рдореБрдЭреЗ рд╕рдВрджреЗрд╣ рд╣реИ рдХрд┐ рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдореБрдЦреНрдп рдЦрдкрдд рдореЗрдВ рдЕрдВрддрд░ рд╣реИред



рд╕рдВрджреЗрд╢реЛрдВ рдХрд╛ рдФрд╕рдд 1000 рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрддреНрдкрдиреНрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдкреНрд░рддрд┐ 60ms рдкреНрд░рддрд┐ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рдмреАрдЪ рдФрд╕рдд рд╕рдордп, рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб рд▓рдЧрднрдЧ 16666 рд╕рдВрджреЗрд╢ рджреЗрддрд╛ рд╣реИ:

 erl> [ spawn( fun()->msggen:start(1000000, 10+random:uniform(100), 1000000) end) || I <- lists:seq(1,1000) ].
      
      





рдЧрдВрдЧрд╛рд▓рд┐рдпрд╛ рдореЗрдВ рд╕рд░реНрд╡рд░ 4:



рд▓рдЧрднрдЧ 10 рдПрдордмреА рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб - 16.666 рд╕рдВрджреЗрд╢ред



рдЬрдм рдореИрдВрдиреЗ рд╕рдВрджреЗрд╢ рднреЗрдЬрдиреЗ рд╢реБрд░реВ рдХрд┐рдП, рддреЛ рдкрд╣рд▓реЗ рд╕рд░реНрд╡рд░ рдкрд░ рд▓реЛрдб рдХрдо рд░рд╣рд╛ред рджреВрд╕рд░реЗ рд╕рд░реНрд╡рд░ рдкрд░ рд╕реАрдкреАрдпреВ рдХреА рдЦрдкрдд рдмрдврд╝реА:



рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ, рдХреНрдпреЛрдВрдХрд┐ рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рд╛рдЗрдмрд░рдиреЗрдЯ () рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛, рдореЗрдореЛрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдереЛрдбрд╝рд╛ рдмрдврд╝ рдЬрд╛рддрд╛ рд╣реИред рдХрд┐рд╕реА рднреА рд╕рдВрджреЗрд╢ рдХреЗ рдмрд┐рдирд╛ рд╕рднреА рдЦреБрд▓реЗ рдХрдиреЗрдХреНрд╢рди рд╣реЛрдиреЗ рд╕реЗ рдореЗрдореЛрд░реА рдЙрдкрдпреЛрдЧ рдореЗрдВ рдЗрд╖реНрдЯрддрдо рд╣реИред рдЖрд╢реНрдЪрд░реНрдп рдирд╣реАрдВ рдХрд┐ рдХрд┐рд╕реА рднреА рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рд╕реНрдореГрддрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред



рддреЛ рд╕реНрдореГрддрд┐ рдХрд╣рд╛рдБ рдмрд╣рддреА рд╣реИ? рдореЛрдЪреАрд╡реНрдм рдХреЛ 1,000,000 рд╕рдХреНрд░рд┐рдп рдХрдиреЗрдХреНрд╢рдиреЛрдВ рдХреЛ рдЦреБрд▓рд╛ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП 40 рдЬреАрдмреА рд░реИрдо рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рд▓реЛрдб рдХреЗ рддрд╣рдд, 30 рдЬреАрдмреА рддрдХ рдореЗрдореЛрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдореЛрдЪреАрд╡реЗрдм рдФрд░ рд╢реЗрд╖ 10 рдЬреАрдмреА рдХреЛрд░ рджреНрд╡рд╛рд░рд╛ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдкреНрд░рддрд┐ рдХрдиреЗрдХреНрд╢рди рд▓рдЧрднрдЧ 40Kb рдХреА рдЬрд░реВрд░рдд рд╣реИред



рдмрд╣реБрдд рд╕рд╛рд░реЗ рдХрдиреЗрдХреНрд╢рди рдХреЗ рд╕рд╛рде рд╡рд┐рднрд┐рдиреНрди рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ, рдореИрдВрдиреЗ sysctl.conf рдореЗрдВ рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рдмрджрд▓рд╛рд╡ рдХрд┐рдПред рдореИрдВ рдкрд░реАрдХреНрд╖рдг рдФрд░ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдЖрдпрд╛ рдерд╛, рдФрд░ рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рдореВрд▓реНрдпреЛрдВ рдХреЛ рдХреНрдпрд╛ рдмрджрд▓рдирд╛ рд╣реИред рдореЗрд░реА рдиреАрддрд┐ рдпрд╣ рдереА рдХрд┐ рдореИрдВ /var/log/kern.log рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рддреНрд░реБрдЯрд┐ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реВрдВ рдФрд░ рджреЗрдЦреВрдВ рдХрд┐ рд░рд╣рд╕реНрдпрдордп рддреНрд░реБрдЯрд┐ рдореБрдЭреЗ рдХреНрдпрд╛ рдмрддрд╛рддреА рд╣реИред рдпрд╣рд╛рдБ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рд╣реИрдВ:

 net.core.rmem_max = 33554432 net.core.wmem_max = 33554432 net.ipv4.tcp_rmem = 4096 16384 33554432 net.ipv4.tcp_wmem = 4096 16384 33554432 net.ipv4.tcp_mem = 786432 1048576 26777216 net.ipv4.tcp_max_tw_buckets = 360000 net.core.netdev_max_backlog = 2500 vm.min_free_kbytes = 65536 vm.swappiness = 0 net.ipv4.ip_local_port_range = 1024 65535
      
      





рдореИрдВ рдЕрдзрд┐рдХ рд╕реВрдЪрд┐рдд рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд┐рдирдХреНрд╕ рдЯреАрд╕реАрдкреА рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ред рд▓рдЧрднрдЧ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдпреЗ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдЗрд╖реНрдЯрддрдо рдирд╣реАрдВ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдХрдо рд╕реЗ рдХрдо рдпрд╣ 1,000,000 рдХрдиреЗрдХреНрд╢рди рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рдерд╛ред



рд▓рд┐рдмрд╡реЗрдВрдЯ рдкрд░ рдПрд░рд▓рдВрдЧ рдиреЛрдб



Libevent рдХреЗ рд▓рд┐рдП HTTP API рдХреЗ рд╕рд╛рде рдЫреЗрдбрд╝рдЫрд╛рдбрд╝ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдЙрдкрд░реЛрдХреНрдд рдкрд░реАрдХреНрд╖рдг рдХреЛ libevent HTTPd рдХреЗ рд╕рд╛рде N рдореЗрдВ рд▓рд┐рдЦрд╛ рдЬрд╛рдирд╛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЙрдЪрд┐рдд рд▓рдЧрддрд╛ рд╣реИред



рдореИрдВ erlang рдкрд░ рдЕрдзрд┐рдХ рд╕реЗ рдЕрдзрд┐рдХ рдХреЛрдб рдЫреЛрдбрд╝рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛, рддреЛ рдЖрдЗрдП C - C рдореЗрдВ рдПрдХ рдиреНрдпреВрдирддрдо рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ - рдХреЗрд╡рд▓ HTTP рдХрдиреЗрдХреНрд╢рди рдХреЛ рд╕рдВрднрд╛рд▓рддреЗ рд╣реБрдПред



рд▓рд┐рдмрд╡реЗрдВрдЯ рдореЗрдВ рдПрдХ рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ HTTP рдПрдкреАрдЖрдИ рд╣реИ, рдЬреЛ HTTP рд╕рд░реНрд╡рд░ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рддреБрдЪреНрдЫ рдмрдирд╛рддрд╛ рд╣реИред рдореИрдВрдиреЗ рдПрд░рд▓рдВрдЧ рдХреЗ рд▓рд┐рдП рд╕реА рдЗрдВрдЯрд░рдлреЗрд╕ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдХрд╛рд░рдг рднреА рджреЗрдЦрд╛ред рдпрд╣ рдПрдХ HTTP рд╕рд░реНрд╡рд░ рд╣реИ рдЬреЛ рдХрд┐ libevent рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдкреВрд░реЗ Id (рдЬреИрд╕реЗ рд╣рдорд╛рд░реЗ mochiweb рдПрдкреНрд▓рд┐рдХреЗрд╢рди) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреА рдкрд╣рдЪрд╛рди рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдПрдХ Erlang C-рдиреЛрдб рдХреЗ рд░реВрдк рдореЗрдВ рднреА рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред



рдпрд╣ рдПрд░реНрд▓рд╛рдВрдЧ-рдирд╛рдорд┐рдд рд╣реЛрд╕реНрдЯ рд╕реЗ рдЬреБрдбрд╝рддрд╛ рд╣реИ, {123, << "рд╣реИрд▓реЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 123" >>} рдЬреИрд╕реЗ рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рд╕реБрдирддрд╛ рд╣реИ, рдЕрдЧрд░ рдпрд╣ рдЬреБрдбрд╝рд╛ рд╣реБрдЖ рд╣реИ, рддреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 123 рдХреЛ "рд╣реИрд▓реЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 123" рднреЗрдЬрддрд╛ рд╣реИред рдЕрд╕рдВрдмрджреНрдз рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╕рдВрджреЗрд╢ рдкрд╣рд▓реЗ рдХреА рддрд░рд╣ рд╣реА рдЫреЛрдбрд╝ рджрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред

 #include <sys/types.h> #include <sys/time.h> #include <sys/queue.h> #include <stdlib.h> #include <err.h> #include <event.h> #include <evhttp.h> #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include "erl_interface.h" #include "ei.h" #include <pthread.h> #define BUFSIZE 1024 #define MAXUSERS (17*65536) // C1024K // List of current http requests by uid: struct evhttp_request * clients[MAXUSERS+1]; // Memory to store uids passed to the cleanup callback: int slots[MAXUSERS+1]; // called when user disconnects void cleanup(struct evhttp_connection *evcon, void *arg) { int *uidp = (int *) arg; fprintf(stderr, "disconnected uid %d\n", *uidp); clients[*uidp] = NULL; } // handles http connections, sets them up for chunked transfer, // extracts the user id and registers in the global connection table, // also sends a welcome chunk. void request_handler(struct evhttp_request *req, void *arg) { struct evbuffer *buf; buf = evbuffer_new(); if (buf == NULL){ err(1, "failed to create response buffer"); } evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=utf-8"); int uid = -1; if(strncmp(evhttp_request_uri(req), "/test/", 6) == 0){ uid = atoi( 6+evhttp_request_uri(req) ); } if(uid <= 0){ evbuffer_add_printf(buf, "User id not found, try /test/123 instead"); evhttp_send_reply(req, HTTP_NOTFOUND, "Not Found", buf); evbuffer_free(buf); return; } if(uid > MAXUSERS){ evbuffer_add_printf(buf, "Max uid allowed is %d", MAXUSERS); evhttp_send_reply(req, HTTP_SERVUNAVAIL, "We ran out of numbers", buf); evbuffer_free(buf); return; } evhttp_send_reply_start(req, HTTP_OK, "OK"); // Send welcome chunk: evbuffer_add_printf(buf, "Welcome, Url: '%s' Id: %d\n", evhttp_request_uri(req), uid); evhttp_send_reply_chunk(req, buf); evbuffer_free(buf); // put reference into global uid->connection table: clients[uid] = req; // set close callback evhttp_connection_set_closecb( req->evcon, cleanup, &slots[uid] ); } // runs in a thread тАУ the erlang c-node stuff // expects msgs like {uid, msg} and sends aa 'msg' chunk to uid if connected void cnode_run() { int fd; /* fd to Erlang node */ int got; /* Result of receive */ unsigned char buf[BUFSIZE]; /* Buffer for incoming message */ ErlMessage emsg; /* Incoming message */ ETERM *uid, *msg; erl_init(NULL, 0); if (erl_connect_init(1, "secretcookie", 0) == -1) erl_err_quit("erl_connect_init"); if ((fd = erl_connect("httpdmaster@localhost")) < 0) erl_err_quit("erl_connect"); fprintf(stderr, "Connected to httpdmaster@localhost\n\r"); struct evbuffer *evbuf; while (1) { got = erl_receive_msg(fd, buf, BUFSIZE, &emsg); if (got == ERL_TICK) { continue; } else if (got == ERL_ERROR) { fprintf(stderr, "ERL_ERROR from erl_receive_msg.\n"); break; } else { if (emsg.type == ERL_REG_SEND) { // get uid and body data from eg: {123, <<"Hello">>} uid = erl_element(1, emsg.msg); msg = erl_element(2, emsg.msg); int userid = ERL_INT_VALUE(uid); char *body = (char *) ERL_BIN_PTR(msg); int body_len = ERL_BIN_SIZE(msg); // Is this userid connected? if(clients[userid]){ fprintf(stderr, "Sending %d bytes to uid %d\n", body_len, userid); evbuf = evbuffer_new(); evbuffer_add(evbuf, (const void*)body, (size_t) body_len); evhttp_send_reply_chunk(clients[userid], evbuf); evbuffer_free(evbuf); }else{ fprintf(stderr, "Discarding %d bytes to uid %d тАУ user not connected\n", body_len, userid); // noop } erl_free_term(emsg.msg); erl_free_term(uid); erl_free_term(msg); } } } // if we got here, erlang connection died. // this thread is supposed to run forever // TODO тАУ gracefully handle failure / reconnect / etc pthread_exit(0); } int main(int argc, char **argv) { // Launch the thread that runs the cnode: pthread_attr_t tattr; pthread_t helper; int status; pthread_create(&helper, NULL, cnode_run, NULL); int i; for(i=0;i<=MAXUSERS;i++) slots[i]=i; // Launch libevent httpd: struct evhttp *httpd; event_init(); httpd = evhttp_start("0.0.0.0", 8000); evhttp_set_gencb(httpd, request_handler, NULL); event_dispatch(); // Not reached, event_dispatch() shouldn't return evhttp_free(httpd); return 0; }
      
      





рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреА рдЕрдзрд┐рдХрддрдо рд╕рдВрдЦреНрдпрд╛ #define рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реЗрдЯ рдХреА рдЧрдИ рд╣реИ, рдкреЛрд░реНрдЯ 8000 рд╕реБрдиреА рдЬрд╛рддреА рд╣реИ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рд╕реЗ рдЕрдкреЗрдХреНрд╖рд╛ рдХреА рдЬрд╛рддреА рд╣реИред рдХреБрдХреА рдиреЛрдб рдХрд╛ Erlang рдирд╛рдо рд╣рд╛рд░реНрдб-рдХреЛрдбреЗрдб рднреА рд╣реИред



рд╡рд╣ рдиреЛрдб рдкреНрд░рд╛рд░рдВрдн рдХрд░реЗрдВ рдЬрд┐рд╕рд╕реЗ рд╕рд░реНрд╡рд░ рдХрдиреЗрдХреНрдЯ рд╣реЛрдЧрд╛:

 $ erl -setcookie secretcookie -sname httpdmaster@localhost
      
      







C рдиреЛрдб рдЪрд▓рд╛рдПрдБ:

 $ gcc -o httpdcnode httpdcnode.c -lerl_interface -lei -levent $ ./httpdcnode
      
      





рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдиреЛрдб рджрд┐рдЦрд╛рдИ рджреЗ рд░рд╣рд╛ рд╣реИ:

 erl> nodes(hidden). [c1@localhost]
      
      





рдУрдкрди рд▓реЛрдХрд▓рд╣реЛрд╕реНрдЯ : 8000 / рдЯреЗрд╕реНрдЯ / 123 рдЕрдкрдиреЗ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ ред рдЖрдкрдХреЛ рдПрдХ рд╕реНрд╡рд╛рдЧрдд рд╕рдВрджреЗрд╢ рджреЗрдЦрдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЕрдЧрд▓рд╛, C рдиреЛрдб рдХреЛ рдПрдХ рд╕рдВрджреЗрд╢ рднреЗрдЬреЗрдВ:

 erl> {any, c1@localhost} ! {123, <<"Hello Libevent World">>}.
      
      





рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдо Pid рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ - рд╣рдо {procname, node} рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рд╣рдо "рдХрд┐рд╕реА рднреА" рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдХ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рдирд╛рдо рдХреЗ рд░реВрдк рдореЗрдВ рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕реЗ рд╕реА-рдиреЛрдб рджреНрд╡рд╛рд░рд╛ рдЕрдирджреЗрдЦрд╛ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред



рдЕрдм рдЖрдк Erlang рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рдВрджреЗрд╢ рджреЗрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╕рднреА рдХрдиреЗрдХреНрд╢рдиреЛрдВ рдХреЛ libevent C рдкреНрд░реЛрдЧреНрд░рд╛рдо рджреНрд╡рд╛рд░рд╛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ Erlang рдиреЛрдб рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред



рдбрд┐рдмрдЧ рдЖрдЙрдЯрдкреБрдЯ рдХреЛ рд╣рдЯрд╛рдиреЗ рдХреЗ рдмрд╛рдж, рдореИрдВрдиреЗ 1,000,000 рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдЙрд╕реА рдХреНрд▓рд╛рдЗрдВрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ httpdcnode рд╕рд░реНрд╡рд░ рд╕реЗ рдЬреЛрдбрд╝рд╛ рд╣реИ рдЬреЛ рдКрдкрд░ рдХреЗ рд╕рдорд╛рди рдХреНрд▓рд╛рдЗрдВрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реИред рдорд╢реАрди рдиреЗ рдХреБрд▓ 10 рдЬреАрдмреА рдореЗрдореЛрд░реА рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ред



рд╕рд░реНрд╡рд░ рдореЗрдореЛрд░реА 2GB рдХреЗ рдЖрд╕рдкрд╛рд╕ рд╕реНрдерд┐рд░ рдереА:





рдкреНрд░рддрд┐ рдХрдиреЗрдХреНрд╢рди 2KB рдХреЗ рдмрд╛рд░реЗ рдореЗрдВред



рдореЗрдореЛрд░реА рд╕реНрдерд┐рддрд┐:

 Mem: 32968672k total, 9636488k used, 23332184k free, 180k buffers
      
      





рддреЛ рдХрд░реНрдиреЗрд▓ / рдЯреАрд╕реАрдкреА рд╕реНрдЯреИрдХ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд 8Kb рдкреНрд░рддрд┐ рдХрдиреЗрдХреНрд╢рди рд▓реЗрддрд╛ рд╣реИ, рдЬреЛ рдЙрдЪреНрдЪ рд▓рдЧрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореЗрд░реЗ рдкрд╛рд╕ рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рднреА рдирд╣реАрдВ рд╣реИред



рдЗрд╕ libevent-cnode рд╕рд░реНрд╡рд░ рдХреЛ рд╕реНрд╡рдпрдВ рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдпрд╣ рдПрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕реЗ рдХрдИ рдХрдиреЗрдХреНрд╢рди рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдмреБрджреНрдзрд┐рдорд╛рди рдирд╣реАрдВ рд╣реИ, рдФрд░ рдЕрднреА рднреА "рджреМрдбрд╝ рдХреА рд╕реНрдерд┐рддрд┐" рд╣реИрдВ рдпрджрд┐ рдЖрдк рдХреЗрд╡рд▓ рд╕рдВрджреЗрд╢ рднреЗрдЬреЗ рдЬрд╛рдиреЗ рдкрд░ рдбрд┐рд╕реНрдХрдиреЗрдХреНрдЯ рдХрд░рддреЗ рд╣реИрдВред



рдЗрд╕рдХреЗ рдмрд╛рд╡рдЬреВрдж, рд╣рдордиреЗ рд╕рднреА рджрд┐рд▓рдЪрд╕реНрдк рдЪреАрдЬреЛрдВ рдХреЗ рд▓рд┐рдП рдПрд░реНрд▓реИрдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛, рдФрд░ рдирд┐рдореНрди рд╕реНрддрд░ рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЗ рд▓рд┐рдП C + libevent рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛ред рдПрдХ рд╕реА рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЛ рдбреНрд░рд╛рдЗрд╡рд░ рдпрд╛ рд╕реА рдиреЛрдб рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд▓рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдПрд░рд▓реИрдВрдЧ рдЗрдВрдЯрд░рдлреЗрд╕ рдЖрдкрдХреЛ рдПрдХ рд╕рднреНрдп рдПрдкреАрдЖрдИ рджреЗ рд╕рдХрддрд╛ рд╣реИред рдореБрдЭреЗ рдЕрднреА рднреА рдЗрд╕рдХреЗ рд╕рд╛рде рдкреНрд░рдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЗрдЪреНрдЫрд╛ рд╣реИред



рдЕрдВрддрд┐рдо рдирд┐рд╖реНрдХрд░реНрд╖





рдореЗрд░реЗ рдкрд╛рд╕ рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рдбреЗрдЯрд╛ рд╣реИ рдХрд┐ рдпрджрд┐ рд╣рдо рдПрдХ рдмрдбрд╝реЗ рд▓рд╛рд╕реНрдЯ.рдлреИрдо рд╕реНрдХреЗрд▓ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рддреИрдирд╛рдд рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдХреМрди рд╕реЗ рдЙрдкрдХрд░рдгреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рд╕рдмрд╕реЗ рдЦрд░рд╛рдм рд╕реНрдерд┐рддрд┐ рдореЗрдВ рднреА, рдкреНрд░рддрд┐ рдХрдиреЗрдХреНрд╢рди 40Kb рдПрдХ рдЕрдЪреНрдЫрд╛ рдкрд░рд┐рдгрд╛рдо рд╣реИ - рд╕реНрдореГрддрд┐ рдЗрд╕ рд╕рдордп рдмрд╣реБрдд рд╕рд╕реНрддреА рд╣реИ, рдФрд░ рд▓рд╛рдЦреЛрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП 40GB рдПрдХ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИред 10GB рднреА рдмреЗрд╣рддрд░ рд╣реИред



All Articles