HN user

slact

108 karma
Posts3
Comments22
View on HN

besides directive prefix

The old setting is still recognized.

Subscribers" section of "Push Module" should include websocket

Nope, push module didn't do websocket. You may be thinking of the Push _Stream_ module, which is an independent push module fork.

global message id / global channel Yeah, I don't have global ids. every message is bound to the channel it was published to. But I do understand that for your use case, (user + arbitrary list of groups), you'd need a good deal more than 4 channel multiplexing. It's a pretty strong use case and I'll see what I can do in the next month.

Of course, I can be incentivized to work faster with a generous donation :)

Regarding web sockets [...]

All the cool kids were talking about it, so I thought I might as well support them, too.

No, ack/nack would need to be implemented in the client or the application.

However, messages do not disappear from the queue when received. All subscriber requests are idempotent, and can be repeated so long as the message queue is storing the message (which is a configurable parameter). So if a subscriber failed before processing it, it's free to request the same message again.

Nice project, and a curious featureset overlap, too...

We have a concept of "reliable pub sub" [...] Does the redis store you have do something similar (I can not see backing lists in the redis store implementation in store.c)

Dig a little deeper... https://github.com/slact/nchan/blob/master/src/store/redis/s... I used lua scripts for all the fancy redis logic, that's where you'll find the backing list accesses. Messages are stored as hashes, referenced by id in lists, along with some other channel metadata. So a longpoll or EventSource client knows its last message id, and can request the next avaliable message as long as said message has not yet expired. Websocket clients don't have this information, and I'm not yet sure how to relay it with each message while remaining content-agnostic. Basically, regardless of the protocol, you can send a If-Modified-Since + If-None-Match or Last-Event-ID headers and it will resume from that position in the message queue for the given channel.

I see you can do auth upfront but can per-message security seems not doable

Per-message access will definitely not be implemented. You could, however, do this client-side by, say, encrypting the messages and sharing keys with authorized subscribers. That's kind of roundabout though.

We don't bother with per-channel URLS [...], we often subscribe to 10 channels on a request, the multiplexing seems a bit limited

The main use-case I had in mind for multiplexing is that of a single channel per user, and some shared broadcast channel. It's currently limited to 4 max because I wanted to get this code out the door. Unlimited multiplexing will be supported in the future, and you could trivially rebuild the module to support up to 16 right now (At the cost of some memory per message per subscriber per channel overhead).

When we subscribe to a channel due to the "reliable" nature of the store we are able to tell the server what the last id is we subscribed to and catch up from there

Yep, Nchan does that too. (except for Websocket, and hopefully I'll find a workaround)

How does that work for feature parity?

Well, if it ain't broke, as they say...

here's a page on the differences between Nchan and the Push Module: https://nchan.slact.net/upgrade . One important thing I forgot to add is that the Push Module suffered from memory fragmentation under high load, and with a fixed-size shared-memory chunk that could mean running out of usable shared memory for a long-running nginx process. If you're not experiencing that, and you don't need to scale up, or the new features don't appeal to you, don't upgrade -- certainly not yet.

Maybe in a month or two when nchan makes its way into the nginx-extras debian package (replacing the push module), then consider upgrading.

That's correct, that feature is for authentication only. I may add a feature to replace the message with the back end response.

By multiplexing I mean that a single websocket (or any other) subscriber can subscribe to multiple channels.

Yes. All messages are buffered for a configurable length of time. Longpoll and EventSource clients receive the last message id with each message, and if interrupted can be resumed from there provided the message has not timed out. I don't yet have a way of transferring the last-received message id for websocket clients, but if it is known it can be set during the ws handshake.

Yep, I'll be adding an example js client, but I don't intend on standardizing this. Mostly because I'm also a js guy and I like mootools, and I don't want to start a best-js-framework flamewar with an official client. But example code will be up for sure.

the execution of middlewares when a user publishes a message (to filter them or something else)

You can do that with nchan: https://nchan.slact.net/details#authenticate-with-nchan_auth...

Right now, I'm using two websockets, one to Nginx PushStream only to receive messages and another to the NodeJS server to publish messages.

You can also multiplex several websockets into one for the client.

I can't offer you a standalone server, but I can offer some pretty fancy features : )

Nchan is about 12K lines of C, I'd say 2-5K of that is dealing with Nginx guts. To get rid of Nginx entirely, you'd need to add an event loop, forking and multiprocess management, config parsing and reloading, and shared memory allocation code. That's not a simple task, but it's certainly possible. The reason I built this on top of Nginx is precisely because I didn't want to handle those other things. Besides, nginx these days is a hulking scalable monster. What's the bother?

If you really don't want an nginx dependency, I'd say you're better off rolling your own pubsub server in Node.

I'm not familiar with MQTT, I've just glanced over the spec right now.

Nchan is basically a message broker with channels, optimized for message broadcast.

MQTT is a TCP-level protocol, whereas all the currently implemented subscriber clients for Nchan are HTTP-level (Longpoll, EventSource and Websocket, which begins with an HTTP request). MQTT subscribers and publishers could be implemented in nchan, but I haven't yet written any raw-TCP connection negotiation code, so I don't know how hard it would be. Aside from that, the subscriber code is very modular and adding another protocol like MQTT would be straightforward.

Yes, this is a different project, although they are related. Push Stream is a fork of my Nginx HTTP Push Module, so they both descend from the same original codebase. Push Stream uses a blocking concurrency model, whereas Nhan is completely non-blocking. In theory, this means Nchan should scale better. In practice, I haven't benchmarked it heavily enough yet to see a divergence.

Besides that, nchan and Push Stream offer different feature sets. For example, Nchan has horizontal scaling and persistence through redis, whereas push stream has customizable message transforms. There are other differences as well, but that would take a whole article to elaborate. I should probably write it soon.

I consider those two and socket.io my main competition. Nchan is built to scale, but of course you'd need some numbers to back that up. I plan on doing benchmarks once I iron out the documentation, although I realize it would be a great selling point to have the numbers ready right away.

Well, it would be very easy to make a realtime 4chan-like thing with Nchan, but it's far from the only use case. It's a general-purpose server and pubsub proxy.

The name is a play on nginx and channels. I got tired of saying "nginx http push module" all the time and renamed it.

This is a huge refactoring of an old project of mine -- the Nginx HTTP Push Module. I'm wondering if anyone here has used it.

Most importantly, I want feedback on the documentation. Did I overcomplicate things? Does it need more examples? Does it need more live code? Is it too long? Too short? Etc.

Everything is pretty much as efficient as vanilla nginx. There are some O(log(n)) lookups, but i've not noticed CPU usage hit anything even remotely suspicious (fixed bugs aside).

Memory usage for long-polling requests is regular nginx usage ("2.5MB for 10K idle connections"), + around a hundred bytes or so per ling-polling requests. A channel eats up about a dozen bytes.

The only limitation that one might run into is the maximum memory allotted for shared messages -- but that's a configurable value.