前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我掌握的新兴技术--在线文档的网络层设计思考

我掌握的新兴技术--在线文档的网络层设计思考

原创
作者头像
被删
发布2024-01-30 06:42:26
3280
发布2024-01-30 06:42:26
举报

像在线文档这样大型的项目,不管是从功能职责方面,还是从代码维护方面,分层和分模块都是必然的趋势。而网络层作为与服务端直接连接的一层,有多少是我们可以做到更好的呢?

认识网络层

首先,涉及多人在线协作的场景,从用户交互到服务端存储都会特别复杂。对于前端来说,从后台获取的数据到展示,分别需要经过网络层、数据层和渲染层。除此之外,多人在线同样涉及房间管理等,简单来说,我们大致可以这么进行分层(图1):

图1
图1

网络层职责

一般来说,网络层无非就是做一些与服务端通信的工作,例如发起请求、异常处理、自动重试、登录态续期等。如果说,除了 HTTP 请求,可能还涉及 socket、长连接、请求数据缓存等各种功能。

在多人协作的场景下,为了保证用户体验,一般会采用 OT 算法来进行冲突处理。而为了保证每次的用户操作都可以按照正确的时序来更新,我们会维护一个自增的版本号,每次有新的修改,都会更新版本号。因此,在这样的场景下,网络层的职责大概包括:

  • 校验数据合法性
  • 本地数据准确的提交给后台(涉及队列和版本控制)
  • 协同数据正确处理后分发给数据层(涉及冲突处理)

我们能看到,与网络层有交接的主要包括服务端和数据层。

那么,我们可以考虑将网络层拆分模块:

1. 连接层:管理与服务端的连接(Socket、长连接等)。

2. 接入层:管理数据版本、冲突处理、与数据层的连接等。

这样,我们的分层结构调整为图2:

图2
图2

网络层设计

既然对网络层进行了模块的拆分,那么相关的设计我们也来分模块进行吧。

连接层

连接层作为直接与服务端连接的一层,需要包括以下能力(图3):

  • 多种通信方式支持(长连接、socket、短连接、SSE等)
  • 房间管理(心跳管理、用户管理、消息管理)
图3
图3

1. 多种通信方式支持。

前后端通信方式有很多种,常见的包括 HTTP 短轮询(pollinf)、Websocket、HTTP 长轮询(long-polling)、SSE(Server-Sent Events)等。

我们也能看到,不同的在线文档团队选用的通信方式并不一致。例如谷歌文档上行数据使用 Ajax、下行数据使用 HTTP 长轮询推送;石墨文档上行数据使用 Ajax、下行数据使用 SSE 推送;金山文档、飞书文档、腾讯文档则都使用了 Websocket 传输。

而每种通信方式都有各自的优缺点,包括兼容性、资源消耗、实时性等,也有可能跟业务团队自身的后台架构有关系。因此我们在设计连接层的时候,考虑接口拓展性,应该预留对各种方式的支持。

2. 房间管理。

由于多人协同的需要,相比普通的 Web 页面,还多了房间和用户的管理。在同一个文档中的用户,可视作在同一个房间。除了能看到哪些人在同一个房间以外,我们能收到相互之间的消息,在文档的场景中,用户的每一个操作,都可以作为是一个消息。

但文档和一般的房间聊天不一样的地方在于,用户的操作内容可能会很大,例如用户复制粘贴了一个10W、20W的表格内容,这样的消息显然无法一次性传输完。在这种情况下,除了考虑像 Websocket 这种需要自行进行数据压缩(HTTP 本身支持压缩)以外,我们还需要实现自己的分片逻辑。当涉及数据分片之后,紧接而来的还有如何分片、分片数据丢失的一些情况处理。

这样,我们的连接层则演化成图4的架构:

图4
图4

接入层

接入层主要负责与业务比较相关的一些内容,例如协同数据的版本管理、冲突处理、用户操作的任务队列。我们可以从接收和发送两个方向来进行拆分(图5):

  • 接收数据(服务端 -> 数据层):管理来自服务端的数据
  • 发送数据(数据层 -> 服务端):管理需要提交给服务端的数据
图5
图5

接入层的职责主要包括两个部分:

1. 维护数据任务队列。

  • 用户操作数据正常进入队列
  • 队列任务正常提交到接入层
  • 队列任务提交异常后进行重试
  • 队列任务确认提交成功后移除

2. 数据版本有序递增。

  • 协同数据版本更新
  • 丢失数据版本补拉
  • 提交数据版本递增

也就是说,来自数据层的数据,将会添加到任务队列中。任务队列中的数据在提交数据之前,需要检查本地的版本和服务端的版本是否一致,如果有版本缺失的话,则要先从服务端拉取缺失的版本,确认本地版本最新后,则可以提交到服务端。

而来自服务端的数据,则需要先和任务队列中的数据进行冲突处理。冲突处理完成之后,则会同步到数据层。

这里面其实还有更多的细节,包括队列中任务的状态、任务的合并、数据版本的合并、版本断层的处理、重试失败的处理,队列中任务与协同消息的冲突处理、撤销重做的反向冲突处理,甚至还可能涉及断网离线的操作、本地缓存的任务队列、离线数据与在线数据的同步等等。本文我们就不继续讨论这些细节,还是回归到整体的设计上。

到这,我们的网络层架构大概出来了:

图6
图6

结束语

相比其他常见前端项目,在线文档光是网络层的设计都要复杂很多。而网络层只是其中一小部分,我们还有数据层、渲染层、各个组件和 feature 模块,依赖管理、通信管理、流程控制、性能优化等各种功能模块,每一个都有特别多的挑战。对于前端来说,能参与这样一个项目也是一件很幸福的事情了。

查看Github有更多内容噢: https://github.com/godbasin

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 认识网络层
    • 网络层职责
      • 网络层设计
        • 连接层
      • 接入层
      • 结束语
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
      http://www.vxiaotou.com