GithubHelp home page GithubHelp logo

libchan's Introduction

libchan: like Go channels over the network

Circle CI

Libchan is an ultra-lightweight networking library which lets network services communicate in the same way that goroutines communicate using channels:

  • Simple message passing
  • Synchronization for concurrent programming
  • Nesting: channels can send channels

Libchan supports the following transports out of the box:

  • In-memory Go channel
  • Unix socket
  • Raw TCP
  • TLS
  • HTTP2/SPDY
  • Websocket

This provides great flexibility in scaling an application by breaking it down into loosely coupled concurrent services. The same application could be composed of goroutines communicating over in-memory channels; then transition to separate unix processes, each assigned to a processor core, and communicating over high-performance IPC; then to a cluster of machines communicating over authenticated TLS sessions. All along it benefits from the concurrency model which has made Go so popular.

Not all transports have the same semantics. In-memory Go channels guarantee exactly-once delivery; TCP, TLS, and the various HTTP socket families do not guarantee delivery. Messages arrive in order but may be arbitrarily delayed or lost. There are no ordering invariants across channels.

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.

Focused on not reinventing the wheel

Because remote libchan sessions are regular HTTP2 over TLS sessions, they can be used in combination with any standard proxy or authentication middleware. This means libchan, when configured properly, can be safely exposed on the public Internet. It can also be embedded in an existing rest API using an http1 and websocket fallback.

How is it different from RPC or REST?

Modern micro-services are not a great fit for classical RPC or REST protocols because they often rely heavily on events, bi-directional communication, stream multiplexing, and some form of data synchronization. Sometimes these services have a component which requires raw socket access, either for performance (file transfer, event firehose, database access) or simply because they have their own protocol (dns, smtp, sql, ssh, zeromq, etc). These components typically need a separate set of tools because they are outside the scope of the REST and RPC tools. If there is also a websocket or ServerEvents transport, those require yet another layer of tools.

Instead of a clunky patchwork of tools, libchan implements in a single minimalistic library all the primitives needed by modern micro-services:

  • Request/response with arbitrary structured data

  • Asynchronous events flowing in real-time in both directions

  • Requests and responses can flow in any direction, and can be arbitrarily nested, for example to implement a self-registering worker model

  • Any message serialization format can be plugged in: json, msgpack, xml, protobuf.

  • Raw file descriptors can be "attached" to any message, and passed under the hood using the best method available to each transport. The Go channel transport just passes os.File pointers around. The unix socket transport uses fd passing which makes it suitable for high-performance IPC. The tcp transport uses dedicated http2 streams. And as a bonus extension, a built-in tcp gateway can be used to proxy raw network sockets without extra overhead. That means libchan services can be used as smart gateways to a sql database, ssh or file transfer service, with unified auth, discovery and tooling and without performance penalty.

Example usage

Here's an example implementing basic RPC-style request/response. We gloss over error handling to tersely demonstrate the core concepts.

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)

On the server:

var ch libchan.Receiver

// Wait for messages in a loop
// Set the return channel flag to indicate that 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 extremely useful response")});
}

Creators

Solomon Hykes

Additional Implementations

Java

Javascript / Node.js

Copyright and license

Code and documentation copyright 2013-2014 Docker, inc. Code released under the Apache 2.0 license. Docs released under Creative commons.

libchan's People

Contributors

aanand avatar aphyr avatar bfirsh avatar caindy avatar dmcgowan avatar dmp42 avatar drewwells avatar emosbaugh avatar fkautz avatar liubin avatar lk4d4 avatar mcollina avatar thajeztah avatar tiborvass avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libchan's Issues

Define channel semantics

Following on from #22 and #26: I think we need to define the channel semantics. Saying "the ordering depends on the underlying transport you use" isn't helpful for developers who want to build software that is independent of the underlying transport.

For transports that don't guarantee ordering, perhaps we should enforce ordering at the libchan level? Perhaps we should not use transports that have undefined ordering?

Some other things that would be useful to know when developing on top of libchan, regardless of transport:

  • Are messages dropped or repeated?
  • How reliably are messages delivered? (i.e. given a 100%, 99.99%, 99.9% etc reliable network, what is the reliability of libchan?)
  • Are there buffers that can overflow?

@aphyr @shykes @dmcgowan @aanand – thoughts?

(I know little about protocol design, so all credit to @andrewgodwin for thoughts on this.)

Proposal: Use protocol defined in PROTOCOL.md

Moving protocol related discussion from #38 to here. This would follow the model Docker is adopting for large design changes, discussion is on the protocol and the PR is for code review and discussion related to whether it implements the proposal as defined.

Please read the PROTOCOL.md before commenting on this issue.

On going discussions

  • Nested channels ids are not defined, should stream ids, reference ids, or something else be used?
  • msgpack custom formats
  • Dealing with net.Conns and file descriptors
  • Channel semantics similarity to go channels (do we need to provide back pressure semantics in the protocol)

undefined: spdy.NewClientTransport

I was using v0.1.0 version and my program ran OK.

transport, err := spdy.NewClientTransport(client)

Now, using origin master, I get this error:

undefined: spdy.NewClientTransport

Which method I need to use instead ?

Websocket transport

Is the websocket transport missing or am I missing something obvious about how to hook in one of the other websocket packages to just use the conn transport?

How to migrate code from v.0.1.0 version ?

I'm trying to do the build of https://github.com/bfosberry/banano/blob/master/server/main.go code and I am getting the following errors:

  • undefined: spdy.NewTransportListener
  • undefined: spdy.NoAuthenticator

The code is:

listener, err := net.Listen("tcp", fmt.Sprintf(":%s", port))
if err != nil {
    log.Fatal(err)
}

tl, err := spdy.NewTransportListener(listener, spdy.NoAuthenticator)
if err != nil {
    log.Fatal(err)
}

This code run with v.0.1.0 of libchain

I haven't found documentation of changes to be made in code when we want to migrate to the current version of libchain.

PROTOCOL.md vs implementation vs WIP

I'm having an hard time to figure out how to implement the libchan over SPDY in nodejs for jschan mainly because there are at least 3 different sources of information: the code, the PROTOCOL file and #38.

What is not clear is exactly how msgpack and the 'libchan-ref' header works.
On master there is no msgpack, just urlenconding strings. In the PROTOCOL spec is stated that all messages should be in msgpack format, and #38 implements that.

On master each message gets its own spdy stream, plus a spdy stream for response: master uses the 'parent' relationship of SPDY streams to create all those streams (e.g. the response of a message travels over a SPDY stream that has the current one as parent). This is different to what is specified in PROTOCOL.md, as the 'libchan-ref' header should play some role: however nesting is not documented, and there is no way to 'reply' to a message as in PROTOCOL.md.

In #38, which from what I understand implements PROTOCOL.md, channels are unidirectional but are nestable thanks to an extension of msgpack. In practice, this means that the transport leverage the capabilities in msgpack v5 that allows extension points. This means an extendable msgpack library is needed (which we don't have on node, but that's not the point of the discussion).

Where is the project going? What are the plans? What is the spec of libchan protocol? Will it be all-msgpack for messages (but the README and the purpose of the protocol says otherwise)?
As an environment is spawning up around libchan and microservices, I suggest we do drafts like RFC, e.g. we can know library X implements libchan-1, and iterate over that.

Anyway, thanks for all the good work, there is enough stuff here to blow up my head :).

cc @Vertice @peger.

Suggested order of implementation for the libchan protocol

I'm in the process of researching and designing a node.js/javascript implementation of libchan (i'm calling it Graft).

I'm planning to use node streams as the base of the abstraction, and i'm aiming for a api similar in usage to gulp.

What I'm wondering is, what you would consider the simplest proof of concept to bootstrap this implementation, so that I can iterate on the various components from there.

So I guess, what does 'hello world' look like for libchan?

Support CBOR

CBOR should be an option to use for serialization along with msgpack.

Go chan encode/decode

Add support for encoding and decoding Go channels using the channel extended type with the new msgpack library.

test http2/listener_test.go not work

hi

i trying run the test for http2 and they block forever.
look, i do in directory libchan/http2:

 $ go test # Block forever!!!
 $ go test listener_test.go stream.go spdy.go listener.go # Block forever!!
 $ go test stream_test.go stream.go spdy.go listener.go # Pass OK

Large binary in repository

There is 6Mb binary examples/beamsh/beamsh in repository. It is not very cool, and it is became less cooler with every commit.
May be we should remove it through filter-branch or at least just git rm?
ping @shykes

Anonymous embedded structs aren't supported

It seems when using anonymous embedded structs, field values are not transmitted. For example, given the following types:

type B struct {
    I int
}

type A struct {
    B
    J int
}

If A is sent on a channel, values for the anonymously embedded B struct are not sent.

WebRTC data channel support

Over at jschan we are busy discussing allowing peer-to-peer connections via webRTC.
GraftJS/jschan#27

We're currently planning to do this the same way we did the websocket support (#56), with a custom transport, because re-implementing SPDY is just too big a task for us right now.

Use Go channels with libchan.Pipe

Currrently libchan.Pipe does not use Go channels to communicate. Pipe should be updated to use Go channels and add options for buffering the pipe.

Browser support

I'm starting to work on a node.js / javascript implementation using streams as the base abstraction (less elegant than goroutines, but I can see them working).

Other than the websocket support missing, as per #5, are there any specific issues you can see with the browser environment?

Have you considered browserchannel as another option for a fallback?

Add a transport that uses UDP or DTLS when multiplexing streams

As I wasn't at the DockerCon I haven't heard how libchan is going to be used, but if multiple streams on top of these transports is a goal I suggest adding a datagram-based transport as well.

The reason is because of head-of-line blocking.

Obviously, HTTP/2 or SPDY is already better than HTTP/1.x or something like WebSocket at dealing with multiple streams.

But at the TCP level you can still get head-of-line blocking because if packets are lost they can not be reordered.

It's similar to the TCP tunneling in TCP problem:
http://sites.inka.de/~W1011/devel/tcp-tcp.html

It is also (one of ?) the reasons https://en.wikipedia.org/wiki/QUIC is being developed.

An other example WebRTC which uses DTLS ('SSL'/TLS over UDP) at the lowerlevel and SCTP as the datachannel protocol for the multiplexing.

Obviously I wouldn't suggest implementing all of WebRTC, it's a pretty big specification.

But they are just examples of current protocols that already do this.

MsgPack improvements

The currently Go msgpack library does not allow for encoding based on interfaces. This limits the ability of the Send operation to dynamically create underlying streams for non-bytestream ReadWriteCloser (any ReadWriteCloser not created through Sender.CreateByteStream). As a workaround, libchan.ByteStreamWrapper was added to allow the encoder to recognize any ReadWriteCloser type and transparently copy to the transport's byte stream. Ideally this extra wrapping should not need to exist and the encoder could take care of it. It is the encoders responsibility as owning the send type reflection process and to avoid having to do extra type reflection before encoding.

handling many request types

Is there a recommended pattern for implementing a server that can handle a multitude of different requests? The question I have is how to represent the request. For example, suppose I have the following requests:

type EchoRequest struct {
  Cmd: string // "echo"
  Text: string
  Ret: libchan.Sender
}
type AddRequest struct {
  Cmd: string // "add"
  A, B: int
  Ret: libchan.Sender
}

What would I Receive into on the server side without going through map[interface{}]interface{} hell? The cleanest I can come up with is to give each request type its own (well-typed) channel and to make the root channel just send a map of request-type=>channel. If these were Go channels I would receive into an interface{}, look up the command, and then coerce the interface{} to EchoRequest or AddRequest. But that doesn't work with libchan as far as I can see. I'm probably missing something obvious...

Proposal: Use context throughout libchan

In libchan we need a way to seamlessly carry trace, debugging, cancellation and other data across boundaries - whether that be process, goroutine or RPC.

The code.google.com/p/go.net/context package provides wiring to do this.
References http://blog.golang.org/context

If libchan can be seamlessly used over unix socket, go channels, etc a standardized mechanism for propagating scoped values, cancelation signals, and deadlines, etc across the boundaries would be awesome.

I'm happy to do the work but not sure if this is something people feel a need for at the moment

@shykes @dmcgowan ?

http2 fd too many files

hi,

i'm implementing a server with libchan and http2, they work well, but they fail after some minutes with the error fd too many files open,when debug see the descriptor for libchan.Message.Fd create by the http2.StreamReceiver.Receive method used on the server, they grow and grow..
look, simple test,
ulimit -n 80
then running de server the Fd grow:

  • adialer-handler2014/07/09 00:01:14 msg.Fd &{%!s(*os.file=&{9 0})}
  • adialer-handler2014/07/09 00:01:15 msg.Fd &{%!s(*os.file=&{13 0})}
  • adialer-handler2014/07/09 00:01:15 msg.Fd &{%!s(*os.file=&{15 0})}
  • adialer-handler2014/07/09 00:01:17 msg.Fd &{%!s(*os.file=&{23 0})}
  • adialer-handler2014/07/09 00:01:29 msg.Fd &{%!s(*os.file=&{29 0})}
  • ...
  • adialer-handler2014/07/09 00:01:34 msg.Fd &{%!s(*os.file=&{72 0})}

and boom!, i'm find a solution and it's closing the descriptor (msg.Fd.Close()) when then server finish the response,

there a better way?

thanks

Clarify channel semantics

The readme says:

network services communicate in the same way that goroutines communicate using channels:

And the Golang spec, regarding asynchronous channels, says:

elements are received in the order they are sent

How does libchan enforce the ordering/delivery properties of golang channels when the underlying transport is disrupted--e.g., when re-establishing a TCP link that dropped, how does the channel state machine negotiate redelivery of incomplete in-flight messages? Do libchan channels yield at-least-once delivery? At-most-once? Exactly once? Are there any ordering invariants, or can messages be arbitrarily reordered? If ordering is preserved, what are the space costs on both sides of the network?

Add channel select capability

Most of the power of Go channels come from flexibility provided by select clauses and the analogous reflect package API. An efficient select functionality in libchan would bring it further into parity with Go channels and could support some powerful use cases:

  1. A select server where different request types are sent over different channels. The server blocks on all channels until one can proceed and it handles the specific request type (See #73 (comment) for a more detail description).
  2. Provide synchronization of distributed request control flow (lots of words). Imagine propagating a timeout through a pipeline of processes, using an operation channel and a cancellation channel.

An implementation could be as simple as providing a select call that spawns multiple goroutines for each sender and receiver passed in and dispatches a callback based on it. More complex implementations would add methods to Sender and Receiver that indicate whether the operation can proceed. It may make sense to even bridge it with process-local Go channels. The API could take hints from the reflect package channel API.

Prosposal: enhanced logging and debugging

Libchan can be difficult to debug network interactions through traditional packet sniffing. Because of the lack of tooling which currently exists around debugging spdy, libchan should have a debug mechanism which is spdy stream and channel aware. Debug level logging as well as efficient info level logging will be needed by applications using libchan.

Example usage would be for docker-archive/docker-registry#635

it's *not* 'Like Go channels over the network'

The tag line on github for this project states that it is "Like Go channels over the network".

In Go, channels have two purposes: communication and synchronisation. The above phrase creates the impression that libchan addresses both aspects, whereas in reality it handles only the former. The phrase is therefore deeply misleading and the source of much confusion. To make matters worse, the README even explicitly states that libchan provides "Synchronization for concurrent programming", when this evidently isn't the case. I have spoken to a few folks who had looked at libchan and nearly all of them mistakenly though it dealt with synchronisation.

The phrase need changing.

Add example using websockets

Add an example which demonstrates libchan being used over a websocket. Since the spdy protocol is separated from the transport, this should be possible to implement using the existing code.

Relevant to #5

Dual transport

The default SpdyTransport uses spdy streams for messages as well as byte streams. A Dual transport would allow for using spdy streams for messages, but a different network type for byte streams. This would most likely involve adding a transport type which is created with a network connection for channels over spdy, but contains a listener/dialer for creation of byte streams. This would allow calls to CreateByteStream on the transport's sender to return real network connections. Any new protocol should be clearly defined and referenced by changes to the Protocol document to ensure different implementation of libchan are in agreement of the transport protocol.

Proposal: Channel reference identifiers

Background

Currently the libchan protocol does not define the mechanism for connecting both ends of a channel. This leaves it up the implementer to either use the underlying spdy stream id or something custom. Using the spdy stream id should not be used since the identifier is part of a lower and separate layer and depending on the spdy implementation may not be accessible. In order for clients to be compatible the protocol should have channels define an identifier in the same way as byte streams and communicate that identifier through the spdy headers. The channel header can use the same reference id space as byte streams and be distinguished by the existance of a parent identifier (which byte streams do no have since they do not have hiearchy).

Proposal

I am proposing adding a 'libchan-parent-ref' spdy header to be used when creating channels and requiring both channels and byte streams to make use of the existing 'libchan-ref' header. The decision on whether a new stream is a channel will then be made by the existance of 'libchan-parent-ref' rather the absence of 'libchan-ref'. The msgpack object will then communicate the reference identifer rather than anything custom or the spdy stream id.

Documentation

Is there any documentation for this? Am I missing something?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.