11 ms·
Ditching Go for Node.js
- inglor 9y agoI've dabbled a lot with Go. I've found it _very_ effective to a wide variety of problems I don't really have most of the time. If I wanted to implement RAFT I would probably pick Go. If I want a simple REST/GraphSQL server then Node.js is so much easier. `async/await` is nicer for me than goroutines and I find my code easier to reason about. Full disclosure: I'm a Node.js core team member and a Go fan. Part of my reasoning might be how much nicer Node.js got these last couple of years.
- dullgiulio 9y agoChannels are basically the primitive with which you can implement futures, thread-safe queues, etc. Can you elaborate on why you think async/await is easier (for you) to reason about than a goroutine and a channel?
- inglor 9y agoYes, An async function is explicitly async (in its definition). The syntax is obvious which is why JavaScript chose to go that route (rather than adopt channels at a language level for example). Plus, 95% of the time I care about the singular return value of a function - I just want something that's a function but async - and not a green thread that's using a channel to send information back. Both conceptually and in the code it's a lot simpler.
- anonymoushn 9y agoMost of the time you write `let x = await foo()` in js should become `x, err := foo() if err != nil then return nil, err end` in go, not anything to do with channels
- always_good 9y agoWhat about `const [a, b] = await Promise.all([thing2(), thing2()])`. Or const results = await Promise.map(xs, x => process(x), { concurrency: 2 }) Or having 2 concurrent loops processing some data? All things that require more boilerplate in Go while trivial in Node.
- Vendan 9y agohttp://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ http://journal.stuffwithstuff.com/2015/02/01/what-color-is-y...
- Cthulhu_ 9y agoI think it's a decision between levels of abstraction, with Node being a level higher than Go in that area. Probably easier to use it to link services together (glue apps), because with Go you'll probably have to define types and such a lot.
- Thaxll 9y agoOP is complaining about Goroutine stack size at 4kb per connection, his test shows that Node8 is taking up to 150MB of memory with 5k users, 4kb*5k = 20MB for Go memory, I don't understand how Nodejs can take less memory than Go, and without real numbers / test I'm pretty sure he's doing something wrong somewhere. From my experience on some large prod deployment, Nodejs app takes much more memory and CPU vs Go app for doing similar work.
- bryanlarsen 9y agoIt's 2 per connection, so that's 40MB of RAM. The OP also said that was minor compared to the channel overhead -- it seems the number of channels was exponential to the number of users in a room.
- anonymoushn 9y agoSeems like it should be linear??
- iends 9y agoHopefully it's linear, or it's implemented wrong.
- bryanlarsen 9y agoHopefully, but all he said was "fanout" which could be either. He knows it's implemented wrong, that's the point of the article: that Go doesn't make it easy for him to implement it right. The only question is the degree of wrongness. :)
- iends 9y agoIt being implemented incorrectly is not a property of the Go language, though.
- 9y ago
- verroq 9y agoWhy not use mutexes and callbacks instead of channels for pubsub?
- iends 9y agoThis is not considered idiomatic Go and would be a premature optimization unless you ran a profiler and determined that channels are actually your bottleneck. It sounds like this has not been done.
- calcifer 9y agoNot only that, but channels are internally implemented with mutexes anyway, so a naive mutexes+callbacks implementation wouldn't be any faster.
- iends 9y agoChannels have a performance overhead over handling the locking yourself. Maybe look at stuff from Tyler Treat to learn more (maybe his most recent talk? https://www.youtube.com/watch?v=DJ4d_PZ6Gns https://www.youtube.com/watch?v=DJ4d_PZ6Gns) but there are some other discussions (mostly with earlier Go versions) but maybe something changed?
- qaq 9y agoThat's the funny thing modern Node is surprisingly usable and if using TS has very advanced tooling.
- iends 9y agoIt's incredibly easy to throw stuff together in Node.js, it's much harder to maintain over time. TS helps with this but you still run into really hard to diagnose memory leaks (mostly in 3rd party packages written in C++, but sometime in Node core itself). The tooling for these type of issues is really poor in my experience.
- fermuch 9y agoMy main concern with node is how fast everything moves. Try to maintain a project that started with es5, then migrated to es6 (but some legacy code is still es5), then added some es2017 and now is adding slowly typescript to the monster, and all of this in just 3 years! Things become a mess in no time, tooling changes constantly, and maintaining legacy code while developing new parts with current best practices helps you build a Frankenstein in no time. (and don't even mention about coffee, or it'll make me start ranting about the move from coffee to es6 and now TS!)
- chmln 9y agoI don't get this. No one forces you to upgrade your perfectly functional es5 code to es2015, es2017, or typescript. Yes, node moves fast and new features are introduced, but everything is largely backwards-compatible. You don't have to incorporate every shiny new feature, framework, or tooling. If you do so by choice, this rant is rendered meaningless.
- egeozcan 9y ago> (...) developing new parts with current best practices (...) I sincerely suggest that you stop doing this. If JS folks had 10% of the "don't fix what isn't broken" philosophy of the Python developers who were presented with v3 as the future, we wouldn't have any of those "js fatigue" posts.
- iends 9y agoSome random thoughts as somebody who codes a lot of Node.js at work and a lot Go in my freetime (and sometimes at work): Did you try using pprof and the other tooling go provides to better understand your performance limitations? Tooling is a lot better in go ecosystem for understanding CPU and memory consumption, so if/when you run into into issues with Node you're going to be in a world of pain (this is basically a large portion of my job in a large node.js code base in the $day_job). You'll basically have to resort to using lldb and heapdumps in the Node world. I'm surprised the number of concurrent clients you go with Go was so small. I know lots of people using Go and Gorilla websockets that exceed 1.5k clients with similar memory constraints. To be perfectly honest, it sounds like you're doing something wrong. As of Go 1.4, the default stack size per goroutine was 2KB and not 4KB. If you add in TypeScript, you'll have a better type system than Go provides in the Node ecosystem. That's a huge point for using Node.js, especially if there are multiple contributors and the code base lasts for many years.
- ryanplant-au 9y agoThere are quite a few things I like about Go, but it's just so hard to leave the safety and reliability of TypeScript. Go's limited type system is its fatal handicap IMO.
- blowski 9y agoIt’s interesting how divisive Go’s type system is. For some people it’s the main reason they use it, for others it’s a fatal handicap. FWIW I predominantly use PHP, so I have no dog in this fight.
- iends 9y agoI think a lot of the differences between how people view Go is based on where they are previously coming from. The C/C++ folks are used to worse or more complex type systems so they view Go as fresh air. The “better python” people love the easy to use type system and the performance improvements. But those “better python” people are used to things like package managers which the C/C++ have done just fine without. The Java people don’t understand why they should give up an expressive type system for faster compile times. (Might see this from people who love C++ templates too.) At least that’s some generalizations I’ve observed, YMMV.
- nevi-me 9y agoThis is a very interesting direction to take. I've built a lot of my personal stuff on JS, and TBH, the one thing I really wish I had right now was a statically typed codebase. I spend a lot of time thinking about why I'm creating a certain data model, whether I might need to change something in future, etc. About 60% of my productive time is spent thinking about how and why, so I hardly refactor. However, when the need arises, I wish I had something like Kotlin. For the past few months I've been writing new JS code in TS, adding types here and there, I haven't tried out Kotlin on JS, but I'm hoping to go there. I'm learning Go, but for other reasons. I find JS to be performant, my oldest active codebase has been around since the v0.8 days.
- egeozcan 9y agoI've refactored (or should I say, annotated) a >5K LOC node.js app to Typescript. It's an incredibly powerful system. Structural typing gives you 90% of the flexibility of dynamic typing with 90% of the security of classical static typing (of course this is just a feeling - it's not like I'm presenting a scientific result here). I had more than 90% test coverage, with meaningful tests so I didn't really find too many bugs but I could delete a lot of tests and run-time checks which were making sure stupid input don't cause unexpected behavior. When I check my commits & logs, LOC/hour didn't change significantly but bugs/month reduced to nearly half if my SQL skills aren't failing me.
- KirinDave 9y agoYou have two excellent options: TypeScript and PureScript. Even better, they play fairly well together. You can work in Purescript but still provide well typed integration points for contributors that can't. And uh, no one here is talking about how fantastically slow Go channels are. But I just saw the code last night, and it's not hard for 20 year old techniques to beat out a "futex for literally every message send" technique.
- nevi-me 9y agoI'm already using TypeScript, but you sometimes have to bend over backwards to get it to work nicely with a huge JS codebase (which I have). Talking about channels, I haven't gotten there with my Go learning. Few things beat websockets + a nice wrapper (with simplicity). For example, I'm doing realtime transit, and as part of it I'm sending out hundreds of vehicle positions per 5-7 seconds. On the back-end I have a pubsub through a gRPC stream, and I stream positions to socket.io topics. Works beautifully, I can't imagine having to roll it out manually over websockets. In another thread here, someone mentions how non-trivial working with websockets is in Rust. I think that until we have a socket.io (server) version for other languages, Node.js will always beat most other languages.
- dictum 9y agoThe reverse @tjholowaychuk ;) (If you're a 10x engineer, check his new tool for 1e10x engineers: https://news.ycombinator.com/item?id=15731936 https://news.ycombinator.com/item?id=15731936)
- dz0ny 9y agoHe went meta recently. Made node_modules cleaner in golang https://github.com/tj/node-prune https://github.com/tj/node-prune :D
- DiThi 9y agoWould Matrix be a good fit for this use case? There are a bunch of different server implementations and the (web based) protocol is relatively simple and very well documented.
- philsnow 9y agoLast I looked at the reference implementation ("synapse"), the authors hadn't started to optimize its memory usage yet, so it was pretty thrashy on the 512MB ram droplet I ran it on.
- drdaeman 9y agoIt's still the case, and it requires quite a lot of CPU time too. There is no way Synapse is a good fit for something like RPi. Maybe when Dendrite is ready, it will make this possible.
- clandry94 9y agoI've been working on a similar project lately which also uses the gorilla/websocket library. I just tested connecting 1500 connections in parallel like was done in this link for Raspchat, and my application only uses 75 MB along with all other overhead within it. I'm not sure how this would cause a Raspberry Pi with 512MB memory to thrash and come to a crawl unless Raspchat has a ton of other overhead outside of connection management.
- divs1210 9y agoHi! I'm implementing channels/coroutines in clojure[0] and js[1]. These are alpha quality right now, but I already have channels with backpressure and async go blocks. I wrote the js implementation to show that these could be ported to any language. The main thought behind this is: CSP - S = Communicating Processes = Green Threads [0] https://github.com/divs1210/functional-core-async https://github.com/divs1210/functional-core-async [1] https://github.com/divs1210/coroutines.js https://github.com/divs1210/coroutines.js
- riskable 9y agoI feel his pain about the lack of decent WebSockets support in Rust. There's a few Websockets implementations but all of them are meant to run on a separate port from the web server. As in, they want you to run your web server on port 443 and the websocket on... Something else. Which makes zero sense (browsers will deny access to the second port because of security features related to SSL certificates). Also, unless you go low level (lower than frameworks like Tokio) you can't easily access file descriptors to watch them (e.g. epoll) for data waiting to be read. It makes it difficult to use WebSockets for their intended purpose: Real-time stuff. Rust needs a web framework that has built-in support for Websockets (running on the same port as the main web server) and also provides low-level access to things like epoll. Something like a very thin abstraction on top of mio (that still gives you direct access to the mio TcpListener directly). In my attempts to get Tokio reading a raw file descriptor I just couldn't get it working. I opened a bug and was told that raw fd support wasn't really supported (not well-tested because it only works on Unix and cross-cross-platform stuff is a higher priority). Very frustrating. I wish the Tokio devs didn't make the underlying mio TcpListener private in their structs.
- stmw 9y agoInteresting - I wonder if a much thinner, simpler library is the answer here. The part with websocket on same port is interesting, did you hear reasons why that hasn't been done?
- indream 9y agoI've found two frameworks supported websocket: https://github.com/tomaka/rouille https://github.com/tomaka/rouille https://github.com/actix/actix-web https://github.com/actix/actix-web Ref: https://github.com/flosse/rust-web-framework-comparison https://github.com/flosse/rust-web-framework-comparison
- halayli 9y agoI don't use Go but I find the reasoning fueled by a confirmation bias to pick JS. goroutines are now 2k. If you use 2 goroutines per connection that's 4k. If you have 10k connections that's roughly 20mb only which is very reasonable.
- _Codemonkeyism 9y agoNo clue about Go, but how can it take more memory then Javascript on Node? This is hard to believe.
- mattnewton 9y agoI think it’s the event loop model reuses more per connection. He mentions nothing is stopping you from implementing an event loop model for the pub-sub in go, just there wasn’t any library support and he didn’t want to spend time building it out when it is the default model in Node.
- iends 9y agoThere was an event loop implemented in Go on HN a few weeks/months ago that people might find interesting: https://github.com/tidwall/evio https://github.com/tidwall/evio
- nevi-me 9y agoOn a side note, tidwall (Josh) is one of the primary reasons why I want to give Go a go. I love https://github.com/tidwall/tile38 https://github.com/tidwall/tile38.
- Vendan 9y agoIt's a bad comparison, cause the Go version is using a "db" (key/value store) that tends to use quite a bit of memory.
- RomanPushkin 9y agoWe had pretty good number of sim.connections on 512MB instance. Unfortunately there is no enough details on methodology you used to compare, so I can't compare the number of clients it can support. I appreciate if you can do it yourself. https://github.com/ro31337/hacktunnel https://github.com/ro31337/hacktunnel
- dudul 9y agoI know very little about both Node and Go (currently learning the latter but haven't done anything really interesting so far :) - but, really it's hard to believe that Elixir/Phoenix would be disregarded so quickly if the crux of the problem is to have good pub/sub support.
- igotsideas 9y agoI was curious about the memory usage for Elixir. It’s the second time I’ve read (without details).
- iends 9y agoThis is the only article I'm aware of that has comparisons between a number of languages/platforms: https://hashrocket.com/blog/posts/websocket-shootout https://hashrocket.com/blog/posts/websocket-shootout
- pera 9y agoI actually did some experiments with Elixir, and my conclusion from benchmarking them was that Elixir is in fact significatively faster and consumed less memory than Node. In any case, Elixir is a great language, and even if BEAM was slower than Node I would still suggest to choose Elixir (+Phoenix) over JavaScript.
- kenhwang 9y agoI wonder if something like http://nerves-project.org/ http://nerves-project.org/ would've been suitable for his use case; not sure how seriously he was targeting a RasPi.
- dnautics 9y agoI thought exactly the same thing.
- tankenmate 9y agoWhy two (or three) go routines per connection? Why not one net socket (for reads) and two channels (one for writes, other for pub/sub) and select() between them? It seems like the OP is trying too hard to avoid event loops.
- lenkite 9y agoPlease upvote parent. This is the first thing that struck my mind too. golang offers `select` for non-blocking calls. Deeply skeptical that node.js is the best solution for a chat service. (unless the backend is serving rendered UI's)
- Thetawaves 9y agoYou generally need one thread to read for incoming messages, typical: for { select { case <-finish: done <- true return default: // read from the socket } } You need another thread to listen for messages on a channel and send them out the socket typical: for { select { case <-finish: done <- true return case msg <- msg_out: // write msg to socket } }
- tankenmate 9y agoInstead of? for { select { case <-finish: done <- true return case msg <- msg_out: // write handling case <-pubsub: // handle oob controls default: // read handling } }
- Thetawaves 9y agoYou wont be able to write messages while blocked on the read in this scenario.
- krylon 9y agoSo, I am not a big fan of Javascript. I do not despise it or anything, I just never got to like it. I guess. I did really love POE, though, so when I heard of Node.JS, I thought I will probably like this very much. I am not sure what happened. I think it was the tutorials being always out of date. Node.js seem so be such a fast-moving target. I do not mind asynchronous, callback-driven code. But when a tutorial that was written three months ago fails to run because some library had a breaking API change in between, that tends to drive me away. Think of Go what you want, but its policy towards backward compatibility is a big plus.
- iends 9y agoYou're comparing core libraries of Go with non-core libraries of Node.js. Since Go libraries are not versioned without a tool like dep, you're putting trust that master doesn't have breaking changes vs hoping the maintainer follows SemVer correctly. In fact, even the core Go team has problem with this and has to revert changes to things under golang.org/x/ when they break backwards compatibility.
- weberc2 9y agoThis seems to be a commonly-misunderstood point, so I would like to clarify a few things for readers. Go's tooling isn't great, but to characterize it as "trusting master" is inaccurate. Besides tools like `dep`, you can also vendor your dependencies manually or use submodules to pin to a known-good version of your dependencies. There are also tools like Nix which give you fully-reproducible builds. Just because Go has historically punted on the problem doesn't mean there aren't lots of better solutions than "trusting master". :)
- acover 9y agoNode's fs library changed within the last 2 years. I copy pasted code and it failed.
- iends 9y agoI guess you’re talking about well published changes resulting in new major versions being released?
- jorblumesea 9y agoPlease look into typescript. Makes js development sane.
- Vendan 9y agoOne thing to note is that they were using boltdb, which is an in process K/V store designed for high read loads, and doing a lot of writes to it. boltdb also tends to use a lot of memory, as it's using a mmap'd file. The switch also moved them to sqlite, which I would say is a much better fit for what they are doing, but means a lot of this is an apples and oranges comparison.
- Vendan 9y agoAnd now to get ranty: Boltdb was being handled badly: https://github.com/maxpert/raspchat/blob/79315d861968c1266701d07cb11d1db2fb95f47c/src/sibte.so/rascore/chat_log_store.go#L49 https://github.com/maxpert/raspchat/blob/79315d861968c126670... You should be using bolt's helper funcs, so you don't forget to close the transaction https://github.com/maxpert/raspchat/blob/79315d861968c1266701d07cb11d1db2fb95f47c/src/sibte.so/rascore/chat_log_store.go#L74 https://github.com/maxpert/raspchat/blob/79315d861968c126670... At least this is actually deferred, but still. https://github.com/maxpert/raspchat/blob/79315d861968c1266701d07cb11d1db2fb95f47c/src/sibte.so/rascore/messages.go https://github.com/maxpert/raspchat/blob/79315d861968c126670... These messages are horrifying, would be much better switching back to json and implementing a strategy like http://eagain.net/articles/go-dynamic-json/ http://eagain.net/articles/go-dynamic-json/ It copies in an unlicensed "snowflake generation" thing? https://github.com/maxpert/raspchat/blob/79315d861968c1266701d07cb11d1db2fb95f47c/src/sibte.so/rascore/snowflake.go https://github.com/maxpert/raspchat/blob/79315d861968c126670... and then essentially relicenses it? That's illegal...? They do have a better json pattern for some stuff: https://github.com/maxpert/raspchat/blob/79315d861968c1266701d07cb11d1db2fb95f47c/src/sibte.so/rascore/transport_json_decoder.go https://github.com/maxpert/raspchat/blob/79315d861968c126670... but I'd still steer away from reflection based, there's so much better ways of doing this stuff, like so: http://eagain.net/articles/go-json-kind/ http://eagain.net/articles/go-json-kind/
- dullgiulio 9y agohttps://github.com/maxpert/raspchat/blob/79315d861968c1266701d07cb11d1db2fb95f47c/src/sibte.so/rascore/snowflake.go#L83 https://github.com/maxpert/raspchat/blob/79315d861968c126670... This is a spinner?! No wonders the code is slow. The general use of inheritance and very non-idiomatic code makes me think this is another person who ditched Go before understanding any of it. It seems a very popular sport.
- nickthemagicman 9y agoTJ Hollowaychuck the author of express.js had the opposite opinion. https://medium.com/@tjholowaychuk/farewell-node-js-4ba9e7f3e52b https://medium.com/@tjholowaychuk/farewell-node-js-4ba9e7f3e...
- Vendan 9y agoAs did Ryan Dahl, the creator of node.js https://www.mappingthejourney.com/single-post/2017/08/31/episode-8-interview-with-ryan-dahl-creator-of-nodejs/ https://www.mappingthejourney.com/single-post/2017/08/31/epi...
- nickthemagicman 9y agoHa! Thats insane the creator of Node switched to Go.
- the_common_man 9y agoNode is very different now from what he started.
- zokier 9y agoAs someone who has neither Go, nodejs, or RPi experience the results seem surprising. Many have already commented that the author must have been doing something wrong; the code is there for everyone to see, so could some wiser gopher take a look and tell whats actually going on here?
- Vendan 9y agoI did, and wrote some else in here, but a lot of it boils down to poor choices in the Go code. They're using an embedded K/V store designed for high read loads and are writing to it often, there's really complex concurrent lockfree datastructures, and very poorly designed deserialization systems. On the flip side, they switched to Node and to a db that can deal with mixed read/write, nixed all the complex datastructures, and node can deal with unstructured JSON.
- jonathanoliver 9y agoIt's interesting he's referencing the Disruptor pattern. I wrote the Go port of the Disruptor implementation that he links to (https://github.com/smartystreets/go-disruptor https://github.com/smartystreets/go-disruptor) a while back and it performed beautifully. That said, channels weren't slow either. Our finding showed that we could easily push 10-30 million messages per second through a channel, so I'm struggling to understand what he defines as slow. That said, with a few tweaks to the Go memory model and I think I could take the Disruptor project to completion. Without those tweaks, I have to do memory fences in assembly.
- deleted 9y ago[deleted]
- Zekio 9y agohave you tried seeing how many messages you can push if you change how often the garbage collector runs? after seeing the Golang garbage collector blog post from cloudflare?
- jonathanoliver 9y agoI never tweaked GC. With channels, I imagine there would be quite a bit of garbage. With the Disruptor, it was zero allocations and zero collections so no garbage was produced because every element in the ring buffer was long lived.
- im_down_w_otp 9y agoOn a really slow, in-order-execution processor w/ tiny caches and fairly awful front-side bus that's also all responsible for managing the network connection over USB? The thing about Intel non-Atom level hardware is that Intel has spent a lot of money over the better part of two decades packing processors full of features that make all kinds of theoretically inefficient things run pretty fast. This is not true of the Broadcom SoCs on a Raspberry Pi.
- jonathanoliver 9y ago
- amelius 9y agoThis is surprising, as this is exactly the type of application where you'd think Go would perform well.
- dboreham 9y agoPerhaps this article is the CS version of "The Onion"?
- drinchev 9y agoI'm happy about this article, not because of what it says, but because of the popularity it got. NodeJS is not as bad as people think and I'm really excited about when it will regain status in the "pros" community.
- camus2 9y agoMore like Go has reached peak Go in terms of hype and people are going back to the stack they know best. Go is absolutely not a silver bullet, its community hates "creative solutions" and at the end of the day it's not that enjoyable to write for a lot of people. Go ecosystem isn't that big either compared to JS.
- deleted 9y ago[deleted]
- noncoml 9y agoErlang
- rmetzler 9y agoor Elixir
- _ph_ 9y agoBesides that, as many here have pointed out, this sounds like a problem somewhere hiding in the Go code ruining the performance, it is certainly true, that an event-handler based approach is increadible efficient to manage a high number of simple requests with limited resources. If every request can be handled in a single event, it only has advantages. It does not require many resources and you don't have to deal with any synchronisation issues. In many typical web applications you have less if no interaction between the connections, but rather complex logic running at each request. There the event-based approach, which must not block, is getting more complex to manage and you want to use all cpus in the system. There a goroutine based approach should shine much stronger, as the goroutines may block and you don't have to spread your program logic across callbacks.
- andmarios 9y agoUsing go's websocket library would also be viable. For the receiving end, go can use http handlers for websockets. So when a message from any websocket is received the handler will be spawn and process it (just as any http request). Preferably dispatch it to a big central channel. Keeping separate channels for each websocket seems overkill to me. Go has maps. Create a map with all the websocket connections and maybe smaller maps for each chat room, then set n workers to listen to the central channel and dispatch messages directly to each room member.
- jimsmart 9y agoIf instead of ditching Go he had posted some kind of help request to the 'gonuts' group / mailing list, I'm 100% certain that several people would've helped him with code reviews and feedback. I've seen this happen in the gonuts group countless times, including contributions/assistance from the core Go team that hang out there :) As noted by other commenters, below, the code seems to have some issues. And, if it still didn't perform well after addressing those, somebody in gonuts would've helped teach how to profile it, and then expert-eyes could have looked over the profiler output and provided further feedback.
- tschellenbach 9y agoI'm working on the exact opposite migration at the moment :) (Most of our stack is Go, but we use the excellent Faye library written in Node) The Node code is really well done. https://faye.jcoglan.com/ https://faye.jcoglan.com/ Nothing wrong with the Node codebase. In our case we just had to add a lot of business logic. I could have done that in Node (we did for a long time), but I decided that with the latest set of changes we'd bring this component in line with the rest of our infrastructure. It's hard to know without the code, but the author seems to be doing a few things wrong: 1. You only need a few channels, not N. Maybe 4-5 is enough. 2. In terms of goroutines you only need as many as are actively communicating with your server. So creating a new connection creates a goroutine, sending a message to a channel creates a goroutine etc. 3. You need something like Redis if you want to support multiple nodes For inspiration check out this awesome project: https://github.com/faye/faye-redis-node https://github.com/faye/faye-redis-node This will perform well in Node and even better in Go.
- MrBuddyCasino 9y agoRyan Dahl, the creator of Node.js: "That said, I think Node is not the best system to build a massive server web. I would use Go for that. And honestly, that’s the reason why I left Node. It was the realization that: oh, actually, this is not the best server-side system ever." Full interview: https://www.mappingthejourney.com/single-post/2017/08/31/episode-8-interview-with-ryan-dahl-creator-of-nodejs/ https://www.mappingthejourney.com/single-post/2017/08/31/epi...
- monsieurbanana 9y agoAm I missing something? In the interview Ryan Dahl said that if he were to build a "massively distributed DNS server" he would not chose node. And then again "Node is not the best system to build a massive server web". But he also said that for less massive projects Node could be the right fit. Isn't that basically agreeing with the blog post? I don't see what's your point.
- spraak 9y agoWhat is your point? Are you trying to say that the OP is wrong because the creator of Node says to use Go instead?
- erikpukinskis 9y agoI am a huge JS fan and I agree, for purely server side plays it’s probably not the best choice. I actually think Node has not yet realized its best feature. It’s still in a research phase while it learns its best trick: components that bridge the client and server. Meteor was an attempt. And server side boot in the MVC frameworks is another attempt. But both are wrong. Both try to create anonymous code that doesn’t know whether it’s on the client or server. But the client and server are different. The winning solution will acknowledge that, and just help the component do both. Once we have components that span client and server we can then write applications that don’t deal directly with HTTP. But not before. That’ll be a huge thing.
- styfle 9y agoGood point. What do you think about shared components using React SSR? https://github.com/styfle/react-server-example-tsx https://github.com/styfle/react-server-example-tsx
- _jsdw 9y agoRegarding Rust not having a mature websockets lib, this library seems to be a decent websockets implementation at a glance and passes all of the autobahn tests: https://github.com/housleyjk/ws-rs/ https://github.com/housleyjk/ws-rs/ In any case, that is where I'd begin :)
- coolaliasbro 9y agoComputers.
- majewsky 9y ago> Since go does not have generics or unions my only option right now is to decode message in a base message struct with just the @ JSON field and then based on that try to decode message in a full payload struct. If he is in control of his protocol, why did he not shape it to suit his parser library? Instead of this: message1 = { "@": "foo", "foo1": 1, "foo2": 2 } message2 = { "@": "bar", "bar1": 1, "bar2": 2 } Do this: message1 = { "foo": { "foo1": 1, "foo2": 2 } } message2 = { "bar": { "bar1": 1, "bar2": 2 } } Then you can read both types of messages into a single Go type, type Mesage struct { Foo *FooMessage Bar *BarMessage } After parsing, that element which is not nil tells you which type of message was sent.
- KirinDave 9y agoI support ports of a Golang library and protocol that did this and I am very tired of having to suffer Go's anemic type system in every other language I work with. Please stop infecting us with Go-specific type tags (that btw make the protocol versioning story much more complicated) and either demand Go support generics like every other modern statically typed language, or accept your language is ill-equipped for parsing and check if things = nil a lot more. Don't advocate for pushing your tooling's problems out on your peers.
- tree_of_item 9y agoAre you referring to majewsky's encoding? How is that a Go-specific type tag? This is a really common encoding of sum types in unityped languages: the presence or absence of a key.
- KirinDave 9y agoThat kind of encoding is only the right call if you want for a message to be a foo, a bar, OR a foo+bar. If you've got an opcode, name it semantically with a name field. If you've got a type to serialize, do it semantically and don't just do like what the library I ported does and put the Golang type annotation in a string. And don't let objects inhabit a fusion like this. It leads to surprising behavior with malformed messages.
- anonymous7777 9y agoGophers must be crying now!!
- deleted 9y ago[deleted]
- partycoder 9y agoOpen source software often makes use of the wisdom of the crowds to move forward, and when those crowds are in average less prepared, the results are comparably bad. See the top answer for this question in StackOverflow: https://stackoverflow.com/questions/5062614/how-to-decide-when-to-use-node-js https://stackoverflow.com/questions/5062614/how-to-decide-wh... . The top answer with 1360 upvotes is wrong and had little to do with the question. This is a recurrent thing in the node world. Go ask this same thing on an Erlang, Haskell, Rust, etc. forum and I am sure the right answer will come up quickly.
- Arzh 9y agoI think you are right, go is not the best language for your project, single threaded just moving blobs of data around node is a good solution. I'm not sure why anyone would have a problem understanding that. (And I'm a guy who hates node but loves go)