-
Notifications
You must be signed in to change notification settings - Fork 385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MSC2108: Sync over Server Sent Events #2108
base: old_master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
## Introduction | ||
|
||
Currently, Matrix clients use long polling to get the latest state from the server, | ||
it becomes an issue when you have a lot of clients because: | ||
* homeserver needs to process a lot of requests, which by the way may return nothing | ||
* it affects network bandwidth, each time client sends request it creates a new HTTP | ||
request with headers, cookies and other stuff | ||
* for mobile clients, it spends their cellular Internet and eats money | ||
* when homeserver uses SSL over HTTP (what is recommended), | ||
clients are doing again and again the most expensive operation, the TLS handshake | ||
|
||
So, instead of long polling I propose to implement | ||
sync logic over [Server Sent Events][mdn-sse](SSE) | ||
|
||
## Proposal | ||
|
||
[Server Sent Events][mdn-sse](SSE) is a way for servers to push events to clients. | ||
It was a part of HTML5 standard and now available in all major web and mobile browsers. | ||
It was specifically designed to overcome challenges related to short/long polling. | ||
By introducing this technology, we can get the next benefits: | ||
* only 1 persisted connection per client that is kept open "forever". | ||
* SSE is built on top of HTTP protocol, so can be used in communication between servers | ||
* SSE is more compliant with existing IT infrastructure like (Load Balancer, Firewall, etc) | ||
uhoreg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* web and mobile browsers support automatic reconnection and `Last-Event-Id` header out of the box | ||
* Matrix protocol is built over HTTP, so SSE should fit good in protocol specification | ||
|
||
Check this for details: | ||
* https://medium.com/axiomzenteam/websockets-http-2-and-sse-5c24ae4d9d96 | ||
* https://www.html5rocks.com/en/tutorials/eventsource/basics/ | ||
* https://stackoverflow.com/questions/9397528/server-sent-events-vs-polling | ||
* https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events | ||
* supported browsers: https://caniuse.com/#feat=eventsource | ||
|
||
SSE is easy to implement by your own on server side as it just a text based streaming on top of HTTP | ||
but there are libraries which can do this for us (e.g., https://pypi.org/project/Flask-SSE/). | ||
Support for SSE exists in Android and iOS libraries as well (few quickly googled): | ||
* Android - http://kaazing.org/ | ||
* iOS - /~https://github.com/inaka/EventSource | ||
|
||
This proposal doesn't change the shape of Matrix events or required parameters to do state synchronization | ||
but instead propose to use a different underlying technology to do this. | ||
As it was suggested in the related issue: | ||
* lets expose `/sync/stream` URL for SSE in order to be backward compatible with other clients and servers | ||
uhoreg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* this URL returns the same data as continually calling `/sync` | ||
* it accepts the same parameters as `/sync`, except `since` and `timeout` | ||
Half-Shot marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question. My guess is that it would be equivalent to continually calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question. I think that there are three options:
Personally, I think my preference would be 2, then 1, then 3, with 1 and 2 being fairly close, and 3 being much less preferred. |
||
* instead of using the `since` query parameter, the next batch token will be passed through the `Last-Event-ID` header. | ||
Half-Shot marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* each event will have the same format as what `/sync` returns. The id of each event will be the `next_batch` token | ||
uhoreg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* the server sends events in exactly the same way that it would send responses to `/sync` calls with the `since` | ||
parameter set to the previous `next_batch` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per above, perhaps you could give a description on what an event is in SSE terms? I assume a SSE event is the body being sent along the wire, but it's not explicit here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added links to documentation for the shape of matrix sync endpoint and for the format of SSE event. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It still doesn't make any sense to me: how is a client meant to resume their sync stream? All they'd have is a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If their call to It may be helpful to give an example of how the requests/responses look, so that people don't have to go digging through the SSE docs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 to examples. The SSE docs are a bit too complicated to try and parse in parallel here. Doesn't even need to be valid SSE:
|
||
|
||
## Tradeoffs | ||
|
||
Another alternative is to implement websocket communication for state synchronization. So, why not websockets? | ||
* websockets are built over TCP protocol and requires implementation in server language | ||
Half-Shot marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* some proxy servers or firewalls may block websockets | ||
* HTTP/2 was standardized in 2015 without any mention of WebSockets | ||
uhoreg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
and only in 2019 support for websockets over HTTP/2 was added. | ||
* lack of built-in support for `Last-Event-Id` and automatic reconnection | ||
|
||
The main difference between Websockets and SSE is that the first one is 2 way communication. | ||
But with adoption of HTTP/2, which can be easily enabled in reverse proxy like nginx over HTTPS, | ||
HTTP requests are cheaper than in HTTP/1.1 due to headers compression and request multiplexing. | ||
So, it's not an issue anymore to send requests from client via regular HTTP and get events via SSE. | ||
|
||
## Potential issues | ||
|
||
Don't see issues. There are old clients which does not support SSE | ||
uhoreg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
but polyfills with SSE implementation can be used. | ||
|
||
## Security considerations | ||
|
||
No security issues from SSE perspective | ||
|
||
## Conclusion | ||
|
||
By adopting SSE, homeservers will be able to keep higher load and bigger amount of clients | ||
s SSE was designed to handle these cases with low consumption of resources. | ||
SSE is just a HTTP streaming (basically `Content-Type`), | ||
so it should fit good in existing HTTP infrastructure and Matrix protocol. | ||
|
||
[mdn-sse]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no mention of how limited syncs work in this proposal. Syncs can be limited due to a filter or due to the server's maximum willingness to serve events.
The existing sync endpoint is built for long polling, which doesn't really make it suitable for SSE. Although the sync format does lend itself to being a nice and backwards compatible data structure, I think it would be best if we used a more stream-oriented structure for SSE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought on this was that it would work just like calling
/sync
repeatedly. For example, if you call/sync/sse
with theLast-Event-ID
set to some value, and the equivalent/sync
call would have return a limited sync, then the first SSE event that you get will also be a limited result. Also, if the server is streaming SSE events, and you suddenly get a billion events in one room, then the next SSE event that it sends will be limited. It doesn't quite fit perfectly with a streaming model (for example, calling/sync/sse
with the sameLast-Event-ID
two times won't give you the same result for the first event), but it fits with the way that Matrix currently handles truncating results. And I don't think SSE has a native method of skipping over events.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, adding some examples to the proposal may be useful.