From https://en.wikipedia.org/wiki/Server_%28computing%29:
The nature of communication between a client and server is request and response. This is in contrast with peer-to-peer model in which the relationship is on-demand reciprocation.
What is "on-demand reciprocation"?
How is it different from "request and response"? Thanks.
Request-response mostly is an unidirectional flow of payload data, the request is just metadata.
In a p2p system data flows in both directions. For example in bittorrent you have have an asynchronous stream of messages in each direction where messages can be both requests and responses. The asynchronous part is important that data can flow both ways continuously.
If you wanted to compare it to HTTP then it would be like having one pipelined HTTP 1.1 connection open in each direction.
Related
I am prettty new to microservices, and I am trying to figure out how to set a micro-service architecture in which my publisher that emits an event, can receive a response with data from the consumer within the publisher?
From what i have read about message-brokers and message-queues, it seems like it's one-way communication. The producer emits an event (or rather, sends a message) which is handled by the message broker, and then the consumer consumes that event and performs some action.
This allows for decoupled code, which is part of what im looking for, but i dont understand if the consumer is able to return any data to the caller.
Say for example I have a microservice that communicates with an external API to fetch data. I want to be able to send a message or emit an event from my front-facing server, which then calls the service that fetches data, parses the data, and then returns that data back to my servver1 (front-facing server)
Is there a way to make message brokers or queues bidirectional? Or is it only useable in one direction. I keep reading message brokers allow services to communicate with each other, but I only find examples in which data flow goes one way.
Even reading rabbitMQ documentation hasn't really made it very clear to me how i could do this
In general, when talking about messaging, it's one-way.
When you send a letter to someone you're not opening up a mind-meld so that they telepathically communicate their response to you.
Instead, you include a return address (or some other means of contacting you).
So to map a request-response interaction when communicating with explicit messaging (e.g. via a message queue), the solution is the same: you include some directions which the recipient can/will interpret as "send a response here". That could, for instance be, "publish a message on this queue with this correlation ID".
Your publisher then, after sending this message, subscribes to the queue it's designated and waits for a message with the expected correlation ID.
Needless to say, this is fairly elaborate: you are, in some sense, reimplementing a decent portion of a session protocol like TCP on top of a datagram protocol like IP (albeit in this case, we may have some stronger reliability guarantees than we'd get from IP). It's worth noting that this sort of request-response interaction intrinsically couples the two parties (we can't really say "sender and receiver": each is the other's audience), so we're basically putting in some effort to decouple the two sides and then some more effort to recouple them.
With that in mind, if the actual business use case calls for a request-response interaction like this, consider implementing it with an actual request-response protocol (e.g. REST over HTTP or gRPC...) and accept that you have this coupling.
Alternatively, if you really want to pursue loose coupling, go for broke and embrace the asynchronicity at the heart of the universe (maybe that way lies true enlightenment?). Have your publisher return success with that correlation ID as soon as its sent its message. Meanwhile, have a different service be tracking the state of those correlation IDs and exposing a query interface (CQRS, hooray!). Your client can then check at any time whether the thing it wanted succeeded, even if its connection to your publisher gets interrupted.
Queues are the wrong level of abstraction for request-reply. You can build an application out of them, but it would be nontrivial to support and operate.
The solution is to use an orchestration system like temporal.io or AWS Step Functions. These services out of the box provide state management, asynchronous communication, and automatic recovery in case of various types of failures.
I'm writing a web app feature that would use WebSocket messages to transmit JSON structures between client and server. The most simple protocol for the app would be to keep repeatedly sending mostly redudant parts back and forth. Can HTTP/2 compression effectively compress redundant parts in separate messages going back and forth? I know this should be possible in theory but how about in practice?
Example case:
Assume that the shared_state is a string that is mostly same but not identical between different messages:
Client connects:
ws = new WebSocket("wss://myserver.example/foo/bar");
Client sends message over the WebSocket connection:
{ command: "foo", shared_state: "...long data here..." }
Server sends:
{ command: "bar", shared_state: "...long data here slightly modified..." }
Client sends:
{ command: "zoo", shared_state: "...long data here slightly modified again..." }
All these messages will be passed over a single HTTP/2 connection using a single websocket.
Will the messages going in both directions be compressed by HTTP/2? This would mean that the later data packets effectively could just use some references to already seen data in previously transmitted data in the same HTTP/2 connection. It would simplify the custom protocol that I need to implement if I can keep sending the shared state instead of just delta without causing high bandwidth usage in practice. I don't need to care about old clients that cannot support HTTP/2.
I'm assuming the delta between messages to be less than 1 KB but the whole message including the redundant part could be usually in range 10-60 KB.
The way WebSocket over HTTP/2 works is that WebSocket frames are carried as opaque bytes in HTTP/2 DATA frames.
A logical WebSocket connection is carried by a single HTTP/2 stream, with "infinite" request content and "infinite" response content, as DATA frames (containing WebSocket frames) continue to flow from client to server and from server to client.
Since WebSocket bytes are carried by DATA frames, there is no "compression" going on at the HTTP/2 level.
HTTP/2 only offers "compression" for HTTP headers via HPACK in HEADERS frames, but WebSocket over HTTP/2 cannot leverage that (because it does not use HTTP/2 HEADERS frames).
Your custom protocol has key/value pairs, but it's a WebSocket payload carried by DATA frames.
The only "compression" that you're going to get is driven by WebSocket's permessage-deflate functionality.
For example, a browser would open a connection, establish WebSocket over HTTP/2 (with the permessage-deflate extension negotiated during WebSocket upgrade), and then send a WebSocket message. The WebSocket message will be compressed, the compressed bytes packed into WebSocket frames, the WebSocket frames packed in HTTP/2 DATA frames and then sent over the network.
If your shared_state compresses well, then you are trading network bandwidth (less bytes over the network) for CPU usage (to decompress).
If it does not compress well, then it's probably not worth it.
I'd recommend that you look into existing protocols over WebSocket, there may be ones that do what you need already (for example, Bayeux).
Also, consider not using JSON as format since now JavaScript supports binary, so you may be more efficient (see for example CBOR).
The concepts of "stream, connection, message, and frame" constitute the main design of http2. And what confuses me is the idea of stream.
At first, the stream idea seems to me only as a virtual description of the flow of frames. But then I find the priority of http2 is aimed at streams instead of messages/requests. And why is that, I think the applications both client and server sides care more about and directly control the requests or messages, not which stream these messages reside in.
Plese refer to "stream prioritization":
https://developers.google.com/web/fundamentals/performance/http2#design_and_technical_goals
A stream in HTTP/2 corresponds to all the frames which make up a request and its corresponding response, so is the natural place to handle priority and flow control. The sentences "the response for this request should have high priority" and "the stream for this request and its response should have high priority" are equivalent.
There is a mention in the document you quote of a stream carrying "one or more messages", but I think that's just sloppy language in that document. If you look at section 8.1 of the spec it says "A client sends an HTTP request on a new stream" and "An HTTP request/response exchange fully consumes a single stream."
There can be other frames in that stream, such as PUSH_PROMISE, but those aren't actual requests and responses; the response data for a server push is sent on a new stream, which can then be given a different priority.
I'm in the process of designing a micro-service architecture and I have a performance related question. This is what I am trying out with my design:
I have a several micro-services which perform distinct actions and store those results in their own data-store.
The micro-services receive work via a message queue where they receive requests to run their process for the specific data given. The micro-services do NOT communicate with each other.
I have an API gateway which effectively has three journeys:
1) Receive a request to process data which it then translates into several messages which it puts on the queue for the micro-services to process in their own time. The processing time can be in minutes or longer (not-instant)
2) Receives a request for the status of the process, where it returns the progress of the overall process.
3) Receives a request for combined data, which is some combination of all the results from the services.
My problem lies in #3 above and the performance of this process.
Whenever this request is received, the api gateway has to put a message request onto the queue for information from all the services, it than has to wait for all the services to reply with the latest state of their data and then it combines this data and returns to the caller.
This process is obviously rather slow as it has to wait for every service to respond. What is the way of speeding this up?
The only way I thought of solving this is having another aggregate service/data-store where duplicate data is stored and queried by my api gateway. I really don't like this approach as it duplicates data and is extra work/code.
What is the 'correct' and performant way of querying up-to-date data from my micro-services.
You can use these approach for Querying data across microservices. Reference
Selective data replication
With this approach, we replicate the data needed from other microservices into the database of our microservice. The only coupling between microservices is in the data replication configuration.
Composite service layer
With this approach, you introduce composite services that aggregate data from lower-level microservices.
Hi guys I was just wondering if the websocket protocol already handles the sending of large data in chunks. At least knowing that it does will save me the time of doing so myself.
According to RFC-6455 base framing, has a maximum size limit of 2^63 bytes which means it actually depends on your client library implementation.
I was just wondering if the websocket protocol already handles the sending of large data in chunks...
Depends what you mean by that.
The WebSockets protocol is frame based (not stream based)
If what you're wondering about is "will a huge payload arrive in one piece?" - the answer is always "yes".
The WebSockets protocol is a frame / message based protocol - not a streaming protocol. Which means that the protocols wraps and unwraps messages in a way that's designed to grantee message ordering and integrity. A messages will not get...
...truncated in the middle (unlike TCP/IP, which is a streaming based protocol, where ordering is preserved, but not message boundaries).
The WebSockets protocol MAY use fragmented "packets"
According to the standard, the protocol may break large messages to smaller chunks. It doesn't have too.
There's a 32 bit compatibility concern that makes some clients / servers fragment messages into smaller fragments and later put them back together on the receiving end (before the onmessage callback is called).
Application layer "chunking" is required for multiplexing
Sending large payloads over a single WebSocket connection will cause a pipelining issue, where other messages will have to wait until the huge payload is sent, received and (if required) re-assembled.
In practice, this means that large payloads should be fragmented by the application layer. This "chunked" application layer approach will enable multiplexing the single WebSocket connection.