Commit 1f4de22d authored by gejun's avatar gejun

translated server_push.md

parent 5e7e71d3
[English version](../en/server_push.md)
# Server push
server push指的是server端发生某事件后立刻向client端发送消息,而不是像通常的RPC访问中那样被动地回复client。brpc中推荐以如下两种方式实现推送。
# 远程事件
和本地事件类似,分为两步:注册和通知。client发送一个代表**注册**的异步RPC至server,处理事件的代码写在对应的RPC回调中。server收到请求后把对应的done存下来,等到对应的本地事件触发时才调用done**通知**client发生了事件,可以看到server也是异步的。这个过程中如果连接断开,client端的RPC一般会很快失败,client可选择重试或结束。server端应通过Controller.NotifyOnFailed()及时获知连接断开的消息,并删除无用的done。
和本地事件类似,分为两步:注册和通知。client发送一个代表**事件注册**的异步RPC至server,处理事件的代码写在对应的RPC回调中。此RPC同时也在等待通知,server收到请求后不直接回复,而是等到对应的本地事件触发时才调用done->Run()**通知**client发生了事件。可以看到server也是异步的。这个过程中如果连接断开,client端的RPC一般会很快失败,client可选择重试或结束。server端应通过Controller.NotifyOnFailed()及时获知连接断开的消息,并删除无用的done。
这个模式在原理上类似[long polling](https://en.wikipedia.org/wiki/Push_technology#Long_polling),听上去挺古老,但可能仍是最有效的推送方式。“server push“乍看是server访问client,与常见的client访问server方向相反,挺特殊的,但server发回client的response不也和“client访问server”方向相反么?为了理解response和push的区别,我们假定“client随时可能收到server推来的消息“,并推敲其中的细节:
......@@ -13,14 +15,14 @@ server push指的是server端发生某事件后立刻向client端发送消息,
换句话说,client得对server消息“有准备”,这种“准备”还往往依赖client当时的上下文。综合来看,由client告知server“我准备好了”(注册),之后server再通知client是更普适的模式,**这个模式中的"push"就是"response"**,一个超时很长或无限长RPC的response。
在一些非常明确的场景中,注册可以被简化,如http2中的[push promise](https://tools.ietf.org/html/rfc7540#section-8.2)并不需要浏览器(client)向server注册,因为client和server都知道它们之间的任务就是让client尽快地下载必要的资源,且每个资源有唯一的URI。所以server可以直接向client推送资源及其URI,client看到这些资源时会缓存下来避免下次重复访问。类似的,一些协议提供的双向通信也是在限定的场景中提高推送效率,而不是实现通用的推送,比如多媒体流,格式固定的key/value对等。client默认能处理server所有可能推送的消息,以至于不需要额外的注册,但推送仍可被视作"response":client和server早已约定好的注册请求的response。
在一些非常明确的场景中,注册可以被简略,如http2中的[push promise](https://tools.ietf.org/html/rfc7540#section-8.2)并不需要浏览器(client)向server注册,因为client和server都知道它们之间的任务就是让client尽快地下载必要的资源。由于每个资源有唯一的URI,server可以直接向client推送资源及其URI,client看到这些资源时会缓存下来避免下次重复访问。类似的,一些协议提供的"双向通信"也是在限定的场景中提高推送效率,而不是实现通用的推送,比如多媒体流,格式固定的key/value对等。client默认能处理server所有可能推送的消息,以至于不需要额外的注册。但推送仍可被视作"response":client和server早已约定好的请求的response。
# Restful回调
client希望在事件发生时调用一个给定的URL,并附上必要的参数。在这个模式中,server在收到client注册请求时可以直接回复,因为事件触发和注册用的RPC结束与否无关。另外由于回调只是一个URL,可以存放于数据库或经消息队列流转,这个模式灵活性很高,在业务系统中使用广泛。
client希望在事件发生时调用一个给定的URL,并附上必要的参数。在这个模式中,server在收到client注册请求时可以直接回复,因为事件不由注册用RPC的结束触发。由于回调只是一个URL,可以存放于数据库或经消息队列流转,这个模式灵活性很高,在业务系统中使用广泛。
URL和参数中必须有足够的信息使回调知道这次调用对应某次注册,因为client未必一次只关心一个事件,即使一个事件也可能由于网络抖动、机器重启等因素注册多次。如果回调是固定路径,client应在注册请求中置入一个唯一ID,在回调时带回。或者client为每次注册生成唯一路径,自然也可以区分。本质上这两种形式是一样的,只是唯一标志符出现的位置不同。
回调应处理[幂等问题](https://en.wikipedia.org/wiki/Idempotence),server为了确保不漏通知,在网络出现问题时往往会多次重试,如果第一次的通知已经成功了,后续的通知就应该不产生效果。上节“远程事件”模式中的幂等性由RPC代劳,它会确保done只被调用一次。
为了避免重要的回调被漏掉,用户往往还需灵活组合RPC和消息队列。RPC的时效性和开销都明显好于消息队列,但由于内存有限,在重试过一些次数后仍然失败的话,server就得把这部分内存空出来去做其他事情了。这时把通知放到消息队列中,利用其持久化能力做较长时间的重试直至成功,辅以回调的幂等性,就能使绝大部分通知既及时又不会被漏掉。
\ No newline at end of file
为了避免重要的通知被漏掉,用户往往还需灵活组合RPC和消息队列。RPC的时效性和开销都明显好于消息队列,但由于内存有限,在重试过一些次数后仍然失败的话,server就得把这部分内存空出来去做其他事情了。这时把通知放到消息队列中,利用其持久化能力做较长时间的重试直至成功,辅以回调的幂等性,就能使绝大部分通知既及时又不会被漏掉。
\ No newline at end of file
[中文版](../cn/server_push.md)
# Server push
What "server push" refers to is: server sends a message to client after occurrence of an event, rather than passively replying the client as in ordinary RPCs. Following two methods are recommended to implement server push in brpc.
## Remote event
Similar to local event, remote event is divided into two steps: registration and notification. The client sends an asynchronous RPC to the server for registration, and puts the event-handling code in the RPC callback. The RPC is also a part of the waiting for the notification, namely the server does not respond directly after receiving the request, instead it does not call done->Run() (to notify the client) until the local event triggers. As we see, the server is also asynchronous. If the connection is broken during the process, the client fails soon and may choose to retry another server or end the RPC. Server should be aware of the disconnection by using Controller.NotifyOnFailed() and delete useless done in-time.
This pattern is similar to [long polling](https://en.wikipedia.org/wiki/Push_technology#Long_polling) in some sense, sounds old but probably still be the most effective method. At first glance "server push" is server visiting client, opposite with ordinary client visiting server. But do you notice that, the response sent from server back to client is also in the opposite direction of "client visiting server"? In order to understand differences between response and push, let's analyze the process with the presumption that "client may receive messages from the server at any time".
* Client has to understand the messages from server anyway, otherwise the messaging is pointless.
* Client also needs to know how to deal with the message. If the client does not have the handling code, the message is still useless.
In other words, the client should "be prepared" to the messages from the server, and the "preparation" often relies on programming contexts that client just faces. Regarding different factors, it's more universal for client to inform server for "I am ready" (registered) first, then the server notifies the client with events later, in which case **the "push" is just a "response"**, with a very long or even infinite timeout.
In some scenarios, the registration can be ignored, such as the [push promise](https://tools.ietf.org/html/rfc7540#section-8.2) in http2, which does not require the web browser(client) to register with the server, because both client and server know that the task between them is to let the client download necessary resources ASAP. Since each resource has a unique URI, the server can directly push resources and URI to the client, which caches the resources to avoid repeated accesses. Similarly, protocols capable of "two-way communication" probably improves efficiencies of pushing in given scenarios such as multimedia streaming or fixed-format key/value pairs etc, rather than implementing universal pushing. The client knows how to handle messages that may be pushed by servers, so extra registrations are not required. The push can still be treated as a "response": to the request that client already and always promised server.
## Restful callback
The client wants a given URL to be called with necessary parameters when the event occurs. In this pattern, server can reply the client directly when it receives the registration request, because the event is not triggered by the end of the RPC. In addition, since the callback is just a URL, which can be stored in databases and message queues, this pattern is very flexible and widely used in business systems.
URL and parameters must contain enough information to make the callback know that which notification corresponds to which request, because the client may care about more than one event at the same time, or an event may be registered more than once due to network jitter or restarting machines etc. If the URL path is fixed, the client should place an unique ID in the registration request and the server should put the ID unchanged in response. Or the client generates an unique path for each registration so that each request is distinguishable from each other naturally. These methods are actually same in essense, just different positions for unique identifiers.
Callbacks should deal with [idempotence](https://en.wikipedia.org/wiki/Idempotence). The server may retry and send more than one notifications after encountering network problems. If the first notification has been successful, follow-up notifications should not have effects. The "remote event" pattern guarantees idempotency at the layer of RPC, which ensures that the done is called once and only once.
In order to avoid missing important notifications, users often need to combine RPC and message queues flexibly. RPC is much better at latency and efficiency than message queue, but due to limited memory, server needs to stop sending RPC after several failed retries and do more important things with the memory. It's better to move the notification task into a persistent message queue at the moment, which is capable of retrying during a very long time. With the idempotence in URL callback, most notifications are sent reliably and in-time.
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment