Re: ANN: Etiquette: a protocol construction tool
Peter Seibel <[email protected]> 17 Sep 2003 21:27:20 -0700
| Newsgroups | gmane.lisp.clump |
|---|---|
| Message-ID | <[email protected]> |
Luke Gorrie <[email protected]> writes: > A variation is to have a thread pool of a fixed maximum size, but > this is not very robust. It assumes you will never have to block on > more than N connections at a time, which breaks down with > slow/unreliable clients and with DoS attackers. Another variant (which worked quite successfully in a message processing system I worked on in Java) is to use a fixed number of threads to provide an asynchronous interface to things that are fundamentally blocking. Thus you have one thread devoted to running your state machines (or possibly N threads, where N is the number of CPU's in your machine) and then you use one thread to deal with each place you have to blocking i/o. For instance, if you don't have select(), either because it's not exposed up through Lisp or because the OS implements it badly[1], or because you're dealing with some other API that doesn't expose itself as a filehandle, such as doing queries against a database, you can instead spin up a thread that accepts requests to do i/o on a queue and does the i/o as fast as it can. When each piece of i/o finishes, the state machine that submitted the i/o request goes back into the bin to be run by the state machine execution thread. (Actually, at each place where you need to call blocking APIs you want to use as many threads as you need, hopefully a small number, to keep the i/o going at full bandwidth. At least if you're blocked on i/o, which you should be in this kind of system.) The nice thing about implementing a system this way is that all those queues show you exactly where your bottlenecks are--whichever queue backs up is the bottleneck.[2] Another nice feature of this architecture is that, there may be i/o that the state machine doesn't have to wait for. For instance, if the protocol requires data to be durably written to disk (such as a transaction log) it may be able to enqueue write requests as it goes along that it doesn't have to wait for and then finally a flush request that it does. If the i/o subsystem is cranking away writing stuff to disk as fast as it can and flushing whatever it's written anyone asks it to, any given request to flush may return immediately if another flush request already caused the data to be flushed. So, to echo Luke's point, it would be great to have a tool that lets me generate the protocol state machine for an arbitrary protocol in such a way that I can somehow plug in the actions it should do when it needs to interact with the outside world (i.e. do potentially blocking i/o) and provide some way to "suspend" the state machine and "continue" it when the i/o completes. -Peter [1] As the C10k page Luke cited <http://www.kegel.com/c10k.html> points out, select() and poll() have their own scaling problems. [2] c.f. Little's Law. -- Peter Seibel [email protected] Lisp is the red pill. -- John Fraser, comp.lang.lisp