Stream is saved in memory (in shared ETS table, in binaries) in chunks
500 KBytes each.
Client comes and asks for next chunk.
If I write server in C (or with linked-in driver), I whould just
manage common shared circular buffer from which I will send data and
remember
client position in this buffer. If client is too slow to read from
this buffer, it is disconnected and forgotten.
Such approach give ability to save memory and not to copy it in
buffers and driver queues.
Is it possible to have something like this in erlang?
Currently, I've got limits around 3 GBit/s from one erlang node on
loopback interface and I want to raise this limit.
When traffic comes to this limit, memory begins very fast growing and
when it reaches limits of RAM, massive disconnects happen.
This is why I think, that I should save memory first without trying to
write linked-in tcp driver =)
_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://erlang.org/mailman/listinfo/erlang-questions
You might be interested in the new (R15B) file:sendfile function, if having the data on disc is an option.
I think, that something like vmsplice may be an option. I see in
sources of file, that prim_inet:getfd is no here (yes, I know that it
is undocumented =)
and that is why I may use some weird tricks with optimizing.
sendfile is a bad option because:
1) I need to serve from memory
2) I need to serve several thousands of connections. Threads are not
the way to go.
However, I think that I will need to patch efile_drv for using
something like vmsplice
1) increment ref counter for binary in driver
2) replace writev with vmsplice for linux
3) release binary when data is transmitted
I need to check if this really works and helps.
My streaming server is in Erlang and uses this approach. Though a linked in driver is not a good idea. I started with a linked in driver but it was pretty much impossible to get it really stable. With NIFs you can use resources for sockets and stream buffers. They work beautifully.
I have a NIF thread that listens on kqueue/epoll and communicates with a gen_server. Sockets are resources.
Communication from NIFs to gen_server is simple since enif_send exists, communication from gen_server to the NIF thread is done by pipes (global library read pipe and write pipe).
1 thread NIF per core?I have a NIF thread that listens on kqueue/epoll and communicates with a gen_server. Sockets are resources.
Could you please elaborae further on how communication is made from Erlang to NIF (the read/write pipe)?Communication from NIFs to gen_server is simple since enif_send exists, communication from gen_server to the NIF thread is done by pipes (global library read pipe and write pipe).
> On thread initialization the pipes get created and read pipe is placed in epoll/kqueue. Write pipe is from erlang to NIF, and read pipe is for NIF to read that data. I have a simple struct:
> typedef struct kqmsg
> {
> char what;
> int fd;
> ErlNifPid pid;
> void* data;
> }kqmsg;
> So I just fill up this struct with whatever info is required and do: write(pipe_write,&msg,sizeof(struct kqmsg)
>
> As for sockets, I do not use prim_inet:getfd, sockets are completely separate from gen_tcp. The NIF thread keeps the socket FD until it reads the first buffer from it. Once this happens it creates a socket resource, then sends the binary and socket with enif_send to the Erlang process that is in charge of deciding what to do with it.
Does this approach "really" increase performances of your server?
Makes sense now. Thanks Sergej
Regards,
Zabrane