Libchan: Like Go channels over the network
github.com
github.com
I do understand why Docker would create this for their own use, because having a dependency on messaging libraries (where people tend to have varying opinions) wouldn't be the greatest for a wildly popular open source project. I'm just trying to figure out why others would want to use this.
I'm all for more tools in this space, though I like to make sure a tool exists for reasons other than "not invented here" before I learn yet another messaging library.
Libchan is the spiritual child of zerorpc, so it is definitely informed by our experience using zeromq. The main experience was: it's awesome but does too much, too low in the stack, and it's too much of a black box to remove the parts we don't need.
Also, the inability to safely expose it on the public internet was a big problem. I know this has been addressed since then, but we don't want to use a separate protocol stack for that: we want to use the existing HTTP (soon HTTP2) and TLS middleware infrastructure. That's why libchan uses spdy/tls as its main network transport.
Deus, why? Why on Earth would parts of your critical internal infrastructure be exposed to the public Internet?!
Just my 2c based on our own production experience.
Just as forecast by many on HN, HTTP is becoming the network layer.
You must be referring to HTTP2, which is indeed HTTP1+SPDY+TLS in one single protocol. Actually, if SPDY catches on and is used for other uses (I already know muxado [0] that uses a SPDY-based protocol to multiplex requests/responses between client and servers) so that it lives by itself, it will be funny to see if HTTP2 really embeds it (and therefore duplicating the work).
I think I'd like to move muxado in a direction where it provides the common interface to the various stream multiplexers. That way you could code against a common interface and swap out http2/spdy/muxado/yamux as the implementation to suit your performance needs.
I'd also like to see libchan use this common interface as a layer built on top of this primitive.
Thanks!
Here are the slides for the presentation: http://www.slideshare.net/shykes/docker-the-road-ahead
Note: the illustrator who helped me with this is @laurelcomics on Twitter, she is awesome and available for contracting :)
Just curious.
As the other responder pointed out, DockerCon is currently in progress, so most of the projects that have hit HN were just announced publicly as part of that. On a related note, I recommend folks keep an eye out for the videos of the talks. The Red Hat talk on geard/atomic and shykes's talk on the future of Docker (and these other projects) were especially great.
Its a little annoying when they spam it but meh, they work on stuff we need and its open source - could be worse.
Has that changed?
Now your application always checks for IO errors, and the underlying "plumbing" is exposed and available for the developer to tweak at will: timeouts, caching, failover, fan-in, fan-out, etc. become programmable components just like the rest of your app.
TLDR: this is not born-again RPC. It's the anti-RPC.
Now your application always checks for IO errors, and the underlying "plumbing" is exposed and available for the developer to tweak at will: timeouts, caching, failover, fan-in, fan-out, etc
The big problem is that the bandwidth and latency numbers are vastly different over an actual network vs between processes or OS threads on a single machine vs between green threads within a process.
The problem is that sometimes you require high performance, to a degree that is not possible across an actual network link. And if your coding style doesn't distinguish between an actual network link and an imaginary in-process link (or worse, deliberately makes them indistinguishable and silently interchangeable), sooner or later someone will refactor it or change the config file or something and your microsecond-scale latency that you were assuming and relying on has suddenly become multiple-millisecond latency and everything grinds to a halt.
But most things are not hard. Hard things can be dealt with if and when they come up through documentation and training. Dealing with them by making easy things equally hard is silly.
Try on this analogy: Moving in deep blizzard conditions is hard. Using vehicles with tracks and skids would make that easier, but that's obviously not a sensible and useful vehicle because it would suck for driving on dry highways.
But most things are not hard. Hard things can be dealt with if and when they come up through documentation and training. Dealing with them by making easy things equally hard is silly.
You could just as easily apply this reasoning to goto statements. Also to memory management. I'm not saying you don't have a point here -- I'm on board with "the right tool for the job" -- but your analysis could be a bit more nuanced.
That you shouldn't restrict the use of certain tools/constructs/features in order to make areas like concurrency easier. Apparently you misunderstood my analogy. For one thing, it is an analogy, and not a statement you would use goto and manual memory management.
would generally counsel against goto and manual memory management, which are harder tools for solving harder problems,
That is a matter of scale. At small scales, "just using a goto" seems easier. It's only at larger scales that it becomes untenable spaghetti, so is harder. Herein is another analogy which can be related to concurrency and parallelism.
In-thread control transfers vs in-system IPC vs network links all have very different performance (bandwidth/latency) profiles.
The language should not encourage people to conflate them. They behave differently enough that making them indistinguishable is not a sane abstraction.
This does not mean that they need to have wildly different interfaces. Just like 'int' and 'double' don't have wildly different interfaces, but your code still needs to specify which it's using.
When performance matters, specify/document the performance characteristics of your modules and their deployment proximity requirements. This is hardly unusual, I do it all the time.
If you start looking into the ways that parallelism can become highly inefficient on the current multicore architectures, you'll find that there is an inter-core/socket memory hierarchy/communications barrier which isn't well established in the mainstream consciousness of programmers. It turns out, that there is often far less of a difference between an actual network link and an imaginary in-process link than a naive programmer might believe there is, and the conditions which could cause this can result from a subtle interplay between multiple hardware and software mechanisms.
Here's one - http://en.wikipedia.org/wiki/False_sharing
(or worse, deliberately makes them indistinguishable and silently interchangeable)
Erlang/OTP actually makes this tradeoff, much to its advantage. In fact, the multicore pathologies I refer to above make the tradeoff more attractive.
sooner or later someone will refactor it or change the config file or something and your microsecond-scale latency that you were assuming and relying on has suddenly become multiple-millisecond latency and everything grinds to a halt.
What you describe is either a poorly managed shop or a poorly conceived programming environment. Either, the behavior of such a system should be one of the 7 or so things you must know to program such a system, or the environment should make it glaringly awkward to rely on something as a synchronous call.
It's good you mentioned Erlang. What you're describing >is< Erlang/OTP. The language is structured such that you're always somewhat paying a price for fault tolerant, concurrency safe, and parallelizable distribution. It turns out that this makes for a nifty functional programming language and, surprise surprise, the result is great for fault tolerant, concurrency safe, and parallelizable distribution.
On the client:
var ch libchan.Sender
// Send a message, indicate that we want a return channel to be automatically created
ret1, err := ch.Send(&libchan.Message{Data: []byte("request 1!"), Ret: libchan.RetPipe})
// Send another message on the same channel
ret2, err := ch.Send(&libchan.Message{Data: []byte("request 2!"), Ret: libchan.RetPipe})
// Wait for an answer from the first request. Set flags to zero
// to indicate we don't want a nested return channel
msg, err := ret1.Receive(0)
fmt.Printf("Received answer: %s\n", msg.Data)
On the server: var ch libchan.Receiver
// Wait for messages in a loop
// Set the return channel flag,
// to indicate we want to receive nested channels (if any).
// Note: we don't send a nested return channel, but we could.
for {
msg, err := ch.Receive(libchan.Ret)
msg.Ret.Send(&libchan.Message{Data: []byte("this is an utterly useless response")})
}um, sockets anyone?
It's possible to pass in file descriptors on unix sockets but it only works locally.
I'm not trying to diminish the importance of an easy to use library that abstracts away the socket-level code with a good protocol. I'm just saying that sending a socket over a socket isn't a good way to pitch it.
EDIT: I see you mentioned the Unix socket transport passes around file descriptors. How about the inter-host transports? Obviously two browsers can't directly connect to each other (or could they with WebRTC...?) what about, say, TCP between hosts on the same local network?
That being said, it’s a neat project that I’m tempted to port the ideas from.
I've been meaning to spend an afternoon porting it to Go...
Or is this meant to supplant all the existing protocols that we already have.
Would erlang have a use for this?
> An explicit goal of libchan is simplicity of implementation and clarity of spec. Porting it to any language should be as effortless as humanly possible.
Where is the spec?