<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          語雀的技術(shù)架構(gòu)演進(jìn)之路

          共 6132字,需瀏覽 13分鐘

           ·

          2020-09-01 03:32


          每個技術(shù)人心中或多或少都有一個「產(chǎn)品夢」,好的技術(shù)需要搭配好的產(chǎn)品,才能讓用戶愛不釋手,尤其是做一款知識服務(wù)型產(chǎn)品。


          作者何翊宇(花名:不四)是螞蟻金服體驗技術(shù)部高級前端技術(shù)專家語雀產(chǎn)品技術(shù)負(fù)責(zé)人。本文從技術(shù)架構(gòu)的視角,回顧了語雀的原型、內(nèi)部服務(wù)和對外商業(yè)化的全過程,并對函數(shù)計算在語雀架構(gòu)演進(jìn)過程中所扮演的角色做了詳細(xì)的介紹。


          語雀是一個專業(yè)的云端知識庫,用于團(tuán)隊的文檔協(xié)作。現(xiàn)在已是阿里員工進(jìn)行文檔編寫和知識沉淀的標(biāo)配,并于 2018 年開始對外提供服務(wù)。



          1

          原型階段


          | 回到故事的開始。


          2016 年,語雀孵化自螞蟻科技,當(dāng)時,螞蟻金融云需要一個工具來承載它的文檔,負(fù)責(zé)的技術(shù)同學(xué)利用業(yè)余時間,搭建了這個文檔工具。項目的初期,沒有任何人員和資源支持,同時也是為了快速驗證原型,技術(shù)選型上選擇了最低成本的方案。


          底層服務(wù)完全基于體驗技術(shù)部內(nèi)部提供的 BaaS 服務(wù)和容器托管平臺:


          • Object 服務(wù):一個類 MongoDB 的數(shù)據(jù)存儲服務(wù);

          • File 服務(wù):阿里云 OSS 的基礎(chǔ)上封裝的一個文件存儲服務(wù);

          • DockerLab:一個容器托管平臺;



          這些服務(wù)和平臺都是基于 Node.js 實現(xiàn)的,專門給內(nèi)部創(chuàng)新型應(yīng)用使用,也正是由于有這些降低創(chuàng)新成本的內(nèi)部服務(wù),才給工程師們提供了更好的創(chuàng)新環(huán)境。


          語雀的應(yīng)用層服務(wù)端,自然而然的選用了螞蟻體驗技術(shù)部開源的 Node.js Web 框架 Egg(螞蟻內(nèi)部的封裝 Chair),通過一個單體 Web 應(yīng)用實現(xiàn)服務(wù)端。應(yīng)用層客戶端也選用了 React 技術(shù)棧,結(jié)合內(nèi)部的 antd,并采用 CodeMirror 實現(xiàn)了一個功能強大、體驗優(yōu)雅的 markdown 在線編輯器。


          當(dāng)時僅僅是一個工程師的業(yè)余項目,采用內(nèi)部專為創(chuàng)新應(yīng)用提供的 BaaS 服務(wù)和一系列的開源技術(shù),驗證了在線文檔工具這個產(chǎn)品原型。



          2

          內(nèi)部服務(wù)階段


          2017年,隨著語雀得到團(tuán)隊內(nèi)部的認(rèn)可,他的目標(biāo)已經(jīng)不僅僅是金融云的文檔工具,而是成為阿里所有員工的知識管理平臺。不僅面向技術(shù)人員 Markdown 編輯器,還向非技術(shù)知識創(chuàng)作者,提供了富文本編輯器,并選擇了更“Web”的路線,在富文本編輯器中加入了公式、文本繪圖、思維導(dǎo)圖等特色功能。而隨著語雀在知識管理領(lǐng)域的不斷探索,知識管理的三層結(jié)構(gòu)(團(tuán)隊、知識庫、文檔)開始成型。


          | 在此之上的協(xié)作、分享、搜索與消息動態(tài)等功能越來越復(fù)雜單純的依靠 BaaS 服務(wù)已經(jīng)無法滿足語雀的業(yè)務(wù)需求了。


          為了應(yīng)對業(yè)務(wù)發(fā)展帶來的挑戰(zhàn),我們主要從下面幾個點進(jìn)行改造:


          • BaaS 服務(wù)雖然使用簡單成本低,但是它們提供的功能不足以滿足語雀業(yè)務(wù)的發(fā)展,同時穩(wěn)定性上也有不足。所以我們將底層服務(wù)由 BaaS 替換成了阿里云的 IaaS 服務(wù)(MySQL、OSS、緩存、搜索等服務(wù))。

          • Web 層仍然采用了 Node.js 與 Egg 框架,但是業(yè)務(wù)層借鑒 rails 社區(qū)的實踐開始變成了一個大型單體應(yīng)用,通過引入 ORM 構(gòu)建數(shù)據(jù)模型層,讓代碼的分層更清晰。

          • 前端編輯器從 codeMirror 遷移到 Slate。為了更好的實現(xiàn)語雀編輯器的功能,我們內(nèi)部 fork 了 Slate 進(jìn)行深入開發(fā),同時也自定義了一個獨立的內(nèi)容存儲格式,以提供更高效的數(shù)據(jù)處理和更好的兼容性。


          在內(nèi)部服務(wù)階段,語雀已經(jīng)成為了一個正式的產(chǎn)品,通過在阿里內(nèi)部的磨煉,語雀的產(chǎn)品形態(tài)基本定型。


          3

          對外商業(yè)化階段


          隨著語雀在內(nèi)部的影響力越來越大,一些離職出去創(chuàng)業(yè)的阿里校友們開始找到玉伯(螞蟻體驗技術(shù)部研究員):“語雀挺好用的,有沒有考慮商業(yè)化之后讓外面的公司也能夠用起來?”?


          | 經(jīng)過小半年的醞釀和重構(gòu),2018 年初,語雀開始正式對外提供服務(wù),進(jìn)行商業(yè)化。


          當(dāng)一個應(yīng)用走出公司內(nèi)到商業(yè)化環(huán)境中,面臨的技術(shù)挑戰(zhàn)一下子就變大了。最核心的知識創(chuàng)作管理部分的功能越來越復(fù)雜,表格、思維導(dǎo)圖等新格式的加入,多人實時協(xié)同的需求對編輯器技術(shù)提出了更高的挑戰(zhàn)。而為了更好的服務(wù)企業(yè)用戶與個人用戶,語雀在企業(yè)服務(wù)、會員服務(wù)等方面也投入了很大精力。在業(yè)務(wù)快速發(fā)展的同時,服務(wù)商業(yè)化對質(zhì)量、安全和穩(wěn)定性也提出了更高的要求。


          為了應(yīng)對業(yè)務(wù)發(fā)展,語雀的架構(gòu)也隨之發(fā)生了演進(jìn):


          我們將底層的依賴完全上云,全部遷移到了阿里云上,阿里云不僅僅提供了基礎(chǔ)的存儲、計算能力,同時也提供了更豐富的高級服務(wù),同時在穩(wěn)定性上也有保障。


          • 豐富的云計算基礎(chǔ)服務(wù),保障語雀的服務(wù)端可以選用最適合語雀業(yè)務(wù)的的存儲、隊列、搜索引擎等基礎(chǔ)服務(wù);

          • 更多人工智能服務(wù)給語雀的產(chǎn)品帶來了更多的可能性,包括 OCR 識圖、智能翻譯等服務(wù),最終都直接轉(zhuǎn)化成為了語雀的特色服務(wù);


          而在應(yīng)用層,語雀的服務(wù)端依然還是以一個基于 Egg 框架的大型的 Node.js Web 應(yīng)用為主。但是隨著功能越來越多,也開始將一些相對比較獨立的服務(wù)從主服務(wù)中拆出去,可以把這些服務(wù)分成幾類:


          • 微服務(wù)類:例如多人實時協(xié)同服務(wù),由于它相對獨立,且長連接服務(wù)不適合頻繁發(fā)布,所以我們將其拆成了一個獨立的微服務(wù),保持其穩(wěn)定性。

          • 任務(wù)服務(wù)類:像語雀提供的大量本地文件預(yù)覽服務(wù),會產(chǎn)生一些任務(wù)比較消耗資源、依賴復(fù)雜。我們將其從主服務(wù)中剝離,可以避免不可控的依賴和資源消耗對主服務(wù)造成影響。

          • 函數(shù)計算類:類似 Plantuml 預(yù)覽、Mermaid 預(yù)覽等任務(wù),對響應(yīng)時間的敏感度不高,且依賴可以打包到阿里云函數(shù)計算中,我們會將其放到函數(shù)計算中運行,既省錢又安全。


          隨著編輯器越來越復(fù)雜,在 slate 的基礎(chǔ)上進(jìn)行開發(fā)遇到的問題越來越多。最終語雀還是走上了自研編輯器的道路,基于瀏覽器的 Contenteditable 實現(xiàn)了富文本編輯器,通過 Canvas 實現(xiàn)了表格編輯器,通過 SVG 實現(xiàn)了思維導(dǎo)圖編輯器。



          語雀的這個階段(也是現(xiàn)在所處的階段)是商業(yè)化階段,但是我們?nèi)匀槐3至艘粋€很小的團(tuán)隊,通過 JavaScript 全棧進(jìn)行研發(fā)。底層的服務(wù)全面上云,借力云服務(wù)打造語雀的特色功能。同時為企業(yè)級用戶和個人知識工作者者提供知識創(chuàng)作和管理工具。



          4

          和函數(shù)計算的不解之緣


          語雀是一個復(fù)雜的 Web 應(yīng)用,也是一個典型的數(shù)據(jù)密集型應(yīng)用(Data-Intensive Application),背后依賴了大量的數(shù)據(jù)庫等云服務(wù)。語雀服務(wù)端是 Node.js 技術(shù)棧。當(dāng)提到 node 的時候,可能立刻就會有幾個詞浮現(xiàn)在我們腦海之中:單線程(single-threaded)非阻塞(non-blocking)異步(asynchronously programming),這些特性一方面非常的適合于構(gòu)建可擴展的網(wǎng)絡(luò)應(yīng)用,用來實現(xiàn) Web 服務(wù)這類 I/O 密集型的應(yīng)用,另一方面它也是大家一直對 node 詬病的地方,對 CPU 密集型的場景不夠友好,一旦有任何阻塞進(jìn)程的方法被執(zhí)行,整個進(jìn)程就被阻塞。


          像語雀這樣用 node 實現(xiàn)整個服務(wù)端邏輯的應(yīng)用,很難保證不會出現(xiàn)一些場景可能會消耗大量 CPU 甚至是死循環(huán)阻塞進(jìn)程的,例如以 markdown 轉(zhuǎn)換舉例,由于用戶的輸入無法窮舉,總有各種可能讓轉(zhuǎn)換代碼進(jìn)入到一個低效甚至是死循環(huán)的場景之中。在 node 剛出世的年代,很難給這些問題找到完美的解決辦法,而即便是 Java 等基于線程并發(fā)模型的語言,在遇到這樣的場景也很頭痛,畢竟 CPU 對于 web 應(yīng)用來說都是非常重要的資源。而隨著基礎(chǔ)設(shè)置越來越完善,當(dāng)函數(shù)計算出現(xiàn)時,node 最大的短板看起來有了一個比較完美的解決方案。


          阿里云函數(shù)計算是事件驅(qū)動的全托管計算服務(wù)。通過函數(shù)計算,您無需管理服務(wù)器等基礎(chǔ)設(shè)施,只需編寫代碼并上傳,只需要為代碼實際運行所消耗的資源付費,代碼未運行則不產(chǎn)生費用。


          把函數(shù)計算引入之后,我們可以將那些 CPU 密集型、存在不穩(wěn)定因素的操作統(tǒng)統(tǒng)放到函數(shù)計算服務(wù)中去執(zhí)行,而我們的主服務(wù)再次回歸到了 I/O 密集型應(yīng)用模型,又可以愉快的享受 node 給我們帶來的高效研發(fā)福利了!


          以語雀中遇到的一個實際場景來舉例,用戶傳入了一些 HTML 或者 Markdown 格式的文檔內(nèi)容,我們需要將其轉(zhuǎn)換成為語雀自己的文檔格式。在絕大部分情況下,解析用戶輸入的內(nèi)容都很快,然而依然存在某些無法預(yù)料到的場景會觸發(fā)解析器的 bug 而導(dǎo)致死循環(huán)的出現(xiàn),甚至我們不太敢升級 Markdown 解析庫和相關(guān)插件以免引入更多的問題。但是隨著函數(shù)計算的引入,我們將這個消耗 CPU 的轉(zhuǎn)換邏輯放到函數(shù)計算上,語雀的主服務(wù)穩(wěn)定性不會再被影響。



          | 除了幫助 Web 系統(tǒng)分擔(dān)一些 CPU 密集型操作以外,函數(shù)計算還能做什么呢?


          在語雀上我們支持各種代碼形式來繪圖,包括 Plantuml、公式、Mermaid,還有一些將文檔導(dǎo)出成 PDF、圖片等功能。這些場景有兩個特點:


          • 他們依賴于一些復(fù)雜的應(yīng)用軟件,例如 Puppeteer、Graphviz 等;

          • 可能需要執(zhí)行用戶輸入的內(nèi)容;


          支持這類場景看似簡單,通過 process.exec 子進(jìn)程調(diào)用一下就搞定了。但是當(dāng)我們想把它做成一個穩(wěn)定的對外服務(wù)時,問題就出現(xiàn)了。這些復(fù)雜的應(yīng)用軟件可能從設(shè)計上并沒有考慮要長期運行,長期運行時的內(nèi)存占用、穩(wěn)定性可能會有一些問題,同時在被大并發(fā)調(diào)用時,對 CPU 的壓力非常大。再加上有些場景需要運行用戶輸入的代碼,攻擊者通過構(gòu)建惡意輸入,可以在服務(wù)器上運行攻擊代碼,非常危險。


          在沒有引入函數(shù)計算之前,語雀為了支持這些功能,盡管單獨分配了一個任務(wù)集群,在上面運行這些三方服務(wù),接受主服務(wù)的請求來避免影響主服務(wù)的穩(wěn)定性。但是為了解決上面提到的一系列問題還需要付出很大的成本:


          • 需要維持一個不小的任務(wù)集群,盡管可能大部分時間都用不上那么多資源。

          • 需要定時對三方應(yīng)用軟件進(jìn)行重啟,避免長時間運行帶來的內(nèi)存泄露,即便如此有些特殊請求也會造成第三方軟件的不穩(wěn)定。

          • 對用戶的輸入進(jìn)行檢測和過濾,防止黑客惡意攻擊,而黑客的攻擊代碼很難完全防住,安全風(fēng)險依舊很大。



          最后語雀將所有的第三方服務(wù)都分別打包在函數(shù)中,將這個任務(wù)集群上的功能都拆分成了一系列的函數(shù)放到了函數(shù)計算上。通過函數(shù)計算的特點一下解決了上面的所有問題:


          • 函數(shù)計算的計費模式是按照代碼實際運行的 CPU 時間計費,不需要長期維護(hù)一個任務(wù)集群了。

          • 函數(shù)計算上的函數(shù)運行時盡管會有一些常駐函數(shù)的優(yōu)化,但是基本不用考慮長期運行帶來的一系列問題,且每次調(diào)用之間都相互獨立,不會互相影響。

          • 用戶的輸入代碼是運行在一個沙箱容器中,即便不對用戶輸入做任何過濾,惡意攻擊者也拿不到任何敏感信息,同時也無法進(jìn)入內(nèi)部網(wǎng)絡(luò)執(zhí)行代碼,更加安全。


          | 除了上面提到的這些功能之外,語雀最近還使用 OSS + 函數(shù)計算替換了之前使用的阿里云視頻點播服務(wù)來進(jìn)行視頻和音頻的轉(zhuǎn)碼。

          由于瀏覽器可以直接支持播放的音視頻格式并不多,大量用戶上傳的視頻想要能夠直接在語雀上進(jìn)行播放需要對它們進(jìn)行轉(zhuǎn)碼,業(yè)界一般都是通過 FFmpeg 來對音視頻進(jìn)行轉(zhuǎn)碼的。轉(zhuǎn)碼服務(wù)也是一個典型的 CPU 密集型場景,如果要自己搭建視頻轉(zhuǎn)碼集群會面臨大量的資源浪費,而使用阿里云視頻點播服務(wù),成本也比較高,而且能夠控制的東西也不夠多。函數(shù)計算直接集成了 FFmpeg 提供音視頻處理能力,并集成到應(yīng)用中心,配合 SLS 完善了監(jiān)控和數(shù)據(jù)分析。語雀將音視頻處理從視頻點播服務(wù)遷移到函數(shù)計算之后,通過優(yōu)化壓縮率、減少不必要的轉(zhuǎn)碼等優(yōu)化,將費用降低至之前的 1/5。


          從語雀的實踐來看,語雀并沒有像 SFF 一樣將 Web 服務(wù)遷移到函數(shù)計算之上(SFF 模式并不是現(xiàn)在的函數(shù)計算架構(gòu)所擅長的),但是函數(shù)計算在語雀整體的架構(gòu)中對穩(wěn)定性、安全性和成本控制起到了非常重要的作用。總結(jié)下來函數(shù)計算非常適合下面幾種場景:


          • 對于時效性要求不算非常高的 CPU 密集型操作,分擔(dān)主服務(wù) CPU 壓力。

          • 當(dāng)做沙箱環(huán)境執(zhí)行用戶提交的代碼。

          • 運行不穩(wěn)定的三方應(yīng)用軟件服務(wù)。

          • 需要很強動態(tài)伸縮能力的服務(wù)。


          在引入函數(shù)計算之后,語雀現(xiàn)階段的架構(gòu)變成了以一個 Monolith Application 為核心,并將一些獨立的功能模塊根據(jù)使用場景和對能力的要求分別拆分成了 Microservices 和 Serverless 架構(gòu)。應(yīng)用架構(gòu)與團(tuán)隊成員組成、業(yè)務(wù)形態(tài)息息相關(guān),但是隨著各種云服務(wù)與基礎(chǔ)設(shè)施的完善,我們可以更自如的選擇更合適的架構(gòu)。


          為什么要特別把 Serverless 單獨拿出來說呢?還記得之前說 Node.js 是單線程,不適合 CPU 密集型任務(wù)么?


          由于 Serverless 的出現(xiàn),我們可以將這些存在安全風(fēng)險的,消耗大量 CPU 計算的任務(wù)都遷移到函數(shù)計算上。它運行在沙箱環(huán)境中,不用擔(dān)心用戶的惡意代碼造成安全風(fēng)險,同時將這些 CPU 密集型的任務(wù)從主服務(wù)中剝離,避免出現(xiàn)并發(fā)時阻塞主服務(wù)。按需付費的方式也可以大大節(jié)約成本,不需要為低頻功能場景部署一個常駐服務(wù)。所以我們會盡量的把這類服務(wù)都遷移到 Serverless 上(如阿里云函數(shù)計算)。



          5

          結(jié)語 | 語雀的技術(shù)棧選擇


          語雀這幾年一步步發(fā)展過來,背后的技術(shù)一直在演進(jìn),但是始終遵循了幾條原則:


          • 技術(shù)棧選型要匹配產(chǎn)品發(fā)展階段。產(chǎn)品在不同的階段對技術(shù)提出的要求是不一樣的,越前期,對迭代效率的要求越高,商業(yè)化規(guī)模化之后,對穩(wěn)定性、性能的要求就會變高。不需要一上來就用最先進(jìn)的技術(shù)方案,而是需要和產(chǎn)品階段一起考慮和權(quán)衡。

          • 技術(shù)棧選型要結(jié)合團(tuán)隊成員的技術(shù)背景。語雀選擇 JavaScript 全棧的原因是孵化語雀的團(tuán)隊,大部分都是 JavaScript 背景的程序員,同時 Node.js 在螞蟻也算是一等公民,配套的設(shè)施相對完善。

          • 最重要的一點是,不論選擇什么技術(shù)棧,安全、穩(wěn)定、可維護(hù)(擴展)都是要考慮清楚的。用什么語言、用什么服務(wù)會變化,但是這些基礎(chǔ)的安全意識、穩(wěn)定性意識,如何編寫可維護(hù)的代碼,都是決定項目能否長期發(fā)展下去的重要因素。



          本文作者:


          何翊宇,花名不四,高級前端技術(shù)專家,現(xiàn)就職于螞蟻金服體驗技術(shù)部,語雀產(chǎn)品技術(shù)負(fù)責(zé)人。2011 年開始專注在 Node.js 與 Web 研發(fā)領(lǐng)域,負(fù)責(zé)過內(nèi)部的 Node.js 的模塊管理系統(tǒng)和中間件服務(wù)等基礎(chǔ)設(shè)施,也做過 Node.js Web 框架的研發(fā)和開源。同時持續(xù)在使用 Node.js 進(jìn)行產(chǎn)品研發(fā),先后負(fù)責(zé)過淘寶時光機、天貓搭建渲染服務(wù)以及語雀等產(chǎn)品。開源愛好者,Koa.js 和 Egg.js 核心開發(fā)者,cnpm 中國鏡像維護(hù)者。



          往期推薦



          20個使用 Java CompletableFuture的示例,不服不行

          每秒上千訂單場景下的分布式鎖高并發(fā)優(yōu)化實踐!

          「查缺補漏」鞏固你的RocketMQ知識體系

          哇,ElasticSearch多字段權(quán)重排序居然可以這么玩


          后臺回復(fù)?學(xué)習(xí)資料?領(lǐng)取學(xué)習(xí)視頻


          如有收獲,點個在看,誠摯感謝

          瀏覽 34
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  婷婷综合五月天 | 亚洲三级影视 | 亚洲免费观看视频 | 一极a黄色电影 | AV天天艹|