IRC Log


Tuesday January 4, 2011

[Time] NameMessage
[05:42] jugg I've done some work updating the zmq erlang bindings, for the most part things are working well now, but I'm running into issues with events on the socket FD (that was retrieved using ZMQ_FD getsockopt). question: Can the FD be used in poll/select in one thread while the Socket is being used in other thread? eg. the erlang vm sits on the FD in the poll/select call while waiting for an event and in the mean time other socket operations may be performe
[06:45] sustrik jugg: no
[06:45] sustrik sockets are not thread safe
[06:46] sustrik you can access a socket from at most one thread at a time
[06:48] jugg Is this zmq specific, or (I've not yet been able to find an answer) is it the case that a normal file descriptor would have problems if one thread used it in a poll() call, while another thread tried to read/write to it?
[06:49] sustrik normal FDs are thread safe
[06:50] sustrik 0mq is special as it uses lock-free algorithms
[06:50] sustrik thus, it cannot synchronise the access using mutex or somesuch
[06:51] sustrik you can apply a mutex on top of it yourself, if that's what you need
[06:51] sustrik but be aware of the performance impact
[06:51] jugg What makes the socket FD different than a normal FD in this regards?
[06:51] jugg No, that isn't an option for the erlang bindings...
[06:59] neopallium jugg: the 0mq FD is just a socketpair to sent notices that there are messages/commands to read from the socket's queue.
[07:00] neopallium the message data you get from recv() is transferred in-memory from a lock-free queue, not over the socketpair.
[07:02] neopallium jugg: are you making a erlang port or a linked-in driver?
[07:03] jugg linked-in driver - its based off of the broken erlzmq bindings.
[07:10] jugg So if the socket FD is a socketpair, what makes it not usable in a poll call from one thread while another thread uses the socket? Does zmq listen for events on the socket internally (outside of zmq_poll itself)?
[07:11] sustrik jugg: yes, it does so in zmq_send, zmq_recv and alike
[07:12] jugg ok... well, time to approach the erlang binding architecture differently then... :/
[07:14] neopallium sustrik: if the polling thread just calls poll() and not any zmq_* functions like zmq_poll(), would it still cause an issue?
[07:14] jugg if other parts of zmq consume the socketpair events, then yes...
[07:14] neopallium jugg: what is your polling thread doing with the events it gets back from the 0mq FD?
[07:15] jugg Notifies the socket owner thread and event occurred.
[07:16] jugg and => an
[07:16] neopallium ok, even if the owner thread gets a old POLLIN or POLLOUT event it can still try to call zmq_send/zmq_recv() with the NOBLOCK flag.
[07:16] neopallium it will just get an EAGAIN if it had already comsumed the event.
[07:17] jugg the problem is that it does not get a POLLIN/OUT event - as it appears the zmq internals are consuming those events...
[07:17] jugg which from sustrik's statement confirms this.
[07:17] neopallium do you use the NOBLOCK flag?
[07:18] jugg I don't see the relevance... the problem is the erlang poll is not being signaled an event occurred...
[07:18] neopallium your owner thread should be calling zmq_send()/zmq_recv() with the NOBLOCK flag, and only if it get EAGAIN, do it wait for an event notice from the polling thread.
[07:18] sustrik neopallium: getsockopt(ZMQ_EVENTS) consumes events from the socket pair
[07:19] neopallium sustrik: yes, and he should only call that from the owner thread not the poller thread.
[07:20] sustrik jugg: why do you need to combine recv and poll from different threads
[07:20] sustrik (i know, erlang is tricky)
[07:21] sustrik neopallium: i assume the problem is how erlang VM works
[07:21] sustrik it's kind of thread-agnostic
[07:22] neopallium jugg: have you tried an external C port? it would make this must similar.
[07:23] neopallium sustrik: yeah, the book I have on erlang doesn't have much details about how the linked-in driver interface is effected by any internal threads that the erlang VM might have.
[07:25] sustrik the erlang binding is a troublesome one
[07:25] sustrik originally it was written by shammika pathirana
[07:25] jugg the only way to wait on an event in erlang is to provide the fd to the erlang vm. The erlang vm, then calls the driver callback routine input/output_ready depending on the event type. The callback is an arbitrary thread. That callback checks the fd if an even actually occurred on the socket using getsockopt(ZMQ_EVENTS), and if so, then sends a notification back into the erlang world notifying an erlang process which owns the socket. That erlang pr
[07:25] sustrik who had no erlang experience at the time afaik
[07:26] sustrik then it was fixed by serge aleynikov
[07:26] sustrik later on we've created some fixes when working on RabbitMQ/0MQ bridge with VMWare
[07:26] neopallium jugg: are you sure the vm is using a different polling thread from the callbacks?
[07:26] sustrik this are not yet in
[07:26] sustrik etc.
[07:27] jugg neopallium, the callback gets called from arbitrary threads... I don't know for sure if the poll is happening in the same thread or not.
[07:28] sustrik what about an alternative architecture: poll on FD, when signaled remove it from the pollset then read, when read is done, return it to the pollset
[07:29] neopallium jugg: why not do the zmq_recv() in the output_ready() callback instead of sending a notice to the erlang process (which is not a real thread/process).
[07:30] jugg sustrik, I'm already half way down that path...
[07:30] neopallium even if you are sending a notice back to the erlang process (saying hay you can read now), that erlang process will just send a port command which will be delivered to the port
[07:30] jugg neopallium, that has issues with multi-part messages...
[07:31] neopallium the ports callbacks should be restricted to one thread.
[07:31] neopallium I don't see any warnings that linked-in drivers need to be thread-safe.
[07:32] neopallium jugg: do you deliver each part of the message in a different message back to the controlling process?
[07:33] jugg each erlzmq recv call acts just like zmq_recv. It'll return each part separately.
[07:34] sustrik jugg: btw, there's a problem with erlzmq project now; as i've mentioned dhammika is not really an erlang guy and serge has unrelated problems now that prevent him from doing stuff
[07:35] sustrik in case you are interested i can give you commit access...
[07:36] jugg sustrik, let me get this working successfully, and I'll ping you then for access.
[07:37] sustrik jugg: ok, good
[07:38] sustrik there's also VMware patch that solves the sender-side backpressure IIRC
[07:38] jugg sustrik, just to clarify something.. you said getsockopt(ZMQ_EVENTS) consumes the socketpair events... do you mean payload or events that would trigger a waiting poll call?
[07:39] sustrik it consumes internal 0mq events from the socket pair
[07:39] neopallium jugg: it reads from the socketpair which will consume the POLLIN event from the FD
[07:40] sustrik let me give an overvirew of the achitecture
[07:40] sustrik the actual TCP sockets are handled by background threads
[07:40] sustrik making sending/receiving messages asynchronous
[07:41] sustrik the user's thread communicates with background (I/O) threads using so called 'commands'
[07:41] sustrik these are sent via a socketpair connecting the user thread and the I/O thread
[07:42] sustrik example of a command sent from I/O thread to user's thread would be "there are messages available for reading"
[07:43] sustrik when user's thread get that command it knows it can unblock (in case it's blocked in recv) and read new messages from the lock-free queue
[07:43] sustrik that's more or less it
[07:45] jugg are socketpairs ever shared with multiple zmq sockets?
[07:46] jugg or does every zmq socket have its own socketpair?
[07:46] sustrik every socket has it's own socketpair
[07:47] sustrik this is needed to be able to migrate sockets between threads
[07:47] sustrik so, to be precise, in 2.0.x multiple sockets share single socketpair
[07:47] sustrik in 2.1 there's one socketpair per 0mq socket
[07:50] jugg ok. Thanks, this helps my mental picture. I have a couple of approaches to test out now.
[07:51] sustrik good luck :)
[07:52] sustrik ah, btw, erlang binding works with 2.1 only anyway
[07:52] sustrik so you don't have to take the case where the socketpair is shared between sockets into account
[07:54] jugg yes
[07:59] neopallium jugg: I think you should only register events with driver_select() when the 0mq socket is blocked as reported by ZMQ_EVENTS.
[07:59] neopallium and when you are waiting for an event back from the vm don't call zmq_recv() or ZMQ_EVENTS until the event comes back.
[08:00] jugg that is interesting
[08:00] neopallium that way the owner thread can't consume events from the socketpair.
[08:01] neopallium I found the details about driver's and erlang threads.
[08:01] neopallium and by default the driver will only have one thread access it at a time.
[08:02] neopallium you can do locking at driver or port level, the default is locking at the driver level.
[08:03] neopallium if you don't share 0mq sockets between ports it should be possible to use port-level locking.
[08:04] neopallium also remember to remove the event notice from the socket after receiving the event and mark the socket as readable/writable.
[08:05] neopallium sustrik basically said the same thing earlier about removing the socket from the pollset (i.e. from driver_select()) when it is readable.
[08:06] jugg I'm not sure what you meant by "remove the event notice"... are you talking an implementation concept, or an erlang requirement?
[08:07] neopallium jugg: driver_select(port, event, mode, /* put 0 here. */)
[08:08] neopallium that last arg. is for clearing the event (i.e. removing it from the pollset)
[08:09] jugg yes. But my understanding is (although it has been hard to find supporting evidence) that it isn't a requirement normally to do that in order for the erlang vm to report subsequent events on a fd.
[08:10] neopallium jugg: is your current problem that you are not receiving an event from the vm?
[08:11] jugg yes, but I think between sustrik's comment on getsockopt(ZMQ_EVENTS) consuming events, and his description on how things work, I can see why that is the case...
[08:11] neopallium 0mq sockets are edge-triggered, that means you need to read from them until they will block (i.e. you get EAGAIN)
[08:11] jugg yes
[08:12] neopallium when your driver call getsockopt(ZMQ_EVENTS) and it says there is a message to read, then you need to mark the socket as readable, until you read a full message.
[08:13] neopallium once you read a full message call ZMQ_EVENTS again to check if there is another message to read, if it reports "no messages", then you wait for a read event from the vm.
[08:14] neopallium I think there was an example in the guide that use ZMQ_EVENTS like that.
[08:14] sustrik yes, more or less
[08:15] sustrik but you don't have to store the "readable" flag yourself
[08:15] sustrik you can retrieve it from 0mq by calling getsockop(ZMQ_EVENTS) actually
[08:15] jugg yes, I think the key is to implement a poll method which checks ZMQ_EVENTS prior to passing the fd to the erlang vm, and only do so if nothing is pending.
[08:15] sustrik yes
[08:17] neopallium jugg: is this driver pushing messages out to the controlling erlang process? or does the erlang process block in a recv() type function for each message?
[08:22] jugg the driver returns messages only if the erlang process requests it via recv(). Of course, driver does not block in the recv() call, as that'd freeze the vm. It later pushes the incoming message when it comes available - thus the driver must use the fd to be notified of such an event. A gen_server is used to ensure further requests to the driver is not made, and the calling erlang process is blocked in the gen_server call until the driver eventually
[08:22] jugg of course the erlang process can call a non blocking recv as well.
[08:23] jugg (the old erlzmq did not support that last)
[08:27] jugg sustrik, does one only use the socketpair fd with POLLIN? even if waiting for the zmq socket to become writeable?
[08:28] neopallium jugg: so the erlang sends the port a {call, recv} type message telling it to call zmq_recv() and send back a part of the message.
[08:28] sustrik jugg: yes
[08:28] sustrik POLLOUT makes no sense
[08:28] jugg sustrik, ok
[08:29] jugg neopallium, the driver will always call zmq_recv with NOBLOCK. But if the erlang requests did not specify NOBLOCK, and zmq_recv returns EAGAIN, then the driver calls driver_select on the socket fd, and waits for an event, at which point it reads from the socket and returns the received message part to the erlang process.
[08:29] neopallium sustrik: so if the 0mq socket blocks on zmq_send(), do you have to wait for a POLLIN from the socketpair and the check with ZMQ_EVENTS if the socket is writable?
[08:30] sustrik yes
[08:30] sustrik the underlying socketpair is actually used for uni-directional transfer of commands
[08:30] neopallium ok, I need to fix my Lua async handler for 0mq sockets.
[08:30] sustrik so POLLOUT is always signaled
[08:31] sustrik i think it's mentioned in the reference
[08:31] sustrik let me check
[08:31] jugg sustrik, the docs could be clarified on that regards... It kind of says so, but it was unclear.
[08:31] neopallium yeah, I am basically doing a POLLOUT on the socketpair when zmq_send() returns EAGAIN.
[08:32] neopallium it is hard to test blocking on zmq_send()
[08:32] jugg indeed :/
[08:32] sustrik "0MQ library shall signal any pending events on the socket in an edge-triggered fashion by making the file descriptor become ready for reading"
[08:33] sustrik how would you reprharse that?
[08:33] neopallium .... signal any pending events from getsockopt(ZMQ_EVENTS...) when the FD is readable?
[08:34] sustrik i don't understand that :)
[08:34] sustrik maybe 2 sentences?
[08:34] neopallium it needs to say something about calling getsockopt(ZMQ_EVENTS...) for the ready events.
[08:35] sustrik "The ability to read from the returned file descriptor does not necessarily indicate that messages are available to be read from, or can be written to, the underlying socket; applications
[08:35] sustrik must retrieve the actual event state with a subsequent retrieval of the ZMQ_EVENTS option."
[08:35] sustrik see zmq_getsockopt(3)
[08:36] neopallium how about something like: "0MQ library shall signal any pending events by making the FD readable, getsockopt(ZMQ_EVENTS...) returns which events are pending."
[08:37] sustrik that's better
[08:37] neopallium yeah, but not perfect
[08:37] sustrik but kind of duplicates what the note above says
[08:38] sustrik have a look at whole ZMQ_FD section and feel free to propose a better wording
[08:40] neopallium hmm, yeah I guess the original dues say that in the Note
[08:41] neopallium maybe just add a note that checking for POLLOUT on the FD is use-less for finding out if it is writable?
[08:42] jugg is it the case to mark the socketpair FD read, one must call getsockopt(ZMQ_EVENTS), else subsequent calls to poll will always return immediately?
[08:44] neopallium jugg: if you get a POLLIN event from poll() you will need to call getsockopt(ZMQ_EVENTS) to clear that event, or you will just keep getting the POLLIN.
[08:46] neopallium I think from a simple event loop it would be best to call getsockopt(ZMQ_EVENTS) on each POLLIN event and then dispatch the real POLLIN/POLLOUT events as returned from getsockopt(ZMQ_EVENTS).
[08:47] neopallium that is what I am going to try with my async. handlers.
[08:49] sustrik jugg: the event is cleared also when you call non-blocking recv() which returns with EAGAIN
[09:26] mikko good morning
[09:53] sustrik morning
[09:57] mikko hmm, [zeromq-dev] Segfault
[09:57] mikko looks like to be related to the HWM bug we discussed ages ago
[09:58] sustrik mikko: the one you've gave me the test case for?
[09:58] mikko sustrik: i think so
[09:58] sustrik i've looked into that but the problem was not obvious
[09:58] sustrik i'll have to look at it further
[09:58] mikko man, year after year it's harder to come back to work after holidays
[09:59] sustrik same here :)
[10:15] neopallium I hit this assertion in zeromq: Assertion failed: msg_->flags & ZMQ_MSG_MORE (rep.cpp:80)
[10:15] neopallium that is from a REP socket with a XREQ client.
[10:16] neopallium is it bad to connect a XREQ socket to a REP socket?
[10:18] neopallium hmm, looks like XREQ -> REP is a supported setup.
[10:23] jugg I believe REP socket expects at least two message parts, but three is needed. <msg id> <empty msg> <msg body>. Both <msg id> and <empty msg> should be sent with SNDMORE flag set.
[10:26] jugg basically, your application code on the xreq side passes in <msg body> (in one or more parts). The xreq wrapper layer must then provide an identifier for that <msg body> and send that along to the rep socket, along with an empty message so that the rep socket and delineate between id parts and body parts. When the rep socket responds, your xrep wrapper layer pulls off the msg id part and looks up who to route the body part to.
[10:28] jugg "...so that the rep socket can delineate.."
[10:29] neopallium jugg: yup, REQ/REP sockets hid the "address" part of the message, XREQ/XREP expose the "address" part.
[10:30] neopallium I am trying a manual example with the plain lua-zmq bindings to make sure it is not just my use of zmq that is cause it.
[10:30] jugg so, you were already sending along the message id and blank msg?
[10:30] jugg with SNDMORE set?
[10:31] neopallium testing that right now, making a minimal example.
[10:41] neopallium jugg: https://gist.github.com/764629
[10:42] neopallium also sometime I got a crash on the XREQ side.
[10:42] neopallium but not an assertion, just a core dump.
[10:43] jugg I believe the delim needs to be empty, zero bytes. You are sending a single byte.
[10:43] jugg try: s:send("", zmq.SNDMORE)
[10:44] neopallium ah, yeah, I just tried that and it worked
[10:44] jugg cool
[10:44] neopallium I don't know where I read to send "\0" as the delim. part
[11:05] orestis Hello, I'm wondering how 0mq fits in with a GUI event loop - is it safe to make 0mq requests from the GUI thread?
[11:05] mikko orestis: you mean whether it would block?
[11:06] mikko orestis: can you integrate external filehandle polling to your gui event loop?
[11:06] mikko you can get ZMQ_FD from the socket and use that event loop
[11:07] mikko then in the callback check for ZMQ_EVENTS
[11:29] orestis Thanks. That looks a bit too cutting-edge for my taste. I guess my original question was, are the 0mq send/receive calls async? I'm a bit confused because there are mentions of background threads.
[11:33] mikko orestis: send/recv is async yes but there is a possiblity that the calls block
[11:33] mikko unless ZMQ_NOBLOCK is used
[11:37] orestis Thanks. In general, is 0mq a bit more low-level for doing async I/O from something like Twisted (that gives you Deferreds, Callbacks etc)?
[11:38] mikko orestis: i guess that is true. then again as far as i understand twisted is more general purpose ae framework where as 0mq is messaging stack
[11:41] orestis yes, apparently. I mainly wanted to use 0mq to split a monolithic gui app that does heavy I/O into separate processes. I definitely want to use Twisted for Deferreds and Callbacks (and Twisted plays well with GUIs) so I was wondering how to bring everything together.
[11:42] mikko orestis: you should be able to integrate 0mq into twisted
[11:42] mikko using the methods i mentioned earlier
[11:44] orestis mikko: they're not in the stable version though, are they?
[11:45] mikko orestis: if you mean 2.0.x then no
[11:45] mikko but 2.1.x seems fairly stable
[11:45] mikko i use github trunk in all my developments
[12:14] orestis mikko: thanks for your input. I'll see what I can come up with.
[12:21] jugg The documentation for ZMQ_IDENTITY is not clear to me. I assume that the zmq context has to be maintained in order for a socket's identity to be re-usable? But terminating the zmq context will lose the identity persistence?
[15:55] Seta00 how do I build 0MQ with MinGW?
[15:55] mikko Seta00: configure && make && make install i guess
[15:55] mikko Seta00: i got mingw build running on linux machine
[15:55] Seta00 :P
[15:56] mikko haven't tried on windows in a while
[15:56] mikko i got mingw32 on linux and VS2008 on windows in daily builds
[15:56] mikko maybe mingw32 on windows would be a good addition
[15:57] Seta00 definitely :)
[16:00] Seta00 working with various libraries can get messed up really fast
[16:12] Seta00 msg_store.cpp:279: error: ISO C++ does not support `long long'
[16:12] Seta00 why aren't things easier? hehe
[16:13] sustrik Set00: is that 2.0.10?
[16:13] Seta00 sustrik, yes
[16:13] sustrik i recall the long long issue was being solved
[16:13] sustrik maybe it's fixed in 2.1
[16:14] sustrik mikko: don't you remember by chance?
[16:14] Seta00 I'll try
[16:26] Seta00 2.1.0 gives me ".../mingw/lib/dllcrt2.o: No such file or directory" when linking
[16:27] sustrik :|
[16:28] sustrik no idea what that is
[16:28] sustrik as for the long long problem
[16:29] sustrik iirc the problem is that long long is not part of C++ standard, yet it it used in Win32 signatures
[16:29] sustrik Win32 API
[16:30] Skaag I wonder if anyone else is using google protocol buffers to send messages over zmq
[16:31] Seta00 I'm trying with uint64_t
[16:33] Seta00 doesn't work
[16:34] Seta00 how can I remove -Werror?
[16:34] Seta00 other than manually editing the makefile?
[16:35] Seta00 long works fine, but msys doesn`t find that DLL
[16:40] sustrik no idea, try checking configure.in
[16:41] Seta00 forgot to configure fstab
[16:42] mikko sustrik: yes
[16:42] mikko ah, it was answered
[16:42] mikko long long problem is with 2.0.x
[16:43] mikko it's fixed in 2.1.0
[16:43] sustrik thx
[16:46] mikko Skaag: there has been a couple of mentions about that
[16:46] mikko Seta00: i can test mingw32 build when i get home
[16:47] Seta00 mikko, it worked after I configured my fstab on MSYS
[16:47] Seta00 thanks sustrik and mikko
[16:47] sustrik you are welcome
[16:47] Seta00 now I need qmake to link to it :P
[16:48] Seta00 which shall be solved in #qt
[16:48] Seta00 :)
[16:48] mikko i remember someone doing this before
[16:48] mikko with qt toolchain
[16:48] mikko that sparked the whole fixing of mingw32 builds
[17:28] s0undt3ch with pyzmq, on a publisher subscriber model, I'm setting the publisher's identity, how can a subscriber retrieve that identity
[17:28] s0undt3ch ?
[17:31] sustrik it can't
[17:33] s0undt3ch hmmm
[17:33] s0undt3ch I need to pass that on the message then
[17:34] sustrik yes, the identity is only internel per-hop mechanism
[17:34] sustrik it's not passed all the way down from publisher to subscriber
[17:39] s0undt3ch sustrik: same for req/rep right?
[17:41] Seta00 s0undt3ch, are you on windows?
[17:44] sustrik same for all patterns
[17:45] sustrik req/rep is special in that identities are stuck to the request as it passes individual nodes
[17:46] sustrik but there's still no special mechanism to inspect peers' identities
[17:48] s0undt3ch Seta00: nope
[17:49] Seta00 just checking if someone has a pyzmq build for Windows
[18:54] Joes Hello. It is very tempting for me to use ZeroMQ, but I'm trying to figure out how architecture would look like. So, we have chat server (a-la IRC) with chat rooms.
[18:54] Joes Users can join multiple rooms and I need to route messages between users in same room.
[18:54] Joes As far as I understood tutorials, I need 2 connections
[18:55] Joes one pubsub to send room events back to users
[18:55] Joes and one pubsub to send events from users to rooms?
[18:55] Joes can it be done with only one connection?
[18:55] Joes (or socket)
[19:16] mikko Joes_: you would need two
[19:17] Joes in terms of low level communication with tcp transport - two tcp ports on the server will be used
[19:17] Joes correct?
[19:17] Joes (firewall setup, etc)
[19:18] mikko Joes_: assuming you bind the two sockets then yet
[19:18] mikko yes*
[19:18] Joes ok
[19:18] Joes and second question - any bindings for Javascript?
[19:18] mikko i think someone was working for node.js bindings
[19:18] Joes using WebSockets/socketjs/etc
[19:18] Joes saw them
[19:18] Joes includes native C code
[19:19] Joes is wire protocol documented?
[19:19] mikko yes, i think it is
[19:19] mikko gimme a sec
[19:20] mikko here is the message format http://rfc.zeromq.org/spec:2
[19:20] Joes thanks
[19:20] mikko let me see if the rest is documented
[19:21] Joes going to see how long it will take to write dumb client in JS
[19:21] Joes there's one for AMQP, but nothing for ZeroMQ
[19:21] Joes and I don't need 95% of AMQP features...
[19:22] mikko are you going to do communications from browser straight to 0mq?
[19:22] Joes well, that would be ideal
[19:22] mikko i don't think that's going to work
[19:23] mikko at least with websockets
[19:23] mikko as websockets have their own framing as well
[19:23] Joes instead of making own wire protocol
[19:23] Joes hm
[19:23] mikko have you looked into mongrel2?
[19:24] Joes I did
[19:24] Joes however, I can't find any benchmarks
[19:24] Joes or who's using it in production
[19:24] mikko it's very new tech, i would be surprised if there are large installations yet
[19:25] mikko and i tend to find benchmarks mainly useless as there are a lot of people who don't know how to benchmark the software
[19:25] mikko or optimize it for benchmarking
[19:25] Joes well, at least some rough numbers would help
[19:25] Joes like faster than X Y times
[19:27] mikko but very often i find they are comparing apples to oranges
[19:27] mikko one tool with highly optimized config against incorrect config of other
[19:27] Joes I see.
[19:28] mikko it's very hard to create good benchmarks
[19:32] mikko but communicating from browser you most likely need some sort of middle piece
[19:32] mikko probably doesn't need to be complicated but something that converts websocket messages to 0mq messages
[19:32] Joes Let's assume I have middlepiece - some kind of broker between browser and 0MQ
[19:32] Joes (thought about it)
[19:32] Joes with some simple wire protocol
[19:32] sustrik i think that's mostly what mongrel2 does
[19:33] Joes but I have following issues:
[19:33] Joes 1. Who will guarantee delivery, if client drops connection
[19:33] Joes (I will need to queue up messages for this client till his next connection)
[19:33] Joes well, there some other issues, but I don't remember them all :-)
[19:33] mikko if client drops connection do you want to queue messages?
[19:34] mikko for how long time after client leaves?
[19:34] Joes I don't know if client dropped or temporary lost connection to the server and will reconnect shortly
[19:34] sustrik can be done using ZMQ_IDENTITY
[19:34] Joes em
[19:34] Joes let's say I'm am the server which handles requests from browsers.
[19:34] Joes I accepted raw TCP connection (or websocket connection)
[19:35] Joes so, for this connection, I will create 0MQ socket (or two, but it does not matter now)
[19:35] Joes and will connect to the chat server
[19:35] sustrik right
[19:35] Joes if incoming (browser) connection will drop
[19:35] Joes I should close socket?
[19:35] Joes (0MQ socket)
[19:36] sustrik no, 0MQ socket represents all the connections
[19:36] sustrik so closing it means closing all the connections
[19:36] Joes hm
[19:36] Joes 1 socket for all incoming clients?
[19:36] sustrik yes
[19:37] Joes who will be doing queuing of the messages for temporary disconnected clients?
[19:37] sustrik the server
[19:37] Joes I see
[19:37] sustrik to be precise, the 0MQ socket in the server
[19:37] Joes hm
[19:38] sustrik all you need to do is set the ZMQ_IDENTITY socket option on the client
[19:38] sustrik that way the server socket would know that is should not deallocate the connection when it accidentally breaks
[19:38] sustrik the messages will be stored
[19:38] sustrik and once the same client re-connects they will be sent
[19:39] Joes that's the problem - I will have to write proxy between browser and 0MQ server
[19:39] mikko i think you are talking about separate issue
[19:39] mikko in this case:
[19:39] mikko chat server <-- 0mq --> broker <-- raw tcp --> client
[19:39] Joes yep
[19:40] Joes so, my question is - I'm adding extra logic on broker side to handle another wire protocol, message queuing (connection persistence logic like in 0MQ)
[19:40] Joes is it worth of the trouble?
[19:41] Joes broker can be "end point"
[19:41] Joes not scalable solution, though
[19:41] mikko the only thing you have described about the application this far that it's a chat like irc
[19:41] Joes yep, pretty much
[19:42] mikko is this from scratch or do you have something running already?
[19:42] Joes scratch
[19:42] Joes prototyping
[19:43] Joes well, in terms of possible load - ~12k users average online
[19:43] Joes each making ~1 message in 5 seconds (worst case)
[19:43] Joes ajax with long polling does not suit very well
[19:44] mikko why do you need to queue the messages if the client drops?
[19:44] Joes so, trying to find other possibilities apart of writing custom protocol on top of raw sockets
[19:44] Joes to keep state of the room and its recent history
[19:45] Joes it is doable by resending last N items on reconnect
[19:45] Joes which solves the problem, but.. if 0MQ provides it for free..
[19:49] mikko let me think for a sec
[19:49] mikko the biggest problem is the last part to the browser
[19:49] Joes yep
[19:49] Joes I want to get rid of it by having simple, yet functional, 0mq client
[19:50] Joes let's assume there's no WebSocket wrapping for now.
[19:50] Joes plain tcp sockets
[19:50] mikko you are not in control of the client side i assume?
[19:51] mikko as in installing 0mq on client :)
[19:51] Joes nope.
[19:51] Joes plain HTML+JS
[19:51] Joes and, maybe, some Flash.
[19:51] Joes (I already checked almost all language integrations - all of them are dependent on the native C library)
[19:54] mikko yes, i think you would need to implement some logic in your broker
[19:55] Joes in terms of code, for 1 incoming browser it will create 0mq socket or it will handle all incoming browser connections through 1 0mq socket?
[19:55] Joes what is better approach?
[19:56] Joes multiple sockets - free message queuing
[19:56] Joes one socket - easier overall architecture (and speed?), but manual queuing on the broker
[19:57] Joes plus, custom wire protocol from broker to browser
[19:57] Joes etc.
[19:57] mikko one socket also requires custom filtering i guess
[19:57] mikko you got messages coming in 1 socket destined to ~12k clients
[19:57] Joes well, I can read address from the message
[19:58] mikko so you need to write them to correct handles on other side
[19:58] Joes and then pick proper browser socket and send it there
[19:58] Joes yep
[19:58] Joes it = message
[19:59] mikko one socket might be easier to handle for events as well
[19:59] mikko otherwise you got a pollset of 12k items
[19:59] mikko that you need to maintain
[19:59] Joes yeah
[19:59] Joes bad idea.
[19:59] Joes ok, another idea.
[19:59] Joes I write pure JS implementation of the wire protocol
[19:59] Joes it's pretty simple
[19:59] Joes and broker will be dump WebSocket negotiator and TCP proxy
[20:00] Joes (forwards tcp connection to the real 0MQ server port)
[20:00] Joes I assume it might work.
[20:00] Joes each message sent will have address as a first chunk
[20:00] Joes so chat server knows who sent it
[20:00] Joes and, maybe, where
[20:01] Joes dump = dumb
[20:01] mikko i think i wrote websocket daemon ages ago using libev
[20:01] mikko it wasn't complicated
[20:03] Joes hm, someone already did it for Ruby
[20:04] Joes https://github.com/andrewvc/dripdrop
[20:04] Joes custom wire format from client
[20:04] andrewvc hey, that's me
[20:04] Joes browser that is
[20:04] Joes :-)
[20:04] Joes wonderful
[20:04] Joes there was pretty long discussion
[20:05] andrewvc oh?
[20:05] Joes but, to sum it up - any plans for pure JS 0mq client instead of custom protocol?
[20:05] Joes (or message format)
[20:05] Joes so, you can get rid of Ruby server and just relay messages to 0mq
[20:05] Joes straight
[20:05] andrewvc oh
[20:05] andrewvc well, there's a node JS project
[20:06] andrewvc and I was going to implement zmq_devices as part of ffi-rzmq as well
[20:06] andrewvc or do those options not cover it?
[20:06] Joes node JS is using native C library
[20:06] Joes I want something like DripDrop
[20:06] andrewvc oh
[20:06] andrewvc interesting
[20:06] Joes browser <-> 0mq
[20:06] Joes and simple TCP proxy
[20:06] Joes in between
[20:06] andrewvc well, dripdrop doesn't really require zeromq
[20:06] Joes which knows how to handle WebSocket handshake
[20:06] andrewvc it works well with websockets
[20:06] andrewvc and http
[20:06] andrewvc all evented
[20:07] andrewvc I'm a bit confused as to the actual question still I guess
[20:07] mikko andrewvc: but he wants to run this in browser
[20:07] mikko andrewvc: hence the pure js implementation i guess
[20:07] Joes yes
[20:07] andrewvc ohhh, well who would the browser talk to. Itself?
[20:07] Joes 0mq server, preferably.
[20:08] Joes here's another example: online real-time game.
[20:08] andrewvc oh, well, as far as I know you can't open a raw TCP conn from any browser still
[20:08] andrewvc so you're using websockets in the yes?
[20:08] Joes socketjs also works
[20:09] Joes (embeds small Flash object to proxy sockets)
[20:09] Joes gives plain sockets in JS
[20:09] andrewvc yeah, so, that's an interesting idea
[20:09] Joes I mean - sure, I can create custom protocol
[20:10] Joes write custom server software
[20:10] andrewvc what kinds of implementation were you guys thinking?
[20:10] Joes which will parse messages, etc
[20:10] Joes but I dont see a point
[20:10] andrewvc what would the api look like, in JS?
[20:11] Joes so, DripDrop already doing it - checked JS files, it is encapsulating messages into DD.Message
[20:11] andrewvc I think that's probably a good place to start, if you can throw up a gist for a simple case
[20:11] andrewvc yep
[20:11] andrewvc the JS prolly needs a little love at this point
[20:12] Joes so, imagine that there's no need to have custom wire protocol (json serialized) and JS would just talk to 0mq server using 0mq wire protocol
[20:12] Joes that's the simpliest case
[20:13] andrewvc hmmm, the 0mq wire protocol doesn't handle that much really
[20:13] andrewvc I mean, you could express multipart stuff, like socket identities for stuff like xreq/xrep
[20:13] Joes browser won't be server either
[20:13] andrewvc but I'm not sure how useful that is
[20:13] Joes sub or pub, mostly
[20:13] Joes maybe req
[20:14] andrewvc I'm off to grab some lunch, but it's an interesting idea
[20:14] andrewvc I'd love to see a gist of a proposed API
[20:14] Joes actually, from wire perspective it can be req
[20:14] Joes always
[20:14] Joes em, no.
[20:14] Joes I need to get updates from server.
[20:14] Joes anyway, I'll think about it.
[20:14] andrewvc yeah, I'd like to hear more
[20:15] Joes it won't be full-scale 0mq implementation anyway
[20:15] andrewvc If you could ping me at @andrewvc on twitter when you have something I'd be interested
[20:15] andrewvc anyway, off to lunch
[20:15] Joes k
[20:15] Joes bon appetit
[20:17] Joes Disconnected question - how do you handle security? If you don't want particular client to be connected, what you can do?
[20:17] Joes so, I don't want malicious client to DOS my message queue
[20:17] Joes can I forcibly disconnect him?
[20:17] Joes (in my application)
[20:20] mikko hmm
[20:20] mikko was searching for 0mq on twitter and most of the results are people using "0mq" instead of "omg"
[20:20] Joes :-)
[20:24] Joes mikko: any hints on how to forcibly drop connections on server side?
[20:25] Joes or 0mq not really suited for client-facing functionality?
[20:26] mikko there is really no way to forcibly drop a connection
[20:27] Joes ouch.
[20:27] mikko apart from closing the socket
[20:27] Joes on client side, I assume
[20:27] Joes ?
[20:27] mikko on the server-side but that closes all connections
[20:27] Joes oops.
[20:28] Joes means, 0mq not really suitable for client-facing stuff, as clients might misbehave
[20:28] Joes plus, if there's some sort of authentication
[20:28] Joes it's easier to disconnect client
[20:29] Joes than to ignore all his sent messages
[20:43] sustrik what's the difference? a malevolent client can reconnect immediately and sent another malformed message
[20:43] sustrik the only consequence is that the server would use much more CPU to handle the reconnecting instead of simply dropping the messages
[20:47] Joes yep
[20:47] Joes but
[20:47] Joes let's assume that it is pub/sub
[20:47] Joes with, let's say 10 subscribers
[20:48] Joes so, bad clients sends 1 message
[20:48] Joes and 10 messages total are sent to subscribers
[20:49] Joes effectively, network topology creates nice DOS environment
[20:49] Joes bad client sends*
[20:49] Joes I mean - there's no built-in security, so there's no way to filter these messages before they get into "internal" network
[20:50] Joes where workers sit
[20:56] Joes however, I think broker which will relay messages to internal network will work
[20:56] Joes and he'll do the authentication stuff too
[21:13] mikko Joes_: it sounds like a sensible approach