[HN Gopher] Woe be unto you for using a WebSocket
___________________________________________________________________
Woe be unto you for using a WebSocket
Author : mathgladiator
Score : 133 points
Date : 2021-12-22 16:28 UTC (6 hours ago)
(HTM) web link (www.adama-lang.org)
(TXT) w3m dump (www.adama-lang.org)
| bri3d wrote:
| I think this conflates a very specific paradigm for using
| WebSockets (state synchronization with a stateful "server") with
| WebSockets as a technology.
|
| At the end of the day, WebSockets are just, well, sockets, with a
| goofy HTTP "upgrade" handshake and some framing on top of them.
| You could implement the exact same request/response model as in
| an HTTP based service over a WebSocket if you wanted to.
|
| Stateful services are a tradeoff whether you use a WebSocket or
| not.
|
| Reading through here, I think what you're trying to build is a
| synchronized stateful distributed system where state management
| becomes more transparent to the engineer, not only across backend
| services but also between the browser and the service side - this
| is well tread ground and a huge problem, but an interesting one
| to take on nonetheless. "WebSockets" are a red herring and just
| an implementation detail.
| mathgladiator wrote:
| You're right. The key thing is the spectrum of freedom induced
| by the library/framework. For example, if use something like
| PHP then you live in a prison of the request lifecycle.
| Sometimes the prison is socially enforced by not having shared
| state between requests within a process.
|
| There is nothing special about websockets, but they do confer a
| freedom and responsibility.
| vikR0001 wrote:
| Just use Meteor and/or Apollo. They have all this stuff figured
| out.
|
| https://www.meteor.com/
|
| https://www.apollographql.com/
| cultofmetatron wrote:
| come to phoenix/elixir land. Channels are amazing and the new
| views system allows you to seamlessly sync state to a frontend
| using websockets with almost no javascript
| mathgladiator wrote:
| Perhaps I will.
|
| I'm thinking about how I position Adama for both Jamstack and
| as a reactive data-store (which could feed phoenix/elixer
| land). I intend to change my marketing away from the
| "programming language" aspect and more towards "reactive data
| store".
| Zealotux wrote:
| My side-project relies heavily on WS, I'm currently using
| Node.js and it's alright but learning Elixir is my goal during
| these holidays. Any resource to share to get started? I don't
| know much about Elixir except it's perfect for such use-cases.
| dqv wrote:
| I got pretty far in the beginning just by reading the docs on
| Phoenix channels [0]. I was learning Phoenix and ReactJS at
| the same time and got a pretty simple Redux thunk that
| interacted with Phoenix Channels in a few days. I'm not sure
| if that was the optimal way to do it, but it was really cool
| interacting with the application from IEx (elixir shell).
|
| You might find an interesting (albeit more complex) entry
| point by interacting with Phoenix Channels from your Node.js
| app using the Channels Node.js client [1] and within the
| frontend itself.
|
| [0]: https://hexdocs.pm/phoenix/channels.html [1]:
| https://www.npmjs.com/package/phoenix-channels
| lawn wrote:
| The book Real-Time Phoenix is good for designing realtime
| systems.
|
| For a good introduction to Elixir, I loved Elixir in Action
| which also covers OTP.
|
| If you want a good Phoenix resource, the book Programming
| Phoenix is good.
|
| Finally, the docs in Elixir and Phoenix are great.
| sb8244 wrote:
| I wrote Real-Time Phoenix and it goes into pretty much
| everything that I hit when shipping decently large real-time
| Channel application into production. Like, the basics of "I
| don't know what a Channel is" into the nuance of how it's a
| PITA to deploy WS-based applications due to load balancers
| and long-lived connections.
|
| The new LiveView book is great if you're interested in going
| fully into Elixir (server/client basically). I use LiveView
| for my product and it's great.
| b5n wrote:
| Being already familiar with FP I was able to jump right into
| elixir after running through learn you some erlang. Erlang
| and elixir are very similar, and you get the bonus of
| learning a bit about OTP, BEAM, and the underlying
| philosophy. There's a ton of resources after that, and the
| docs are easy to use and understand.
|
| https://learnyousomeerlang.com/
| cultofmetatron wrote:
| I was a nodejs programmer for almost 8 years before I hopped
| to elixir. A lot of it was motivated btw elixir's realtime
| system and concurrency.
|
| One of the issues with nodejs is that you're stuck to one
| process which is single threaded. IE: you're stuck to one
| core. Yes there are systems like clustering which relies on a
| master process spawning slave processes and communicating
| over a bridge but in my experience, its pretty janky.
|
| You're making a great move by trying out elixir. It solves a
| lot of the issues I ran into working with nodejs.
| Immutability is standard and if you compare two maps, it
| automatically does a deep evaluation of all the values in
| each tree.
|
| The killer feature however is liveview. Its what meteor
| WISHES it could be. realtime server push of html to the dom
| and teh ability to have the frontend trigger events on the
| backend in a process thats isolated to that specific user.
| Its a game changer.
|
| Anyways, if you're looking for resources to learn. pragprog
| has a bunch of great books on elixir. Thats how I got
| started.
| callamdelaney wrote:
| Channels are basically websockets and only supported inside
| Phoenix as far as I can tell..
| cultofmetatron wrote:
| its more than just webockets. Its a prototcol built on web-
| sockets that also include keepalive and long-polling
| fallback.
|
| You could in theory replicate the protocol in another stack
| but its more than that. Elixir is uniquely suited to
| websocket applications. Since a websocket is persistent, you
| need a process on your end that handles that. Elixir is
| excellent at creating lightweight threads for managing these
| connections. Out of the box, you can easily support a few
| thousand connections on a single server.
|
| I know because we did it at my startup. channels powers our
| entire realtime sync system and its yet to be a bottleneck.
| It more or less works out of the box without issue. Its
| almost boring level reliable.
| callamdelaney wrote:
| Elixir inherits those properties from the Beam VM it shares
| with Erlang - both languages are effectively great for this
| WS/Channels use case - but Channels seems unhelpful unless
| you're already using phoenix. I can't see that it can be
| used in say Erlang.
| sb8244 wrote:
| Channels are really just a protocol, but that protocol is
| implemented in Elixir (Phoenix) and so isn't available
| elsewhere.
|
| I think that the important question is "why does this
| protocol exist?" Most likely, you'll end up solving
| similar problems as to why Channels exist in the first
| place. So from a protocol perspective, it's nice that
| some problems are solved for you.
| prophesi wrote:
| May not fit your use-case, but you can create an umbrella
| project with both an Erlang app and an Elixir/Phoenix
| app, whereby the latter's capable of calling functions in
| the former.
| hattmall wrote:
| I've never seen websockets accomplish anything that push with
| long polling didn't do more effective and efficiently. I think
| they are a technology that missed their time, the CPU / power
| savings are generally non-existent and the minimal bandwidth
| savings are frequently negated by the need to add in redundancy
| and checks.
| anderspitman wrote:
| If SSE supported binary data I might agree with you. I think
| WebSockets have their place, but are overused. I definitely
| agree long polling should be implemented first and then only
| add WS if you've measured that you need it. You're probably
| going to need to implement polling anyway for clients to catch
| up after disconnect.
| eska wrote:
| I'm confused. Just because you use request response doesn't mean
| you don't have state in your page. And sure, your connection can
| drop, but your requests can also fail. Protocol versioning is
| required, but that is true for any protocol ever, also request
| response. And what's this about wanting to outsource all state
| and everything requires a database as soon as it has state? Which
| one does mspaint.exe use? And if using a load balancer or proxy
| somehow leaks through then something really messed up is going
| on. In pubsub, just like REST, one doesn't care who sent the
| data. I'm confused.
| mathgladiator wrote:
| Sorry about that. Yes, those are required but you have more
| freedom to go wrong in more severe ways.
|
| Mspaint uses the file system at command of the user. Something
| that I didn't mention (which I will I'm a revision) I'd that
| the server is being run by another person with their own
| deployment schedule. So, we generally like to excise state ASAP
| to a durable medium since process state is volatile.
| rglover wrote:
| Make sure you handle disconnects/reconnects, leverage query
| params to pass state (ideally limited), sync/scale via Redis
| pubsub, and assume that the websocket will fail so always have
| some sort of fallback/redundacy. Ideally think of websockets like
| sprinkles on ice cream.
|
| Shameless plug: https://cheatcode.co/courses/how-to-implement-
| real-time-data...
| [deleted]
| halpert wrote:
| pshc wrote:
| On the plus side, once you get a good websocket steady state
| going, the efficiency and latency benefits are nice compared to
| HTTP1 polling.
|
| Maybe not that big of an advantage anymore with HTTP2 popping
| off.
| FZambia wrote:
| Every time I read criticism of WebSockets it reminds me about
| WebSuckets (https://speakerdeck.com/3rdeden/websuckets)
| presentation :)
|
| I am the author of Centrifugo server
| (https://github.com/centrifugal/centrifugo) - where the main
| protocol is WebSocket. Agree with many points in post - and if
| there is a chance to build sth without replacing stateless HTTP
| to persistent WebSocket (or EventSource, HTTP-streaming, raw TCP
| etc) - then definitely better to go without persistent
| connections.
|
| But there are many tasks where WebSockets simply shine - by
| providing a better UX, providing a more interactive content,
| instant information/feedback. This is important to keep - even if
| underlying stack is complicated enough. Not every system need to
| scale to many machines (ex. multiplayer games with limited number
| of players), corporate apps not really struggle from massive
| reconnect scenarios (since number of concurrent users is pretty
| small), and so on. So WebSockets are definitely fine for certain
| scenarios IMO.
|
| I described some problems with WebSockets Centrifugo solves in
| this blog post - https://centrifugal.dev/blog/2020/11/12/scaling-
| websocket. I don't want to say there are no problems, I want to
| say that WebSockets are fine in general and we can do some things
| to deal with things mentioned in the OP's post.
| zemo wrote:
| > Not every system need to scale to many machines (ex.
| multiplayer games with limited number of players)
|
| the author writes a websocket board game server. Most, if not
| all, of these complaints read like the author isn't
| partitioning the connections by game.
| jeroenhd wrote:
| I've only professionally used WebSockets with Spring Boot and
| React and I must say: they're perfectly fine?
|
| That is, if you use WS to simply asynchronously communicate
| events and do out-of-band message passing, they operate quickly,
| easily and efficiently. I wouldn't use them to send binary blobs
| back and forth or rely on them to keep a perfect state match, but
| for notifications and push events they're a delight to work with.
| Plus, their long-term connectivity gives them an edge above plain
| HTTP because you can actually store a little state in sockets
| rather than deriving state from session cookies and the like.
|
| Yes, WebSockets don't fit well within the traditional "one
| request, one response, one operation" workflow that the web was
| built upon, but that model is arguably one of the worst problems
| you encounter when you use HTTP for web applications (not
| websites, though; for websites, HTTP works perfectly!). Most
| backend frameworks have layers upon layers of processing and
| securty mitigations exactly because HTTP has no inherent state
|
| WebSockets aren't some magical protocol that will make all of
| your problems go away but if used efficiently, they can be a huge
| benefit to many web applications. I've never used (or even heard
| of) Adama, so I can totally believe that websockets are a
| terrible match for whatever use case this language has, but that
| doesn't mean they deserve to get such a bad rep. You just have to
| be aware of your limitations when you use them, the same way you
| need to be aware of the limitations of HTTP.
| superice wrote:
| Absolutely right, until you have multiple instances of backends
| you need to deal with and synchronize, which is a pain in the
| behind. The OPs main issue seems to be with that problem, which
| is the tough component of using something stateful like
| websockets anyways. The impedance mismatch of 'something
| happened in the database' to 'send event over websocket' is
| painful in a multi backend instance environment.
|
| Case in point: dossier locking in the product we both worked
| on. Hi Jeroen! Always nice to find an old colleague on here :)
| jeroenhd wrote:
| Ha, hey there! Nice username :)
|
| You're totally right, of course; for shared states between
| different backend instances you'll need a different solution,
| like database locking or complicated inter-backend API calls,
| or even a separate (set of) microservice(s) to deal purely
| with websockets while other backend operate on the database.
| That way you can apply scaling without data consistency
| issues, if you want to go for a _really_ (unnecessarily)
| complicated solution.
|
| It all depends on your problem space. If you want to make a
| little icon go green on a forum because someone commented on
| your post, I think websockets are perfect, much better than
| the long-lived HTTP polls of yore.
|
| I think the OP is using websockets to synchronize game state
| across different clients, which can be quite tricky even
| without having to deal with scaling or asynchronous
| connections. You can use websockets for that, but manual HTTP
| syncs/websocket reconnects after a period of radio silence
| would not go amiss. Hell, if it's real-time games this is
| about, you might even want a custom protocol on top of WebRTC
| to get complete control over data ad state with much better
| performance.
| TameAntelope wrote:
| I kludged together subscription support for our GraphQL stack,
| and it's super scary because the product people see it working
| and are like, "this is awesome!" but sometimes it doesn't totally
| work, and I don't think they realize how hard it would be to,
| "just make it work all the time".
|
| I want a "real" non-kludge solution, but it's hard to convince
| someone they need to give you money to throw away something that
| "works", from their perspective.
| phtrivier wrote:
| For all the mean things I could say about the language and it's
| ecosystem, this is one area where elixir/phoenix/channels shine.
| oautholaf wrote:
| I worked for a while on a well-known product that used (and
| perhaps still uses) WebSockets for its core feature. I very much
| agree with the bulk of the arguments made in this blog post.
|
| In particular, I found this:
|
| - Our well-known cloud hosting provider's networks would
| occasionally (a few times a year) disconnect all long-lived TCP
| sockets in an availability zone in unison. That is, an incident
| that had no SLA promise would cause a large swath of our
| customers to reconnect all at once.
|
| - On a smaller scale, but more frequently: office networks of
| large customers would do the same thing.
|
| - Some customers had network equipment that capped the length of
| time of that a TCP connection could remain open, interfering with
| the preferred operation
|
| - And of course, unless you do not want to upgrade your server
| software, you must at some point restart your servers (and again,
| your cloud hosting provider likely has no SLA on the uptime of an
| individual machine)
|
| - As is pointed out in the article, a TCP connection can cease to
| transmit data even though it has not closed. So attention must be
| paid to this.
|
| If you use WebSockets, you must make reconnects be completely
| free in the common case and you must employ people who are
| willing to become deeply knowledgeable in how TCP works.
|
| WebSockets can be a tremendously powerful tool to help in making
| a great product, but in general they are almost always will add
| more complexity and toil with lower reliability.
|
| (edited typos)
| inopinatus wrote:
| None of this is particular to websockets, and in addition:
|
| > you must employ people who are willing to become deeply
| knowledgeable in how TCP works
|
| You already needed that for your HTTP based application; it's a
| fundamental of networked computing. Developers skipping out on
| mechanical sympathy are often duds, in my experience.
| vlovich123 wrote:
| > - Our well-known cloud hosting provider's networks would
| occasionally (a few times a year) disconnect all long-lived TCP
| sockets in an availability zone in unison. That is, an incident
| that had no SLA promise would cause a large swath of our
| customers to reconnect all at once.
|
| I'm kind of surprised that it was that infrequent. I would
| expect software upgrades should cause long-lived sockets to
| reset...
| inopinatus wrote:
| or a scale-up of an ELB
| xyzzy_plugh wrote:
| > disconnect all long-lived TCP sockets in an availability zone
| in unison
|
| I don't know what this means, but it sounds ridiculous. This
| would cause havoc with any sort of persistent tunnel or
| stateful connection, such as most database clients. Do you
| perhaps mean this just happens at ingress? That is much more
| believable and not as big of a deal.
|
| > office networks of large customers would do the same thing.
|
| Sounds like a personal problem. In all seriousness, your
| clients should handly any sort of network disconnect
| gracefully. It's foolish to assume TCP connections are durable,
| or to assume that you won't be hit by a thundering herd.
|
| Maybe I'm old fashioned but TCP hasn't changed much over the
| years, none of these problems are novel to me, it's well-
| trodden ground and there are many simple techniques to building
| durable clients.
|
| Also, all of the things you mention also affect plain old HTTP,
| especially HTTP2. There shouldn't be a significant difference
| in how you treat them, other than the fact you cannot assume
| they're all short lived connections.
| oautholaf wrote:
| Most applications written using HTTP, in my experience, do
| not have deep dependencies on the longevity of the HTTP2
| connection. In my experience, TCP connections for HTTP2 are
| typically terminated at your load balancer or similar. So
| reconnections here happen completely unseen by either the
| client application in the field or the servers where the
| business logic is.
|
| For us -- and I think this is common -- the persistent
| WebSocket connection allowed a set of assumptions around the
| shared state of the client and server that would have to be
| re-negotiated when reconnecting. The fact that this
| renegotiation was non-trivial was a major driver in selecting
| WebSockets in the first place. With HTTP, regardless of HTTP2
| or QUIC, your application protocol very much is set up to re-
| negotiate things on a per-request basis. And so the issues I
| list don't tend to affect HTTP-based applications.
| xyzzy_plugh wrote:
| > the persistent WebSocket connection allowed a set of
| assumptions around the shared state of the client and
| server that would have to be re-negotiated when
| reconnecting. The fact that this renegotiation was non-
| trivial was a major driver in selecting WebSockets in the
| first place. With HTTP, regardless of HTTP2 or QUIC, your
| application protocol very much is set up to re-negotiate
| things on a per-request basis. And so the issues I list
| don't tend to affect HTTP-based applications.
|
| I think this describes a poor choice in technology. There's
| no silver bullet here, and it sounds like you made a lot of
| questionable tradeoffs. Assuming that "session" state
| persists beyond the lifetime of either the client or the
| server is generally problematic. It's always easier for one
| party to be stateless, but you can become stateful for the
| duration of the transaction.
|
| Shared state is best used as communications optimization,
| and maybe sometimes useful for security reasons.
| tyingq wrote:
| >Sounds like a personal problem. In all seriousness, your
| clients should handly any sort of network disconnect
| gracefully
|
| That can be complex. Corporate MITM filtering boxes,
| "intrusion detection" appliances, firewalls, etc, can just
| decide to drop NAT entries, drop packets, break MTU path
| discovery, etc. Yes, there are things you can do. But then
| customers restart/reload when things don't happen instantly,
| etc. I don't know that there's a simple playbook.
| bri3d wrote:
| I built several large enterprise products over WebSockets. I
| didn't find it that bad.
|
| Office networks that either blocked or killed WebSockets were
| annoying. For some customers they were a non-starter in the
| early 2010s, but by 2016 or so this seemed to be resolved.
|
| Avoiding thundering herd on reconnect is a very explored
| problem and wasn't too bad.
|
| We would see mass TCP issues from time to time as well, but
| they were pretty much no-ops as they would just trigger a
| timeout and reconnect the next time the user performed an
| operation. We would send an ACK back instantly (prior to
| execution) for any client requested operation, so if we didn't
| see the ACK within a fairly tight window, the client could
| proactively reap the WebSocket and try again - customers didn't
| have to wait long to learn a connection was alive and unclosed.
|
| > If you use WebSockets, you must make reconnects be completely
| free in the common case
|
| I agree with this, or at least "close to completely free." But
| in a normal web application you also need to make latency and
| failed requests "close to completely free" as well or your
| application will also die along with the network. This is the
| point I make in my sibling comment - I think distributed state
| management is a hard problem, but WebSockets are just a layer
| on top of that, not a solution or cause of the problem.
|
| > you must employ people who are willing to become deeply
| knowledgeable in how TCP works.
|
| I think this is true insofar as you probably want a TCP expert
| somewhere in your organization to start with, but we never
| found this particularly complicated. Understanding that the
| connection isn't trustworthy (that is, when it says it's open,
| that doesn't mean it works) is the only important fundamental
| for most engineers to be able to work with WebSockets.
| anderspitman wrote:
| > Office networks that either blocked or killed WebSockets
| were annoying
|
| Curious how did they detect WS usage? Were you running on
| HTTP or did they just kill any long-lived TCP connection?
| Root certs?
| bri3d wrote:
| No, we always ran on TLS. There were a few classes of
| these:
|
| * Filtering MITM application firewall solutions which
| installed a new trusted root CA on employee machines and
| looked at the raw traffic. These would usually be
| configured to wholesale kill the connection when they saw
| an UPGRADE because the filtering solutions couldn't
| understand the traffic format and they were considered a
| security risk.
|
| * Oldschool HTTP proxy based systems which would blow up
| when CONNECT was kept alive for very long.
|
| * Firewalls which killed long-lived TCP connections just at
| the TCP level. The worst here were where there was a
| mismatch somewhere and we never got a FIN. But again,
| because we had a rapid expectation for an acknowledgement,
| we could detect and reap these pretty quickly.
|
| We also tried running WebSockets on a different port for
| awhile, which was not a good idea as many organizations
| only allowed 443.
| Waterluvian wrote:
| I use WebSockets for robots to communicate real-time state with a
| web UI. They're the only option and they're fine.
|
| I get that this article is more focused on a narrow perspective
| of the technology. But of course you can make silly use of any
| technology.
| eska wrote:
| I also implemented MQTT for industrial machines to publish data
| to a broker. It was trivial to create a web UI that subscribed
| to that broker via MQTT over Websockets. But I noticed that
| colleagues had this impression that MQTT cannot be used on the
| web, so they wanted to build a conversion from MQTT to
| SignalR.. a quick search would've cleared it up, but they were
| so sure for some reason. After I showed them the demo they just
| went with MQTT as well.
| jvanderbot wrote:
| Author: in this doc, headers are paragraph topic sentences, not
| bookmarks for disjoint ideas.
|
| And they are nonsensical. "Problem: Bumps in the night#". Oh,
| thanks, let me bookmark that for easy sharing.
| PaulDavisThe1st wrote:
| We used WebSockets to build a web-based front end for Ardour, a
| native cross-platform DAW, and didn't encounter any of these
| issues. Part of that is because the protocol was already defined
| (Open Sound Control aka OSC) and used over non-web-sockets
| already. But as others have noted, most of the problems cited in
| TFA come from the design goals, not the use of websockets.
| swagasaurus-rex wrote:
| For the very reasons listed in the article, I built:
|
| https://github.com/siriusastrebe/jsynchronous
|
| a library for keeping a javascript variables synchronized between
| Node.js servers and clients.
|
| Websockets work great for message passing but it struggles with
| data structures more complicated than what JSON can represent.
| Jsynchronous syncs any javascript object or array with
| arbitrarily deep nesting and full support for circular data
| structures.
|
| If a computer goes to sleep, or disconnects, websocket
| connections (and their underlying TCP connections) get reset so
| you lose any data sent while a computer is unavailable. This is
| catastrophic for state-management if it's left unhandled.
| Jsynchronous will re-send any data clients are missing and
| reconstructs the shared state.
|
| There's also a history mode that lets you rewind to past states.
| adamddev1 wrote:
| Very, very nice! I might use that! Just gotta wrap it a nice
| React hook.
| anderspitman wrote:
| Very cool. I tried something similar once. Have you gone down
| the differential/compressed update rabbit hole yet?
| swagasaurus-rex wrote:
| Right now jsynchronous message passes using custom encoding
| in JSON which keeps simple changes as small as an HTTP
| header, but with byte level encoding I think this could be
| halved.
|
| Some compression on top would probably do wonders for huge
| volumes of changes, though more browsers are supporting
| compression on the websocket level.
|
| I'm not familiar with the name differential update. Instead
| of passing potentially large states back and forth,
| Jsynchronous numbers each change to your synchronized data
| and shares these changes with all connected clients. This is
| called Event Sourcing, and it enables jsynchronous to rewind
| to previous states by running the changes from start to any
| intermediate state.
| mgamache wrote:
| Using Blazor (.net). It's been mostly a good experience. Fast UI
| updates, good programming model.
| mwattsun wrote:
| I've been looking at it lately and the SignalR tech it uses.
| Very nice. My cursory Google research indicates a server using
| it can handle about 3000 users, which is not many, but for my
| purposes is fine. Blazor makes it completely optional, which I
| proved to myself by doing client side Blazor (dot net wasm)
| only and using an Apache server instead of IIS with ASP.NET.
|
| https://en.wikipedia.org/wiki/SignalR
| mgamache wrote:
| Right, with .net core 6 the runtime wasm is much smaller.
| SignalR can be scaled if you need to, but for most sites 3000
| concurrent users is plenty.
| wvenable wrote:
| We're migrating to server-side Blazor because of the good
| experience yet all of the things mentioned in this article are
| a concern for using this technology. A few things, especially
| around deployment and maintenance, are significantly less good
| when your clients are always connected. I'm currently trying to
| figure out mitigations.
| thisrobot wrote:
| Full disclosure I work at MSFT and on the fluid framework.
|
| If you are interested in this you may also be interested in the
| fluid framework, https://github.com/microsoft/FluidFramework
|
| We use websockets and solve a lot of the state management problem
| called out here by keeping very little state on the server
| itself. The primary thing on server is a monotonically increasing
| integer we use to stamp messages, this gives us total order
| broadcast which we then build upon:
| https://en.m.wikipedia.org/wiki/Atomic_broadcast
|
| Here are some code pointers if you want to take a look:
|
| The map package is a decent place to look for how we leverage
| total order broadcast to keep clients in sync in our distributed
| data structures:
| https://github.com/microsoft/FluidFramework/blob/main/packag...
|
| The deltamanger in the container-loader package is where we
| manage the websocket. It also hits storage to give the rest of
| the system a continuous, ordered stream of events:
|
| https://github.com/microsoft/FluidFramework/blob/main/packag...
|
| The main server logic is in the Alfred and Deli lambdas. Alfred
| sits on the socket and dumps message into Kafka. Deli sits on the
| Kafka queue, stamps messages, the puts them on another queue for
| Alfred's to broadcast:
| https://github.com/microsoft/FluidFramework/tree/main/server...
| Philip-J-Fry wrote:
| You can turn websockets into a flawless request/response with
| async/await included on like 20 lines of JavaScript. I do it all
| the time.
|
| Generate an ID, make a request, store the promise resolve/reject
| in a map (js object). Your onmessage handler looks up the promise
| based on the ID and resolves the promise.
|
| Add a few more tiny features like messaging and broadcasting
| streams and you've got both request/response and push messaging
| over a single websocket.
|
| It's pretty neat in my opinion, saves having to mix HTTP and
| websockets for a lot of things.
| anderspitman wrote:
| It is neat. I've gone down this path[0]. But you find yourself
| essentially re-implementing HTTP, and losing things like
| backpressure. Sometimes it's what you need, but I try to be
| cautious before jumping to WS these days.
|
| [0]: https://iobio.io/2019/06/12/introducing-fibridge/
| winrid wrote:
| WebSockets are great when used in _addition to_ polling. This
| way, you can design a system that doesn 't result in missed
| events. Example: have a /events?fromTS=123 endpoint.
|
| At FastComments - we do both. We use WS, and then poll the event
| log when required (like on reconnect, etc).
|
| Products that can get away with just polling should. In a lot of
| scenarios you can just offload a lot of the work to companies
| like OneSignal or UrbanAirship, too.
|
| If you're going to use WS and host the server yourself, make sure
| you have plans for being able to shard or scale it horizontally
| to handle herds.
|
| It was hard for us to not use websockets, since like 70% of our
| customers pick us for being a "live" solution for live events
| etc.
| anderspitman wrote:
| Is it really worth the extra effort for WS over long polling at
| that point though? Especially if you're re-using the TCP
| connection it seems like the overhead would be minimal and the
| latency only slightly increased.
| winrid wrote:
| Sorry for the misunderstanding, but I don't mean WS over long
| polling. I mean WS _in addition to_ polling, not long
| polling. Use websockets, but also expose an API to get the
| same events by specifying a timestamp. This way the websocket
| server implementation can be much simpler, and the client
| just has to call the API to "catch up" on missed events on
| reconnect.
|
| You can also use this API for integrations, and your
| clients/consumers will thank you. For example, our third
| party integrations use the event log to sync back to their
| own data stores. They probably call this every hour, or once
| a day. You wouldn't want to use websockets with PHP apps like
| WordPress.
| te_chris wrote:
| Worth looking at Elixir Phoenix Channels if you're wanting to use
| sockets. Handle a lot of the messy stuff for you.
|
| https://hexdocs.pm/phoenix/channels.html
| anderspitman wrote:
| A few years ago I was more inclined to use WebSockets. They're
| undeniably cool. But as implemented in browsers (thanks to the
| asynchronous nature of JavaScript) they offer no mechanism for
| backpressure, and it's pretty trivial to freeze both Chrome and
| Firefox sending in a loop if you have a fast upload connection.
|
| I designed a small protocol[0] to solve this (and a few other
| handy features) which we use at work[1]. A more robust option to
| solve similar problems is RSocket[3].
|
| More recently I've been working on a reverse proxy[2], and
| realized how much of a special case WebSockets is to implement.
| Maybe I'm just lazy and don't want to implement WS in
| boringproxy, but these days I advocate using plain HTTP whenever
| you can get away with it. Server Sent Events on HTTP/1.1 is
| hamstrung by the browser connection limit, but HTTP/2 solves
| this, and HTTP/3 solves HTTP/2's head of line blocking problems.
|
| Also, as mentioned in the article, I try to prefer polling. This
| was discussed recently on HN[4].
|
| [0]: https://github.com/omnistreams
|
| [1]: https://iobio.io/2019/06/12/introducing-fibridge/
|
| [2]: https://boringproxy.io/
|
| [3]: https://rsocket.io/
|
| [4]: https://news.ycombinator.com/item?id=27823109
| loevborg wrote:
| My advice:
|
| * Make push updates optional. If no push connection can be
| established, fall back to polling. You can start by implementing
| polling only and add push later.
|
| * Use websockets only for server-to-client communication.
| Messages from the client are sent via regular HTTP requests.
|
| * Keep no meaningful state on the server. That includes TCP
| connection state. You should be able to kill all your ec2
| instances and re-spawn them without interrupting service.
|
| * Use request/response for all logic on the server. All your code
| should be able to run in an AWS lambda.
|
| * Use a channel/subscription paradigm so client can connect to
| streams they're interested in
|
| * Instead of rolling your own websocket server, use a hosted
| service like pusher.com or ably.com. They do all the heavy
| lifting for you (like keeping thousands of TCP connections open)
| and provide a request/response style interface for your server to
| send messages to connected clients
| badrabbit wrote:
| There is this particular app I have to use for work which relies
| heavily on web sockets. It works great so long as your latency is
| good. But as soon as your latency is over some threshold the
| sheer volume of websocket requests compounds and it becomes
| unusable. Normal sites just load slower, they don't fail entirely
| like this.
|
| I guess it goes without saying but devs really need to test their
| apps under unfavorable conditions.
| austincheney wrote:
| The biggest challenge when migrating from HTTP to any kind of
| stream is the loss of callback on response, because there is no
| request/response. There is only push. That means your messaging
| and message handling becomes far more complex to compensate.
|
| The article mentions that your socket could drop. This isn't
| critical so long as you have HTTP as a redundancy.
|
| For any kind of application making use of micro services I
| strongly recommend migrating to a socket first transmission
| scheme because it is an insane performance improvement. Also it
| means the added complexity to handle message management makes
| your application more durable in the face of any type of
| transmission instability. The durability means that your
| application is less error prone AND it is ready for migration to
| other protocols in the future with almost no refactoring.
| spicybright wrote:
| All of these issues could be solved well by a decent library. Or
| even just basic well thought out abstractions.
|
| I've written a few before from "scratch" myself to decent
| success. I don't think there's anything inherent with sockets
| that make it impossible to use well. I mean, we've been using
| sockets since the beginning of the internet.
|
| You can write the same article for literally any technology
| that's complicated to use without abstractions.
| mathgladiator wrote:
| That's the core thing is the discover of well thought out
| abstractions for a specific domain. I glossed over a lot of the
| specific details, but I iterated the pitfalls that I have seen
| and how I'm thinking about the abstractions I'm using.
| tbeseda wrote:
| Archive link with https https://archive.li/R8Nxi
| woodruffw wrote:
| Just in case the author is listening, I'll play the grammar nazi:
| it's "woe unto," not "woe onto."
| mathgladiator wrote:
| I'll fix when I return to my computer. Thanks
| dang wrote:
| I was just wondering if anyone had pointed that out. Fixed
| above.
|
| Edit: it probably should be "woe unto". From the King James
| Bible: 54 woe unto 24 woe to 2
| woe be unto 1 woe be to
|
| but "woe be unto" is in there so I guess it's legit enough.
| mmzeeman wrote:
| You don't have to design a new protocol. There is an open
| protocol which works nice for this use case. It can handle
| dropping connections, has a nice routing mechanism, it scales
| pretty well, has different QoS levels, pub/sub, request/response.
| That protocol is... MQTT v5!
|
| Personally I'm surprised it is not used more often by web devs.
| thatswrong0 wrote:
| We use this at my place of employment and it's generally OK
| except for dealing with reconnects. Also pub/sub
| request/response was not nearly as smooth as we had hoped and
| eventually we reverted back to HTTP
| mmzeeman wrote:
| We have build a nice support library for it.
| https://github.com/cotonic/cotonic. It helps that our backend
| is Erlang. https://github.com/zotonic/zotonic.
| [deleted]
___________________________________________________________________
(page generated 2021-12-22 23:00 UTC)