日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

百度十亿级流量的搜索前端,是怎么做架构升级的?

發(fā)布時間:2025/3/16 HTML 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 百度十亿级流量的搜索前端,是怎么做架构升级的? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Harttle

百度資深研發(fā)工程師,北京大學物理學學士和計算機科學碩士。2016年加入百度,曾負責和參與百度搜索Web極速瀏覽框架、MIP開源項目的研發(fā),目前負責搜索結(jié)果頁和搜索推薦業(yè)務。LiquidJS 的作者,貢獻于San、Realworld Apps、hightlight.js、ALE、HTML5 Standard等項目。

導讀:前端發(fā)展飛速,從最開始的靜態(tài)頁面到 JavaScript,再從 PC 端到移動端,隨著大前端的復雜度不斷提升,很多公司開始前后端分離,剝離出前、后端架構(gòu)設計。那我們來看看,前端架構(gòu)設計是什么?曾經(jīng)非常簡單的前端架構(gòu)發(fā)展到現(xiàn)在有哪些問題,遇到前端代碼體量巨大、跨團隊協(xié)作效率、代碼耦合、技術(shù)棧落后等問題又該怎么解決?

一、什么是前端架構(gòu)?

前端架構(gòu)這一詞,相信很多人的定義都不太一樣;按照拆詞的解釋來看,我理解為“前端”+“架構(gòu)”。前端是指,Web 端的前臺頁面,包括網(wǎng)頁的內(nèi)容、樣式、腳本等,這三者通常封裝在組件中,可能是模板引擎的文件模塊,也可能是 MVVM 框架里的組件。“架構(gòu)”就更好理解了,架構(gòu)一詞來自建筑行業(yè),可以理解是房屋的整體結(jié)構(gòu)、框架。結(jié)合前端和架構(gòu)的概念,“前端架構(gòu)”可以理解為,Web 頁面組件的抽象和組織方式。

又因為各個公司的業(yè)務不同,每個公司的前端架構(gòu)發(fā)展都不一樣,這里,我會拿百度移動端經(jīng)典的搜索場景來給大家舉例,希望從百度的移動端架構(gòu)演進過程中,發(fā)現(xiàn)一些共性的問題。


二、百度移動端背景及問題


為什么是以百度來舉例?是因為百度是國內(nèi)搜索引擎的領頭人,并且,目前一直處于行業(yè)領先狀態(tài)。據(jù) statcounter 前瞻產(chǎn)業(yè)研究院在 2019 年中國搜索引擎行中可以知道,百度搜索占全世界搜索引擎市場份額12.3%,居第二位,僅次于谷歌。所以用百度來舉例,更具有代表性。

言歸正傳,打開百度 App 你會發(fā)現(xiàn),百度前端直接分為首頁和搜索結(jié)果頁,搜索結(jié)果頁是搜索的主要入口,每天承載著十億級流量。

不僅如此,搜索結(jié)果頁承載著許多產(chǎn)品線的需求和下游模塊的運行時,每年內(nèi)部的研發(fā)人員會提供五百多個產(chǎn)品需求,為十幾個下游模塊提供基礎庫和運行時。甚至還有后端協(xié)同,從圖 1 我們可以看出結(jié)果頁的整體架構(gòu)。


△圖 1:百度搜索結(jié)果頁的整體架構(gòu)

針對整體的架構(gòu)設計,有這些問題:

  • 細分業(yè)務線眾多,單個庫代碼龐大;

  • 平均每月有 200+ 提交,3w+ 行代碼;

  • 80+ 開發(fā)者在同一個代碼庫中開發(fā);

  • 沒有人能完全掌握模塊整體技術(shù)。

于是,梳理出三個方面的問題:

1. 人員職責不清晰,單個模塊同時承擔了多個團隊的職責

  • 框和 Tab:“全部”和垂類搜索共用;

  • 運營產(chǎn)品:滲透在結(jié)果頁代碼庫里;

  • 其他:結(jié)果列表、用戶反饋、搜索推薦、體驗日志、速度日志、計費邏輯……

2. 代碼耦合嚴重

  • 容易出錯,代碼邏輯脆弱;

  • 結(jié)構(gòu)僵化,不易新增功能;

  • 依賴牢固,代碼很難復用。

3. 技術(shù)棧落后

  • 頁面沒有組件化。沒有 Vue、沒有 React,還在用 Smarty 模板;

  • 無法支持 Node.js。Smarty 模板強依賴 PHP 環(huán)境;

  • 工具鏈落后。沒有 TypeScript、沒有 Jest。

這三個問題最終會影響到研發(fā)效率以及產(chǎn)品質(zhì)量。那么百度又是怎么去具體做的呢?架構(gòu)優(yōu)化的目標只有兩個,一是滿足業(yè)務需求,二是技術(shù)上能對框架和工具靈活升級(也是為了持續(xù)的滿足業(yè)務需求)。根據(jù)“滿足業(yè)務需求”這一目標,百度內(nèi)部是制定了三個層面的方向。(如圖 2)

  • 底層基礎層是貼近社區(qū),因為據(jù)內(nèi)部調(diào)研來看,造輪子的成本不高,但是維護這些輪子成本極高,如果想更快的迭代,還是建議貼近社區(qū),去用些開源的事情或者去貢獻開源。主要是解決技術(shù)棧落后以及職責不清晰等問題。

  • 中間層是獨立模塊,主要是應對之前提到的職責不清晰的問題以及交付效率低等問題。主要是解決職責不清晰以及交付效率低等問題。

  • 頂層就是組件化,在獨立模塊的基礎上去做組件化,加速業(yè)務的迭代。

△圖 2:業(yè)務需求的三個方向

三、怎么解決

根據(jù)這里提到的方向和目標,怎么結(jié)合百度自己的架構(gòu)落地呢?首先,回顧下百度的架構(gòu),如下圖 3 可以看到。

△圖 3:百度搜索結(jié)果頁的整體架構(gòu)

1. 這里有兩塊日志,意味著同一套代碼要在兩個部分維護;除了重復之外,它們的差異會對后續(xù)的維護引入更高的成本;

2. 底層這個 HHVM+PHP 和社區(qū)更加擁抱 Node.js 會有沖突。

所以,百度同學把目標架構(gòu)調(diào)整為圖 4 所示。

△圖 4:結(jié)果頁的目標架構(gòu)

圖 4 中可以看到:

  • 把日志、搜索框、相關(guān)搜索、性能打點等獨立成單獨的模塊,有專門的同學來獨立維護和迭代;

  • 在前后端之間加了一層渲染層;讓業(yè)務代碼和后端的邏輯分開;

  • 在底層加了 Node.js 機制。

  • 目標、方向都解決好之后,就得看如何實施。對于一個小體量的庫來說,從零構(gòu)建架構(gòu)就行;但是對于百度來說,實施也是難點。不僅要考慮平滑遷移、性能不退化,還要考慮長期可維護性、安全性、跨平臺等。

    前文也提到了,基本思路是按照基礎設施、模塊拆分、組件化的步驟執(zhí)行;基礎設施是業(yè)務模塊劃分的關(guān)鍵,完善的自動化和工具鏈是模塊化的前提;模塊化拆分可以為業(yè)務和團隊提供更好的橫向擴展能力;模塊化的基礎上,可以進一步在模塊內(nèi)部建設組件化方案來加速業(yè)務迭代。

    在基礎設施需要關(guān)注的事情包括:

    • TypeScript:大型項目必備,提前發(fā)現(xiàn)問題;也是跨平臺的基礎;

    • 持續(xù)集成:確保每次變更新增功能和修復問題的同時,不引入新的問題;

    • 單元測試:在重構(gòu)之初引入,幫助防退化和輔助設計。

    模塊化拆分需要關(guān)注的事情包括:

    • 識別和定義業(yè)務邊界,把大一統(tǒng)的倉庫分割成若干獨立的小倉庫;

    • 在子模塊內(nèi)建設自動化機制,獨立地選型、開發(fā)、上線。

    注意:

    模塊化拆分不是技術(shù)問題,而是業(yè)務問題。只有根據(jù)業(yè)務和產(chǎn)品進行垂直劃分,才有可能達到解耦和獨立迭代的目的。否則只是形式上拆分耦合的代碼,會造成更大的維護和溝通成本。

    由于組件是業(yè)務模塊內(nèi)部的選型,組件化的方案相對比較自由。只需要不嚴重影響性能,且能夠平滑過渡即可。

    四、落地方案

    1. 模塊化

    具體的落地方案,我們也用一張圖(圖5)來表示。可以看到它分為服務端和瀏覽器端兩部分。

    • 服務端關(guān)心的問題是業(yè)務模塊的劃分以及運行時的組合;

    • 瀏覽器端關(guān)心的問題是依賴的解決以及如何支持組件化方案。

    △圖 5:具體的落地方案

    2. 服務端

    百度是把整個大模塊拆分成多個獨立業(yè)務模塊,最終頁面由模塊組合而成。這要求業(yè)務模塊具有統(tǒng)一的接口,即上圖所示的 Molecule 接口,它定義了模塊如何渲染、有哪些依賴等信息。因為渲染過程封裝在了模塊內(nèi)部,所以整個架構(gòu)可以支持多語言、多框架。

    相信你也發(fā)現(xiàn),Molecule 和微服務非常相似。它們的關(guān)鍵區(qū)別在于,微服務的服務之間通過 IPC 互相操作,且每個服務可以獨立伸縮、獨立部署;而 Molecule 的各模塊存在于同一個進程里。雖然有這樣的區(qū)別,Molecule 仍然可以實現(xiàn)和微服務近乎相同的特性,如圖 6 所示。

    △圖 6:Molecule 和微服務的比較

    圖 7 展示的是一個具體的業(yè)務模塊的服務端入口文件,其中 ToptipController 是實現(xiàn)了由 Molecule 提供的控制器接口;這個接口要求提供一個渲染函數(shù),接受一個字典類型的數(shù)據(jù),返回渲染之后的頁面內(nèi)容。由調(diào)用方?jīng)Q定如何組裝頁面。

    △圖 7:具體的業(yè)務模塊的服務端入口文件

    如上是業(yè)務模塊提供方的接口。此外 Molecule 機制還為調(diào)用方(組裝最終頁面的那一側(cè))提供了方便的接口,可以在需要引入子模塊的地方,傳入子模塊名稱和參數(shù)即可在運行時渲染出來。整個機制的原理很簡單,但實際使用中可能還需要引入命名空間、考慮模塊版本等問題。

    3. 客戶端

    那么客戶端如何運行起來呢?我們也需要把每個模塊的瀏覽器端組件運行起來,困難在于組件之間的依賴和代碼共享。這些組件可能位于不同的代碼庫并屬于不同的業(yè)務,所以我們需要一個非常松散的依賴方式。

    這里我們引入的是一個依賴注入的容器(圖 8),總的來說,框架邏輯和通用工具都封裝成具體的Service提供給業(yè)務模塊使用,每個業(yè)務模塊則需要定義它依賴于哪些Service。

    △圖 8:客戶端設計

    圖 9 形象地描述了組件、Service 和容器間的關(guān)系。

    △圖 9:組件、Service 和容器之間的關(guān)系

    其中藍色代表具體的Service,其他顏色表示獨立的業(yè)務模塊。運行時容器會負責解決每個業(yè)務模塊的依賴,并把這些業(yè)務模塊組裝起來,最終得到可交互的 Web 頁面。

    注意:

    業(yè)務模塊之間是獨立的,一個業(yè)務模塊無法依賴于其他業(yè)務模塊,只能依賴于通用 Service。因此如果存在業(yè)務模塊之間的產(chǎn)品邏輯耦合,可能需要一個通用 Service 作為媒介,比如容器里提供一個起事件總線作用的 EventService。

    圖10是業(yè)務模塊的客戶端代碼示例。它的依賴通過構(gòu)造函數(shù)來聲明,運行時容器負責依賴的創(chuàng)建,而業(yè)務模塊只需要關(guān)心依賴的使用。正是使用和創(chuàng)建操作的分離,使得業(yè)務模塊之間、業(yè)務模塊和頁面框架之間可以解耦,可以獨立地開發(fā)、獨立地測試。

    △圖 10:業(yè)務模塊的客戶端代碼示例

    以上是模塊拆分的整體方案,我們回顧一下:在服務端通過一個叫做 Molecule 的接口來組合業(yè)務模塊;在瀏覽器端通過一個 DI 容器來解決依賴關(guān)系,并啟動所有業(yè)務模塊。

    4. 組件化

    組件化方案直接影響業(yè)務開發(fā)的的效率,換句話說,組件化方案某種程度上決定了業(yè)務同學寫怎樣的代碼。組件化也可以幫助解決職責不清晰等問題。我們選的組件化方案是 San,你也可以基于你的業(yè)務或偏好選擇 Vue 或者 React。業(yè)務代碼的遷移比較直觀,就是從 Smarty 模板遷移到 San 組件,從 HTML 字符串拼接變成有業(yè)務語義的組件結(jié)構(gòu)。

    接下來重點關(guān)注組件化方案的兩個關(guān)鍵技術(shù)問題,跨平臺和頁面性能。

    1)跨平臺

    我們有非常多的業(yè)務代碼,有上千個模板、幾十萬行代碼,這些代碼需要遷移到組件化方案上來,而且要確保后端從 PHP 遷移到 Node.js 的整個過程中,業(yè)務代碼不需要重新開發(fā)。所以業(yè)務組件如何跨平臺呢?關(guān)鍵在于抽象。

    • 高層語言:我們業(yè)務代碼需要使用一個足夠高層的語言,這里我們用的是 TypeScript,可以翻譯到多個平臺;

    • 依賴反轉(zhuǎn):我們的高層的業(yè)務的模塊不應該依賴于具體的底層模塊,而是它只依賴于接口,這樣才有可能在不同的平臺給它替換掉不同的底層的實現(xiàn);

    • 抽象接口:最后是 Molecule 這個接口的設計應該足夠的簡單;Molecule 接口不依賴底層實現(xiàn),比如 PHP 的具體 API。

    做到以上幾點就可以完成平滑的過渡。這個過程中又分為三個階段(圖 11)。

    △圖 11:平臺過渡的三個階段

    2)頁面性能

    引入前端框架通常意味著體積增加,性能下降,而性能直接影響搜索收入,因此頁面性能是項目成功的關(guān)鍵。如果性能會比模板引擎的性能差,那么這個項目很可能會夭折。如何去保證頁面性能?著重介紹兩個優(yōu)化點。

    • 引入 SSR:引入服務端渲染,首屏性能可以得到明顯提升;

    • SSR 優(yōu)化:傳統(tǒng)的 SSR 上還需要進一步優(yōu)化性能。

    引入SSR。為了解釋SSR的重要性,請看圖12。瀏覽器加載頁面分為四步:請求頁面、請求外鏈資源、執(zhí)行腳本、渲染組件。從圖中的對比可以看出,CSR在前面三步的時候,用戶都是看不到頁面的;而引入SSR之后,在第二步用戶就能看到請求回來的頁面。SSR它最大的一個用途就是提升首屏時間。

    △圖 12:CSR和SSR的比較

    SSR 優(yōu)化。只是引入 SSR 還不能讓性能達到預期,因為相比于模板引擎直接拼接字符串,SSR 需要遞歸渲染組件,尤其是遞歸 VNode 比較耗時。對此 San SSR 相比于 Vue/React SSR 做了很多改進。

    • 去 VNode:編譯期遞歸 VNode,運行時只做 HTML 拼接;

    • 編譯期計算:盡可能把工作移到編譯期,減小運行時開銷;

    圖 13 展示了最終的 San SSR 和改造前的 Smarty 模板引擎的性能對比。

    △圖 13:最終的 San SSR 和改造前的 Smarty 模板引擎的性能對比

    可以看到 Smarty 和 San SSR 在不同的場景會有不同的表現(xiàn),因為它們的渲染方式非常不同。最終搜索結(jié)果頁的組件化的 SSR 上線之后,線上實驗效果顯示比 Smarty 要快 10ms左右。這個已經(jīng)是一個很不錯的效果了,我們用組件化從性能上打敗了模版引擎。

    五、結(jié)語

    針對百度搜索引擎在架構(gòu)演化中遇到的問題,相信在其他領域也會有一些共性的東西。通過百度的解決思路,希望能對正在做前端架構(gòu)的你有一些啟發(fā)。

    往期推薦

    歐創(chuàng)新:深度解析DDD中臺和微服務設計

    領域驅(qū)動專家張逸文字脫口秀:簡單工廠不簡單

    DDD專家張逸:《解構(gòu)領域驅(qū)動設計》前言

    Hacker News熱文:請停止學習框架,學習領域驅(qū)動設計(DDD)(獲500個點贊)

    京東平臺研發(fā)朱志國:領域驅(qū)動設計(DDD)理論啟示

    DDD專家張逸:構(gòu)建領域驅(qū)動設計知識體系

    領域驅(qū)動設計(DDD)在美團點評業(yè)務系統(tǒng)的實踐

    當DDD遇上微服務

    DDD戰(zhàn)略篇:架構(gòu)設計的響應力

    可視化與領域驅(qū)動設計

    領域驅(qū)動設計(DDD)前夜:面向?qū)ο笏枷?/p>

    領域驅(qū)動設計(DDD):領域和子域

    DDD專家張逸:復雜與架構(gòu)演進的關(guān)系

    滕云:DDD實現(xiàn)之路

    ? ?END ? ?? #技術(shù)人必備#

    點個在看,讓更多人看見

    總結(jié)

    以上是生活随笔為你收集整理的百度十亿级流量的搜索前端,是怎么做架构升级的?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。