前言: 作为学期项目的一部分,我和几个朋友决定建立一个具有实时更新功能的票务系统。这个项目给我们带来了各种产品层面和技术层面的挑战,我们经历了一段相当艰苦的旅程。我负责项目的后端开发,在实施系统的过程中遇到了很多障碍和挑战,我将尝试解释其中的一些问题以及我想到的解决方案。
因此,你需要从服务器上实时更新一些数据,可能是股票价格,可能是比分更新,也可能是公交车上的剩余座位数(我的例子),还希望在服务器上执行一些操作,如购买股票、查看球队详情或预订车票等等。我们该如何高效地完成这些操作呢?
选择一种有效的方式与服务器交换信息确实取决于使用案例,而面对众多的选择,这可能是一项艰巨的任务,让我们从探索从服务器获取实时更新的所有选项开始。
有几种方法可以实时从服务器获取更新,它们是:
- HTTP Polling (短轮询和长轮询)
- WebHooks
- WebSockets
- gRPC
- Server-Sent-Events (SSE:服务器发送事件)
由于它们都有不同的用途,因此并不具有直接可比性,但由于我们使用它们的目的相同,即实时获取更新,因此我们可以尝试进行比较。
首先,这是什么?
这是所有这些通信方法在用于实时从服务器获取更新时的比较。
如何使用?
颜色表示某种方法相对于其他方法的效果,至于为什么我觉得这种方法相对于其他方法效果好或不好,方框里都有说明。所有这些方法以及实现这些方法所需的设置都是我进行比较的标准。
如果你对这些方法完全不熟悉,让我们先来看看这些方法的简要介绍,然后你就可以自己得出这些结论了。在每种方法中,我都会提到一个 IMO(我的观点),你可以作为参考来决定你应该使用哪种方法。这是否意味着你必须相信我的话?不,我在这里的任务是整合我的研究成果,这样您就可以做出推断,并挑选出几款产品供您自行决定,从而帮助您决定要在哪些方面做出取舍,是的,它们都有一个取舍标准。
最后,我将分享我的一些见解,也许能帮助你决定什么才是你的应用程序的正确选择。
1. HTTP 短轮询
以固定的时间间隔向服务器发送重复的 HTTP 请求。
优点:
- 实现简单,因为它利用标准 HTTP 请求。
- 适用于各种浏览器和平台。
缺点:
- 即使没有更新,也会产生大量不必要的网络流量。
- 根据轮询间隔,实时更新可能会出现延迟。
- 由于请求频繁,会给服务器带来额外负担。
合适的用例:适用于每次请求都需要更新数据的场景,如火车或出租车位置跟踪。
IMO:适用于始终需要更新且可以确定更新频率的情况。
2. HTTP长轮询
发送长期 HTTP 请求,除非有更新或资源可用,否则服务器不会响应。
优点:
- 与短轮询相比,可实现实时更新并减少延迟。
- 在更新发生前保持连接开放,从而减少不必要的网络流量。
缺点:
- 与传统轮询相比,服务器负载增加,因为连接保持打开状态的时间更长。
- 需要更复杂的服务器端实现来处理长期连接。
合适的用例:非常适合数据更新不频繁的情况,例如聊天应用程序或推送通知。
IMO:如果更新过于频繁,或无法确定更新频率,请勿使用(以票务应用程序为例,我无法预测买票的频率,如果更新过于频繁,就会产生与短轮询类似的流量)。
3. Webhooks
基于事件触发的 HTTP 请求,其作用就像一个挂有绳子并挂在铃铛上的钩子。当绳子被拉动时,铃声就会响起。
优点:
- 提供实时更新,无需连续轮询。
- 允许以有效负载的形式交换数据,提供更多的事件上下文。
缺点:
- 要求发布者和订阅者设置和维护 Webhook 端点,包括身份验证和错误处理。
- 要求接收者公开端点以接收 Webhook 通知。
合适的用例:通常用于发送通知或根据特定事件执行操作,例如在事务发生时发送电子邮件或发送推送通知。
IMO:用于服务器到服务器的一般通信是有原因的,构建和设置 webhooks 基础设施、确保端点安全等可能会很棘手,不是你在早期就想要的。
4. gRPC
由 Google 开发的远程过程调用 (RPC) 实现,支持单向和双向通信。
优点:
- 通过在不同系统间调用函数,实现高效通信。
- 与 REST 通信相比更快、更轻。
- 提供更强的安全功能。
缺点:
- 实现复杂度较高,需要定义protobuf(数据结构和服务)。
- 对平台尤其是浏览器的支持有限
合适的用例:适合安全性和速度优先且有足够实施时间的微服务通信。
IMO:只有当你有时间建立和维护基础设施,并且你的平台和框架支持 gRPC 时才可以使用。
5. WebSocket
提供全面的双向通信支持,建立初始 HTTP 连接,并为持续的数据传输维护一个持久的 TCP 连接。
优点:
- 支持客户端和服务器之间的实时、全双工通信。
- 支持本地浏览器,易于集成。
- 流行的 WebSocket 库可用于多种编程语言。
缺点:
- 需要在服务器和客户端上设置和处理事件架构。
- 由于每台机器 65535 个连接的限制,可扩展性可能会成为一个问题。
合适的用例:非常适合需要真正的双向通信,例如在多人游戏或实时聊天应用程序中。
IMO:当需要双向通信,并且有时间设置整个事件架构时(一般包括规划要发出和消耗的事件,以及验证,如果要在每个事件上都进行验证,则验证并非轻而易举的事)
6. 服务器发送事件(SSE)
一种简单的、长期存在的 HTTP 连接,允许服务器在需要时随时向客户端发送数据,提供服务器到客户端的单向通信。
优点:
- 为服务器到客户端通信提供易于实施的解决方案,无需额外设置。
- 适用于需要不同频率更新的场景。
缺点:
- 仅限于从服务器到客户端的单向通信。
- 每个浏览器的 SSE 连接数量是有限的(通常约为 6 个)。
合适的用例:适用于需要服务器到客户端持续更新的场景,如股票行情更新或板球比分更新。
IMO:当你想获得频率不一致的更新,又不想麻烦地为套接字或 gRPC 做额外设置时使用。
既然理论已经讲完了,我们来看看你到底应该怎么做。就像软件开发中的所有事情一样,这也没有直接的解决方案,也没有对错之分,你必须根据我提供的比较或这些方法的一般用例来评估什么最适合你的需求,我能提供给你的是我如何解决我的具体问题的见解。
当然,对于像 WebHooks 和 SSE 这样提供单向通信的方法,你需要将其与 HTTP REST 进行分层,以进行粗略的操作。
在我的案例中,我需要实时从服务器获取有关座位空缺的更新信息,并执行一些操作,如预订机票和查看交易,在对所有这些方法进行研究并考虑了这些方法的优缺点后,我得出了以下解决方案。
HTTP REST + SSE
一种合理的方法是使用服务器发送事件(SSE)来传输更新,而所有其他操作则完全通过 REST 进行。你可以获得实时更新,不需要进行任何复杂的设置,也不会向服务器发出大量请求,这种方法相当简单。
HTTP REST + Sockets
当你面对机器 TCP 端口(65535)的物理限制时,单台机器的扩展就成了问题,因此有必要限制那些宝贵的套接字连接。因此,我决定进行优化,将对 REST API(登录、重置密码、注册)的授权请求和其他通信转移到套接字连接上,因为这样可以确保用户有效并已登录。但为什么要这么做呢?如果有像 SSE 这样更容易实现的解决方案,为什么还要这样做呢?这是矫枉过正,因为大部分时间连接都是空闲的。没错,但使用套接字可以为集成更多实时功能提供空间,如果我想在系统中集成实时聊天功能,或将产品游戏化,那么就可以使用套接字,因为它可以让以后实现这些功能变得更容易。
正如你所看到的,这非常依赖于用例。
同样,也可以将 REST + WebHooks 分层,或者只使用 gRPC,或者只使用 WebSockets,这完全取决于你想要优化的程度、你的取舍以及愿意为此付出的代价。
这些例子仅仅是表面现象,因为可以灵活地分层和混合这些通信协议,以满足你的特定需求。
通过对这些方法进行深思熟虑的混合,你可以实现适合自己独特情况的最佳解决方案。
作者:Aryan Wadkar
本文为原创稿件,版权归作者所有,如需转载,请注明出处:https://www.nxrte.com/jishu/im/29332.html