[erlang-questions] my socket can't handle the load

Bernard Duggan <>
Wed Jun 2 23:35:58 CEST 2010


Hi Pablo,
    One thing you may want to try is to wherever possible, avoid letting
the queue on your gen_server grow beyond a couple of messages.  Allowing
the queue to grow unchecked can cause serious performance degradation on
selective receives (which, to be fair, I can't see any of in your code,
but they can crop up in non-obvious library calls at times).
Off the top of my head, you'd do this by:
a) changing the handle_cast operation to a handle_call (to keep clients
using that operation from flooding you with requests) and
b) changing {active, true} to {active, once} in your connect call (and
making the corresponding change in handle_info to reactivate the socket.

It may or may not be your problem, but it's a fairly easy change and
worth a try.

Another possibility is that you have the same issue, but in the calling
process (I'm guessing now, since you haven't provided that code).  A
gen_server call does a selective receive while it waits for a response -
if your message queue is very large when you make the call, there's a
good chance you'll get a timeout regardless of how quickly the
gen_server serves the request.

Cheers,

Bernard

On 3/06/2010 1:27 AM, Pablo Platt wrote:
> Hi,
>
> I'm writing a driver to a database that is using a tcp socket.
> There are two types of messages, "send and forget" and "send and receive".
> I have a gen_server that is responsible for opening the socket, receive a message from a process and sending it to the socket and receive responses and pass them to the caller.
> The gen_server saves a list of {request_id, CallerPid} in the state to know who to respond to when a packet is received from the db. 
>
> Everything works when the rate of messages is low but when increasing it I'm starting to get gen_server timeout error on the requestor.
> Do I need to add/change parameters when opening the socket?
> Should I queue requests and wait for a response before sending the next request or is it ok to send several requests one after the other?
>
> Thanks
>
> The client sends a request using either:
> Resp = gen_server:call(Conn, {request, Request})
> or
> gen_server:cast(Conn, {request, Request})
>
>
> The relevant gen_server code:
>
> init([Host, Port]) ->
>     Socket = open_socket(Host, Port),
>     {ok, #state{socket=Socket, req_id=1}}.
>
> open_socket(Host, Port) ->
>     case gen_tcp:connect(Host, Port, [binary, {active, true}]) of
>         {ok, Sock} ->
>             Sock;
>         {error, Reason} ->
>             exit({open_socket_failed, Reason})
>     end.
>
> handle_call({request, Packet}, From, State) ->
>     ReqID = State#state.req_id + 1,
>     gen_tcp:send(State#state.socket, Packet),
>     {noreply, State#state{req_id=ReqID, requests=[{ReqID, From}|State#state.requests]}};
>
> handle_cast({request, Packet}, State) ->
>     ReqID = State#state.req_id + 1,
>     gen_tcp:send(State#state.socket, Packet),
>     {noreply, State#state{req_id=ReqID}}.
>
> handle_info({tcp, _Socket, Data}, State) ->
>     RawResp = <<(State#state.resp)/binary, Data/binary>>,
>     case check_packet:decode_response(RawResp) of
>         undefined ->
>             {noreply, State#state{resp = RawResp}};
>         {Resp, Tail} ->
>             ResponseTo = get_requestor(Resp),
>             {value, {ResponseTo, Client}, NewRequests} = lists:keytake(ResponseTo, 1, State#state.requests),
>             gen_server:reply(Client, Resp),
>             {noreply, State#state{resp = Tail, requests=NewRequests}}
>     end;
>
> % the following never been called, even when I'm getting the error.
> handle_info({tcp_closed, _Socket}, State) ->   
>     {noreply, State};
>
> handle_info({tcp_error, _Socket, _Reason}, State) ->
>     {noreply, State}.
>
> terminate(_Reason, _State) ->
>     ok.
>
>
>
>       



More information about the erlang-questions mailing list