偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

如何實(shí)現(xiàn)多人協(xié)作的在線文檔

網(wǎng)絡(luò)
由于業(yè)務(wù)需要,在工作中接觸到了在線文檔、在線Excel。但是在調(diào)研階段發(fā)現(xiàn)國(guó)內(nèi)相關(guān)文章比較匱乏,所以結(jié)合工作實(shí)踐和自己的一些思考,寫幾篇文章剖析實(shí)現(xiàn)在線文檔和在線Excel的一些技術(shù)方案。

由于業(yè)務(wù)需要,在工作中接觸到了在線文檔、在線Excel。但是在調(diào)研階段發(fā)現(xiàn)國(guó)內(nèi)相關(guān)文章比較匱乏,所以結(jié)合工作實(shí)踐和自己的一些思考,寫幾篇文章剖析實(shí)現(xiàn)在線文檔和在線Excel的一些技術(shù)方案。為了避免涉及到公司隱私,所以文章中一些數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)和非關(guān)鍵場(chǎng)景都寫的比較簡(jiǎn)略。我們主要從需求分析、方案設(shè)計(jì)、技術(shù)選型等幾個(gè)方面介紹如何實(shí)現(xiàn)多人協(xié)作的在線文檔。

需求分析

我們借鑒領(lǐng)域驅(qū)動(dòng)模型的思路進(jìn)行需求分析。需求中包含「人」「文檔」兩個(gè)實(shí)體。「人」的主要屬性有:用戶ID、用戶名。「文檔」的主要屬性有:文檔ID、文檔內(nèi)容、創(chuàng)建者、創(chuàng)建時(shí)間。人和文檔的關(guān)系非常簡(jiǎn)單:一個(gè)人可以有多個(gè)文檔,一個(gè)文檔只歸屬某一個(gè)人,屬于一對(duì)多的關(guān)系。

因?yàn)槲臋n內(nèi)容不能被隨便閱讀和修改,所以還要有權(quán)限管理,「權(quán)限」是一種值對(duì)象。權(quán)限的值有:閱讀、編輯。人對(duì)文檔可以有閱讀權(quán)限或編輯權(quán)限。

還有一個(gè)最關(guān)鍵的問題就是「協(xié)作」。協(xié)作是多個(gè)「人」,對(duì)一篇文檔同時(shí)操作。協(xié)作的過程中需要把多個(gè)人編輯的內(nèi)容,經(jīng)過合并轉(zhuǎn)換為最終保存的文檔內(nèi)容。協(xié)作的過程中需要讓文檔編輯人員看到當(dāng)前「一起協(xié)作的對(duì)象」和協(xié)作對(duì)象「實(shí)時(shí)編輯的內(nèi)容」

為了實(shí)現(xiàn)以上功能我們把系統(tǒng)拆分成五大模塊:人員管理、文檔管理、權(quán)限管理、協(xié)作和前端文檔編輯器。

方案設(shè)計(jì)

人員管理

因?yàn)槿藛T管理不是本文的重點(diǎn),所以我們只做一個(gè)簡(jiǎn)要的設(shè)計(jì),主要是為了輔助說明后面的設(shè)計(jì)。

表結(jié)構(gòu)主要字段有:

下面介紹下該模塊的主要邏輯。

用戶注冊(cè)

  1. 前端把用戶填寫的用戶名、密碼、手機(jī)號(hào)等信息加密后發(fā)送給服務(wù)端。
  2. 服務(wù)端拿到數(shù)據(jù),再和生成的唯一用戶ID一起,存入表中。

用戶登錄

  1. 前端要求用戶輸入用戶名+密碼并發(fā)送給服務(wù)端,服務(wù)端校驗(yàn)用戶名和密碼的正確性。
  2. 校驗(yàn)通過后,根據(jù)「用戶名+密碼+密鑰+時(shí)間戳」生成有時(shí)效性的Token,返回給客戶端。
  3. 登錄之后前端所有請(qǐng)求都帶著Token信息。服務(wù)端根據(jù)Token獲取當(dāng)前登錄用戶信息并判斷請(qǐng)求是否合法。

文檔管理

文檔的表結(jié)構(gòu)設(shè)計(jì):

下面介紹下該模塊的主要邏輯。

創(chuàng)建文檔

  1. 前端發(fā)送文檔名稱、文檔內(nèi)容給服務(wù)端
  2. 服務(wù)端生成唯一的文檔ID,從Token中獲取到用戶ID,獲取服務(wù)器時(shí)間然后把數(shù)據(jù)一起存入數(shù)據(jù)庫(kù)中
  3. 服務(wù)端返回文檔ID給前端

修改文檔

這里的修改是指修改文檔的內(nèi)容。我們?yōu)榱思皶r(shí)保存用戶編輯的內(nèi)容,需要在用戶編輯過程中實(shí)時(shí)把數(shù)據(jù)傳遞給服務(wù)端。如果每次都發(fā)送全部文檔內(nèi)容給服務(wù)端,雖然服務(wù)端的處理邏輯會(huì)比較簡(jiǎn)單,但是每次請(qǐng)求都有很多冗余數(shù)據(jù),浪費(fèi)大量的帶寬。所以我們最好只發(fā)送變化的內(nèi)容給服務(wù)端,讓服務(wù)端根據(jù)當(dāng)前文檔內(nèi)容和變化內(nèi)容合并生成最新的文檔內(nèi)容。

如何發(fā)送變化的內(nèi)容呢?我們可以把用戶對(duì)文檔內(nèi)容的操作分成三類:「新增、修改、刪除」。新增就是給文檔添加內(nèi)容,修改就是修改文檔的某一段內(nèi)容,刪除就是刪除了文檔的某一段內(nèi)容。對(duì)這三類操作我們可以使用Json形式來表示:

  1. {  
  2.   op:""// 操作 add:新增,update:修改, delete:刪除     
  3.   start:""// 開始位置下標(biāo)     
  4.   end: ""// 結(jié)束位置下標(biāo)     
  5.   text:""// 修改內(nèi)容 

這樣修改文檔的流程就是

  1. 前端生成修改數(shù)據(jù)發(fā)送給服務(wù)端
  2. 服務(wù)端從數(shù)據(jù)庫(kù)中獲取文檔內(nèi)容,然后根據(jù)用戶的行為合并操作,最后保存到數(shù)據(jù)庫(kù)中。

用戶在編輯一篇文章時(shí),往往需要很多次數(shù)據(jù)傳輸。Json的數(shù)據(jù)格式雖然能很好的表達(dá)語(yǔ)意,但是每次傳輸也需要發(fā)送較多的字節(jié),浪費(fèi)帶寬;而且Json的序列化和反序列化過程也相對(duì)低效。我們可以采用Google的Protobuf協(xié)議來代替,它是基于二進(jìn)制的傳輸協(xié)議,在傳輸內(nèi)容大小和解析速度上都強(qiáng)于Json。

  1. message Doc {     
  2.   enum Op{         
  3.     add:0;         
  4.     update:1;         
  5.     delete:2;     
  6.   }     
  7.   required Op op = 0;     
  8.   required int32 start = 1;        
  9.   required int32 end = 5;     
  10.   string text = "修改內(nèi)容"     

這里協(xié)議比較簡(jiǎn)單,自己按照規(guī)則拼接字符串也是可以的。考慮到后續(xù)功能的可擴(kuò)展性,還是建議采用Protobuf協(xié)議。

修改文檔的流程還有順序問題,我們假設(shè)用戶的操作是這樣的:

  1. 用戶先刪除了5個(gè)字“12345”
  2. 添加了5個(gè)字“一二三四五”
  3. 又修改了其中的前兩個(gè)字是“你好”

正常順序下最后的結(jié)果是:「你好三四五」。但是如果服務(wù)端的執(zhí)行順序變成了3、1、2,那最后的結(jié)果變成了:「一二三四五」。這顯然是不符合預(yù)期的。所以我們要保證服務(wù)端順序處理前端發(fā)過來的請(qǐng)求。

保證順序執(zhí)行有幾個(gè)方案:

  1. 前端請(qǐng)求由異步變成同步
  2. 前端每次請(qǐng)求都生成連續(xù)遞增的ID,服務(wù)端判斷如果遞增ID不連續(xù)了,就短暫的等待
  3. 把對(duì)同一個(gè)文檔的操作代理到同一個(gè)服務(wù)器,服務(wù)端單進(jìn)程接收請(qǐng)求,并把數(shù)據(jù)存入有序隊(duì)列。隊(duì)列的消費(fèi)端正常消費(fèi)就可以了。

方案一在請(qǐng)求多的時(shí)候,處理效率太低會(huì)影響用戶體驗(yàn),可以直接排除掉。方案二主要依賴客戶端生成遞增ID,是比較不錯(cuò)的方案。方案三依賴單進(jìn)程和有序隊(duì)列保證順序。雖然單進(jìn)程在并發(fā)量高的情況下很難抗壓,但是如果根據(jù)文檔ID去做負(fù)載均衡也可以比較好的控制流量,畢竟對(duì)一個(gè)文檔的修改QPS也高不到哪去。
當(dāng)然也可以把方案二和方案三結(jié)合使用。

查看文檔

  1. 前端發(fā)送要查看的文檔ID給服務(wù)端
  2. 服務(wù)端根據(jù)文檔ID返回文檔內(nèi)容

刪除文檔

  1. 前端發(fā)送要?jiǎng)h除的文檔ID給服務(wù)端
  2. 服務(wù)端根據(jù)文檔ID刪除對(duì)應(yīng)文檔

權(quán)限管理

當(dāng)前需求的權(quán)限場(chǎng)景特別適合「ABAC」的權(quán)限模型。
用戶屬性:只要是正常登錄用戶即可
環(huán)境屬性:普通的文檔內(nèi)容
操作屬性:文檔的讀和寫
對(duì)象屬性:文檔

所以,我們存儲(chǔ)權(quán)限信息的表結(jié)構(gòu)主要字段有:

下面介紹下該模塊的主要邏輯。

開通權(quán)限

  1. 前端發(fā)送文檔ID和權(quán)限類型(讀/寫)給服務(wù)端
  2. 服務(wù)端根據(jù)文檔ID和Token中的用戶ID,在權(quán)限表中添加記錄,并返回成功

刪除權(quán)限

  1. 前端發(fā)送文檔ID和權(quán)限類型(讀/寫)給服務(wù)端
  2. 服務(wù)端根據(jù)文檔ID和Token中的用戶ID,在權(quán)限表中刪除記錄,并返回成功

校驗(yàn)權(quán)限

我們可以實(shí)現(xiàn)一個(gè)中間鍵,當(dāng)用戶請(qǐng)求某文檔內(nèi)容時(shí),判斷其是否為創(chuàng)建者。如果不是再?gòu)臋?quán)限表中查詢用戶是否有權(quán)限查看或者編輯權(quán)限。修改文檔內(nèi)容時(shí)也是同樣的邏輯,就不再贅述了。

協(xié)作

合并沖突

當(dāng)多個(gè)人同時(shí)修改一個(gè)文檔時(shí),處理內(nèi)容沖突的幾種方式:

  1. 文檔加鎖:當(dāng)有人修改文檔時(shí),對(duì)整個(gè)文檔加寫鎖,別人都只能看不可編輯。雖然實(shí)現(xiàn)簡(jiǎn)單,不過協(xié)作的體驗(yàn)會(huì)特別差。
  2. diff+patch的合并算法:diff+patch是常用的文檔內(nèi)容比較和合并算法,Linux本身就提供了diff和patch命令支持文件的比較和合并。git也使用了diff+patch方法來合并文件,當(dāng)無法解決沖突時(shí),會(huì)把沖突拋給用戶手動(dòng)合并。
  3. OT算法:相比diff+patch來講OT算法往往能帶來更好的合并結(jié)果。不過OT算法的實(shí)現(xiàn)也更復(fù)雜一些。目前Google文檔、騰訊文檔、石墨文檔等都是采用了OT算法。我們后面單獨(dú)寫文章來聊一聊diff+patch和OT算法。

協(xié)作通知

為了更好的協(xié)作,文檔編輯者需要看到同時(shí)編輯文檔的人,還需要看到別人修改的內(nèi)容,來減少?zèng)_突,達(dá)到協(xié)作的目的。

大家打開文檔編輯頁(yè)面的時(shí)間是不同步的,為了讓大家「互相看到」,而且互相看到對(duì)方「修改的內(nèi)容」,就需要服務(wù)端主動(dòng)給客戶端推送消息。此場(chǎng)景下采用長(zhǎng)鏈接的方案是比較合適的。

前文也提到過,文檔修改頻繁的時(shí)候,發(fā)送數(shù)據(jù)的頻次會(huì)很高,如果是HTTP請(qǐng)求會(huì)導(dǎo)致每次請(qǐng)求都攜帶頭信息,建立連接等開銷,所以修改文檔內(nèi)容的數(shù)據(jù)上報(bào)也可以采用長(zhǎng)鏈接。同時(shí),服務(wù)端維護(hù)一個(gè)「協(xié)作列表」來存放所有正在被編輯的文檔和每個(gè)文檔的在線用戶,可以類比為一個(gè)聊天室。

文檔修改者加入

  1. 前端打開一個(gè)文檔時(shí),發(fā)送請(qǐng)求給服務(wù)端,服務(wù)端檢查協(xié)作列表中是否有當(dāng)前文檔。
  2. 如果有則把當(dāng)前用戶加入此文檔修改者列表;如果沒有就把當(dāng)前文檔加入?yún)f(xié)作列表,同時(shí)把當(dāng)前用戶ID寫入其中。
  3. 服務(wù)端通過長(zhǎng)鏈接給文檔列表中的所有其他用戶推送消息,告知大家有用戶加入?yún)f(xié)作。

文檔修改者退出邏輯和加入基本相同就不再贅述了。

「修改內(nèi)容」

  1. 前端把修改數(shù)據(jù)發(fā)送給服務(wù)端
  2. 服務(wù)端暫存多個(gè)用戶的操作,并根據(jù)OT算法把用戶操作合并,最后和數(shù)據(jù)庫(kù)存儲(chǔ)的文檔內(nèi)容合并
  3. 把合并完的文檔內(nèi)容保存到數(shù)據(jù)庫(kù)中
  4. 服務(wù)端根據(jù)文檔ID,讀取協(xié)作列表中的用戶,給所有用戶發(fā)送合并結(jié)果
  5. 客戶端把合并結(jié)果與本地文檔內(nèi)容合并

文檔編輯器

「編輯功能」

文檔編輯器需要支持,文檔內(nèi)容編輯、文字樣式調(diào)整、插入圖片、插入鏈接等一系列功能。 實(shí)現(xiàn)內(nèi)容可編輯的方案有textarea標(biāo)簽和contenteditable屬性可以選擇。但是textarea標(biāo)簽對(duì)其他需求的實(shí)現(xiàn)很難支持,而且不方便控制。所以我們選用contenteditable=true來實(shí)現(xiàn)文檔內(nèi)容的編輯。

「上報(bào)功能」

文檔修改時(shí),內(nèi)容的上報(bào),需要文檔編輯器處理好。不能用戶每輸入一個(gè)字符就上報(bào)一次,這樣頻繁的發(fā)送數(shù)據(jù)會(huì)給服務(wù)端帶來很大壓力,也是沒有必要的。所以客戶端的上報(bào)需要做防抖處理。上報(bào)的過程中有可能會(huì)因?yàn)榫W(wǎng)絡(luò)閃斷等原因?qū)е律蠄?bào)失敗,此時(shí)需要重試。

服務(wù)可能因?yàn)殚L(zhǎng)時(shí)間的網(wǎng)絡(luò)中斷或者服務(wù)器異常導(dǎo)致數(shù)據(jù)上報(bào)失敗。此時(shí)前端可以先把用戶修改存儲(chǔ)在瀏覽器本地的LocalStorage中,不過需要注意瀏覽器本地緩存通常有5M的大小限制。本地存儲(chǔ)除了在網(wǎng)絡(luò)異常時(shí)發(fā)揮作用,在實(shí)現(xiàn)Ctrl+Z操作時(shí),也可以起到記錄之前操作的作用。

「長(zhǎng)鏈接」

需要有一個(gè)單獨(dú)的模塊管理長(zhǎng)鏈接,統(tǒng)一處理上報(bào)的接口和服務(wù)端下發(fā)的數(shù)據(jù),做好數(shù)據(jù)的封裝和解析;并及時(shí)的反饋給用戶連接成功、數(shù)據(jù)保存成功、連接異常等信息。

「大文檔的加載」

對(duì)于大文檔的加載,我們需要做異步處理。根據(jù)滾動(dòng)條滾動(dòng)的位置,在服務(wù)端異步的獲取更多數(shù)據(jù)。

「其他功能」

前端編輯器的其他模塊我們可以根據(jù)其功能范圍拆分:比如控制文字大小、顏色的功能模塊;控制文字對(duì)齊方式的模塊;控制插入內(nèi)容的模塊;支持Ctrl+C、Ctrl+V、Ctrl+Z的模塊等等。拆分好之后根據(jù)功能實(shí)現(xiàn)就可以了,這里就不一一分析了。

技術(shù)選型

「存儲(chǔ)」

存儲(chǔ)方面,當(dāng)前場(chǎng)景使用關(guān)系型數(shù)據(jù)庫(kù)比較合適。我們可以根據(jù)文檔和用戶的數(shù)量級(jí)選擇合適的數(shù)據(jù)庫(kù)。通常千萬(wàn)級(jí)別的數(shù)據(jù)量選擇MySQL就可以了,如果數(shù)據(jù)更多的話我們可以選擇TIDB或者M(jìn)ySQL分庫(kù)分表的方案。
當(dāng)然采用MongoDB和PG也都可以滿足需求,我們可以結(jié)合公司的DBA運(yùn)維能力自行選擇。

補(bǔ)充一下,如果考慮文檔內(nèi)容的搜索,只選擇一種存儲(chǔ)結(jié)構(gòu)是不夠的。需要單獨(dú)為文檔建立索引,可以選擇使用ES集群為文檔創(chuàng)建全文索引。而且索引的創(chuàng)建和MySQL的增刪改比起來是比較耗時(shí)的操作,所以創(chuàng)建索引往往放在異步流程中。而且用戶創(chuàng)建一個(gè)文檔也很少立馬就對(duì)它搜索。

「長(zhǎng)鏈接」

當(dāng)前常用的長(zhǎng)鏈接方案主要有“HTTP/2 + SSE”和WebSocket兩種,WebSocket更成熟一些,優(yōu)先選擇。

「消息隊(duì)列」

建議采用RocketMQ,因?yàn)?/p>

  1. RocketMQ支持同步/異步刷盤,支持同步/異步寫副本,消息的可靠性更有保障。
  2. RocketMQ支持順序消息。

當(dāng)然寫入性能方面要比Kafka弱一些。但是在線文檔的場(chǎng)景里,消息的可靠性和順序更加重要。

架構(gòu)設(shè)計(jì)

基于上面的分析,我們?cè)O(shè)計(jì)的部署架構(gòu)圖如下

其中,接入層負(fù)責(zé)用戶的鑒權(quán)和長(zhǎng)鏈接保持;其他各模塊負(fù)責(zé)各自的功能。文檔修改的隊(duì)列我們采用MQ發(fā)送,文檔管理模塊消費(fèi)。Redis我們用來存放多人協(xié)作時(shí)的文檔和用戶對(duì)應(yīng)關(guān)系。當(dāng)然數(shù)據(jù)量不大時(shí)MQ也可以使用Redis臨時(shí)代替。

總結(jié)

以上就是我對(duì)多人協(xié)作在線文檔的分析和設(shè)計(jì)方案,其中包含了前后端交互流程、文檔的存儲(chǔ)和服務(wù)的部署方案。為了突出主要問題和邏輯,文中很多設(shè)計(jì)和技術(shù)點(diǎn)都是點(diǎn)到為止,給大家造成困擾的地方大家可以自行搜索下關(guān)鍵字或者留言交流。

責(zé)任編輯:梁菲 來源: 一行舟
相關(guān)推薦

2021-09-08 15:43:03

在線寫作協(xié)作文檔辦公軟件

2011-11-30 16:37:58

sync

2021-03-28 17:21:15

Git分支策略

2021-08-30 17:35:17

開發(fā)在線文檔多人協(xié)作

2011-11-30 16:08:14

YC新銳Stypi

2022-03-04 09:02:01

StoryBoard工具git

2012-06-12 09:51:43

在線思維

2011-11-30 15:57:18

2021-08-30 14:41:16

在線文檔協(xié)同辦公騰訊文檔

2016-11-10 07:50:55

群暉云端Office

2009-07-14 08:26:46

微軟網(wǎng)絡(luò)版Office網(wǎng)絡(luò)版Office功能Office 2010

2011-11-30 16:06:16

20個(gè)實(shí)用的在線協(xié)作

2011-11-30 15:57:18

談企業(yè)協(xié)同應(yīng)用

2011-11-30 16:20:56

20款免費(fèi)或廉價(jià)的在線

2021-08-30 16:48:24

在線文檔

2011-11-30 15:28:32

在線協(xié)作系統(tǒng)

2023-11-27 00:50:50

Google系統(tǒng)

2020-02-05 18:24:24

飛書

2011-11-30 16:21:32

5款在線協(xié)作數(shù)字白板
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)