「Web应用架构」如何扩展WebSockets

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 「Web应用架构」如何扩展WebSockets


当与那些还没有使用过WebSockets的开发人员交谈时,他们通常会有同样的担忧:如何将它扩展到多个服务器上?


发布到一台服务器上的通道是可以的,前提是所有订阅者都连接到那台服务器。一旦您有多个服务器,您就需要添加一些其他的东西。这就是这篇文章试图解决的问题。


缩放HTTP vs WebSockets

要了解为什么扩展WebSockets似乎令人生畏,让我们将其与HTTP进行对比,因为大多数人都很了解它。

使用HTTP,您有一个once off请求/应答模式,您不期望客户机的下一个请求返回到相同的服务器。至少您不应该这样做,因为这意味着您有一个棘手的会话问题,并且您不能轻易地向外扩展以获得性能或冗余。

使用HTTP,您可以在负载均衡器后运行几乎无限数量的web服务器实例。当请求进入时,负载平衡器将请求传递给健康的web服务器实例,并且在web服务器计算完响应后将其传递回客户机。HTTP连接的生命周期通常很短,它们只存在到给出响应为止。这是一种很容易理解的、普遍存在的方法,而且扩展性很好。在长轮询中有一个例外,但它并不常见,对本文也不重要。

另一方面,WebSockets与HTTP请求的区别在于它们是持久的。WebSocket客户端打开一个到服务器的连接并重用它。在这个长时间运行的连接上,服务器和客户机都可以发布和响应事件。这个概念称为双工连接。可以通过负载均衡器打开连接,但一旦打开连接,它就会一直与同一服务器在一起,直到关闭或中断。


这意味着交互是有状态的;对于每个打开的客户端连接,您最终将至少在WebSocket服务器的内存中存储一些数据。例如,您可能知道哪个用户位于套接字的客户端,以及用户感兴趣的是什么类型的数据。


WebSocket连接的持久性使得它在实时应用中如此强大,但这也使得它难以扩展。

一个WebSocket应用程序示例

让我们来讨论一个示例应用程序,这样我们就可以在更具体的上下文中讨论问题和方法。


以我们为例,让我们确定一个协作白板应用程序。在这个应用程序中,有多个白板,这意味着人们可以协作绘制多个草图。当一个用户在一个特定的白板上作画时,它通过一个WebSocket连接发布坐标,并通过WebSocket连接发布到打开相同白板的所有其他用户。换句话说,我们在WebSockets上公开了一个pub/sub模式。


在本例中,这意味着应用程序的每个用户的套接字连接的服务器端至少需要知道用户打开了什么白板。


Web套接字实现,如套接字。io有通道的概念。可以将其视为客户端订阅的地址,服务或其他客户端发布到该地址。


它可能容易认为所有我们需要构建协作白板应用是采用渠道(每个白板都有它自己的通道),然后坐下来放松一下,但你将会看到在这篇文章中,你仍然有问题扩展和容错。

您需要一个发布/订阅代理

首先,我说的“pub/sub broker”是什么意思?有各种各样的技术在相当大的规模上支持发布/订阅模式。

当你需要在套接字上扩展发布/订阅架构时,你需要找到一个好的发布/订阅技术来作为你的解决方案的核心。

我们不需要为这篇文章确定一个特定的选项,但这里有一些不错的选择:Redis, RabbitMQ, Kafka,和RethinkDB。

为了了解为什么我们需要添加一个pub/sub代理来帮助你扩展你的WebSockets,让我们先以一个服务器为背景来考虑我们的例子。

对于一个服务器来说,用WebSockets构建一个发布/订阅服务其实很容易。这是因为在一台服务器上,服务器将知道所有客户机以及客户机感兴趣的数据。

考虑一下我们的示例应用程序。当客户端发送绘图的坐标时,我们只需找到绘图的正确通道,并将对绘图所做的更新发布到该通道。所有的客户端都连接到一台服务器上,因此它们都会得到更改的通知。这有点像内存中的pub/sub。

但在现实中,我们希望跨多个服务器扩展,我们这么做有两个原因:1)共享处理能力,2)冗余。

那么我们怎样才能确保我们的应用扩展?嗯,我们需要一些方法让其他与连接的客户端服务知道数据已经改变。

在构建这样一个应用程序时,你可能已经有了一个数据库,甚至在你开始考虑扩展之前。你不会仅仅信任连接的客户来存储所有图纸的数据。不,您将希望在绘图数据从客户端传入时持久保存它,以便在用户打开绘图时随时提供绘图数据。

但问题来了。如果服务器a上的WebSocket写入一些数据到数据库,服务器B上的WebSocket如何知道去获取数据库的最新数据以便通知它的客户端新的数据?


让我们谈谈在解决方案的中心使用Redis的过程。尽管您的集群中可能有数百个WebSocket服务器,让我们假设您只有3个服务器,这样可以使事情更简单一些。我们将把这些服务器称为WS1、WS2和WS3。有时我会用我的创意名字来给自己取个惊喜!


好,假设你有9个人打开了一幅特定的画,画的是一只狗骑着一匹小马驹骑着一只恐龙,id为abc123保存在你的数据库中。假设有3个人连接到集群中的每个服务器(WS1、WS2、WS3)。


一个连接到WS1的用户在白板上画一些东西。在您的WebSocket服务器逻辑中,您写入数据库,以确保更改已经被持久化,然后根据与绘图相关联的唯一标识符(很可能是基于绘图的数据库id)发布到一个通道。在这个例子中,我们假设通道名是drawing_abc123。


在这一点上,你已经把数据安全地写入数据库,并且你已经发布了一个事件到你的pub/sub代理(Redis频道),通知其他有新数据的相关方。


因为你有用户连接到其他WebSocket服务器(WS2, WS3),对同一个绘图感兴趣,他们将在drawing_abc123通道上开放订阅Redis。他们得到事件的通知,并且每个服务器查询DB更新,并在你的WebSocket层使用的WebSocket通道上发出它。

您可以看到,发布/订阅代理用于允许您通过扩展的WebSocket集群公开发布/订阅模型。

处理故障转移

使用pub/sub代理来协调WebSockets的另一个好处是,现在可以轻松处理故障转移。


当一个客户端连接到一个WebSocket服务器时,该服务器崩溃了,客户端可以通过负载平衡器打开一个连接到另一个WebSocket服务器。新的WebSocket服务器将确保对WebSocket客户端感兴趣的数据的发布/订阅代理有一个订阅,并在WebSocket发生变化时通过管道传输。


使用增量

当客户端重新连接时,需要考虑的一件事是使客户端足够智能,通过某种数据同步偏移量(可能以时间戳的形式)发送,以便服务器不会再次发送所有数据。


如果对图纸的每次更新都打上了时间戳,那么客户端可以很容易地存储他们收到的最新时间戳。当客户端失去了连接到一个特定的服务器,它可以连接到你的websocket集群(通过你的负载平衡器)通过在过去的时间戳,收到这样的查询DB只能建立,这样它会返回更新后出现客户端最后成功收到更新。


在应用程序的负载中,担心副本传到客户机可能并不重要。但即便如此,使用时间戳方法来节省资源和用户的带宽也是一个好主意。


结论

构建运行在一台服务器上的发布/订阅服务相对简单。挑战在于构建一个可以水平伸缩以实现负载共享和容错的服务。


当您向外扩展时,您需要一种方法让web套接字服务订阅已更改的数据,因为对所述数据的更改也将来自其他服务器而不是自身。支持实时查询的数据库非常适合用于此目的,例如RethinkDB。这样你只有WebSockets和你的DB。也就是说,你可能已经在你的环境中使用了支持pub/sub的技术(Redis, RabbitMQ, Kafka),这将比在混合中引入一种新的DB技术更容易销售。


感谢你的阅读!:)如果你喜欢它,请转发,点赞加关注。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1天前
|
前端开发 JavaScript UED
在数字化时代,Web 应用性能优化尤为重要。本文探讨了CSS与HTML在提升Web性能中的关键作用及未来趋势
在数字化时代,Web 应用性能优化尤为重要。本文探讨了CSS与HTML在提升Web性能中的关键作用及未来趋势,包括样式表优化、DOM操作减少、图像优化等技术,并分析了电商网站的具体案例,强调了技术演进对Web性能的深远影响。
10 5
|
11天前
|
缓存 安全 网络安全
HTTP/2与HTTPS在Web加速中的应用
HTTP/2与HTTPS在Web加速中的应用
|
13天前
|
SQL 安全 前端开发
PHP与现代Web开发:构建高效的网络应用
【10月更文挑战第37天】在数字化时代,PHP作为一门强大的服务器端脚本语言,持续影响着Web开发的面貌。本文将深入探讨PHP在现代Web开发中的角色,包括其核心优势、面临的挑战以及如何利用PHP构建高效、安全的网络应用。通过具体代码示例和最佳实践的分享,旨在为开发者提供实用指南,帮助他们在不断变化的技术环境中保持竞争力。
|
14天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
9天前
|
消息中间件 前端开发 JavaScript
探索微前端架构:构建现代Web应用的新策略
本文探讨了微前端架构的概念、优势及实施策略,旨在解决传统单体应用难以快速迭代和团队协作的问题。微前端允许不同团队独立开发、部署应用的各部分,提升灵活性与可维护性。文中还讨论了技术栈灵活性、独立部署、团队自治等优势,并提出了定义清晰接口、使用Web组件、状态管理和样式隔离等实施策略。
|
14天前
|
网络协议 数据挖掘 5G
适用于金融和交易应用的低延迟网络:技术、架构与应用
适用于金融和交易应用的低延迟网络:技术、架构与应用
43 5
|
15天前
|
Go 数据处理 API
Go语言在微服务架构中的应用与优势
本文摘要采用问答形式,以期提供更直接的信息获取方式。 Q1: 为什么选择Go语言进行微服务开发? A1: Go语言的并发模型、简洁的语法和高效的编译速度使其成为微服务架构的理想选择。 Q2: Go语言在微服务架构中有哪些优势? A2: 主要优势包括高性能、高并发处理能力、简洁的代码和强大的标准库。 Q3: 文章将如何展示Go语言在微服务中的应用? A3: 通过对比其他语言和展示Go语言在实际项目中的应用案例,来说明其在微服务架构中的优势。
|
13天前
|
监控 持续交付 Docker
Docker 容器化部署在微服务架构中的应用有哪些?
Docker 容器化部署在微服务架构中的应用有哪些?
|
13天前
|
监控 持续交付 Docker
Docker容器化部署在微服务架构中的应用
Docker容器化部署在微服务架构中的应用
|
20天前
|
监控 前端开发 JavaScript
探索微前端架构:构建可扩展的现代Web应用
【10月更文挑战第29天】本文探讨了微前端架构的核心概念、优势及实施策略,通过将大型前端应用拆分为多个独立的微应用,提高开发效率、增强可维护性,并支持灵活的技术选型。实际案例包括Spotify和Zalando的成功应用。
下一篇
无影云桌面