當前位置:才華齋>網路>淘寶>

有關淘寶首頁的基礎知識

淘寶 閱讀(5.66K)

很多人都用淘寶,但是對淘寶首頁並不瞭解,小編這裡帶來一位淘寶首頁的設計師的講解,希望可以讓你對淘寶首頁有一個基本的認識。

有關淘寶首頁的基礎知識

  一、相關背景介紹

淘寶首頁是淘寶的門面,承載著幾乎淘系所有業務的入口,流量很大,量級單位為億。近幾年無線端崛起,業務重點開始向無線終端偏移(目前不能叫偏移,基本以無線為主了),所以淘寶 PC 端首頁的流量也有削減,不過即便如此,它的日均 PV 依然相當高。

淘寶首頁一向是內部平臺和技術的試驗田,它一直在變化著。最新的框架和系統都會找淘寶首頁試點,可以試想下,如果某一項需要推動的升級或者優化措施在淘寶首頁已經上線,並且拿到了良好的資料和穩定性,其他業務還有什麼理由不去嘗試和更迭呢?同時,去年一年身在淘寶前端的技術架構組,自然而然也會主動去 push 一些實驗性的內容到業務上。

淘系的站點頁面包括首頁、其他頻道頁和活動頁等,這些頁面並不都由淘寶前端一行一行的程式碼碼出來,業務如此之多,這種玩法即便人數 double 也忙不過來。事實上,大多數頁面都是依託內部的搭建平臺——運營或者前端通過模組搭建的方式——構建的,而前端 focus 的重點在於搭建平臺的建設自身以及模組的通用性和複用率的保障,當然,還有一些工程化的東西。

使用搭建平臺搭建的頁面,前端只需要考慮組成頁面的原子模組的開發,整體的渲染由搭建平臺提供的統一指令碼全權負責。而在淘寶首頁上,考慮到頁面模組數量巨多,加上還有少量跨部門、跨團隊的溝通,渲染模型略微不同。

  二、淘寶首頁的整體變遷

背景中提到,淘寶首頁依託於內部搭建平臺,它的變遷自然也是跟著搭建系統的變化而變化的。

1、PHP 下的淘寶首頁

接手淘寶首頁不久,便遇到了一年一度的改版,那時它還執行在 PHP 環境中。這裡需要說明的是,淘寶首頁的所有程式碼完全由前端掌控,前端不會直接跟資料庫打交道,其資料來源分為兩部分。

資料來源

一是運營填寫的資料。 採用前端挖坑的形式,預留坑位讓運營獲取填寫資料,

運營填寫這些坑位就會產生這份 PHP 模板對應的資料,最後渲染出來就是一個完整的 HTML 片段(實時性渲染)。

舊版搭建系統中就是通過這種方式構造一個子模組。我描述得十分簡單,但作為一個平臺它需要考慮的東西還有很多,比如資料順序的控制、定時釋出、回滾機制、過濾機制、篩選機制、資料的同步、資料的更新、版本控制、許可權控制、其他系統的引用等等。

二是後端或者個性化平臺提供的資料。 不同的業務有不同的訴求。一些業務有自己的後端,他們要求使用自己業務產出的資料;有的業務希望使用者看到的內容不一樣,千人千面,期望接入演算法;一些業務跟賣家直接打交道,期望使用招商資料;而有些業務期望採用運營從資料池篩選出來的資料……總之,淘寶首頁需要對接形形色色的系統,介面繁多。後面會提到對動態資料來源的整合。

並且這些系統對應的域名是不一樣的,JSONP 格式自然也就成了首選。但一些特殊的系統,比如廣告,它的渲染並不是一個簡單的 JSONP 請求,可能它還要干預整個廣告的渲染流程,比如載入他們的 JS,把渲染的控制權交過去。

頁面的架構

上面介紹了資料的來源和子模組的結構,那麼整個頁面又是如何構成的呢?模組的搭建分為兩種,一種是視覺化搭建,運營或者前端可以將開發好的模組(或者模組庫中選取的模組)拖拽到容器內,形成一個頁面:

當然,上圖也只是一個模型,作為一個系統需要考慮的問題還有很多很多,如頁面的佈局、多終端適配、模組的臨時隱藏、位置調整、面板選擇、模組的複製等等。

通過模組 id 將模組引入,並且新增一些類似 lazyload 的標記,方便控制渲染節奏和資料入口。原始碼搭建和模組搭建的區別在於,前者更易於控制模組的結構以及模組的渲染順序。

動態資料來源

首頁面對一大堆介面和平臺,對接幾十個業務方,介面是個很大的問題,由於後臺系統的差異,基本沒有辦法統一資料來源的格式,一旦運營哪天心血來潮要換一個他自己覺得用的更爽的或者資料更好的系統,前後端估計又得溝通和對接幾次。

平臺具備資料來源接入的能力,也就是說我們挖的坑不僅僅可以讓運營填資料,還可以從各種資料來源中直接匯入資料,當然,這裡需要進行一次資料欄位的對映轉換。

繫結之後,資料既可以同步輸出,也可以非同步輸出,這些都是平臺提供的能力。這個方案基本上解決了後端系統/介面變化的問題,並且減少了前後端之間的溝通成本。

不過這裡需要注意的是,雖然頁面上的介面都通過平臺統一梳理了一次,這也意味著,頁面所有的請求會先流經平臺,然後分發到各個後端,平臺的抗壓能力要求很高。

2、PHP 到 Node 的變遷

淘寶首頁日均請求的這個量級,不可能是十幾二十臺臺伺服器抗得住的,支撐它必須有一個服務叢集。

每一個 CDN 節點上都具備 PHP 渲染的能力,當頁面釋出時,我們把該頁面所有的.模組和資料同步到全部 CDN 節點上,基本模式大概就是如此了。看起來還挺不錯,但是經過一段時間的運維,很多安全、效能問題都慢慢浮現出來了:

效能問題。 每個 PHP 頁面包含多個子模組,而子模組也有可能引用了其他的子模組,PHP 的 include 操作是存在消耗的,每一次引用都是一次磁碟 IO,一個渲染節點上跑了成千上萬個類似淘寶首頁的 PHP 頁面,併發一高其效率可想而知。

推送機制問題。 檔案同步是一種比較噁心的機制。首先,時間上沒法控制,一個檔案同步到所有的節點,快則幾秒鐘,慢的話耗時會超過一兩分鐘;並且同步過程還有可能失敗,健康檢測的成本也是相當高的。釋出比較緊湊時,需要同步的檔案也很多,很容易造成佇列堆積,加劇同步差的體驗。

實時性強需求問題。 檔案在推送之前,還可能經過一些前置系統,釋出鏈路越長,線上生效時間越慢,慢的時候大約五分鐘才生效,這樣的延時對於實時性要求很高(如秒殺)的需求來說是完全不能接受的。

當然,還有很多其他問題,如運維成本增高、安全風險增高、PHP 資深人才儲備不足等等。所以 PHP 渲染容器的命運,就是,被幹掉。

服務叢集為 Cache CDN,它只有靜態檔案處理能力,沒有 PHP/Node 的渲染能力,所以處理效率高,效能也好,抗壓能力相當強,並且扛不住的時候還可以花錢買服務,拓展 Cache 叢集。

使用者訪問時,Nginx 轉到 Cache CDN,如果命中快取則直接返回,沒有命中便回源到源站伺服器。源站伺服器是具備模組渲染能力的 Node 服務,它可以做很多事情:

· 控制 Cache 響應頭,通過 max-age 和 s-maxage 控制頁面在客戶端的快取時間以及在 Cache 上的快取時間,這個快取時間可以根據需求隨時做調整,比如大促的時候調長一些;

· 控制內外網環境,和 AB 測試狀態;

· 融合前端相關的工具鏈,比如檢測、壓縮、過濾等等。

它的優勢有很多,這裡不一一列舉了。這個模式中還添加了一層容災,源站伺服器每隔一段時間將資料推送到於 Cache 同機房的備份伺服器,一點源站掛了,還能夠自動容災到備份資料上。

模式的變化不僅在運維上有了突破,CDN 被攻擊時的安全風險也低了很多,同時也省卻了 sync 所需的各種檢測機制,每年節約成本也是百萬以上,優勢還是相當明顯。

3、Node,不一樣的模式

上面 PHP 模組中,我們只說了 HTML 和資料部分,用心的讀者應該已經發現,CSS 和 JS 這些靜態資源都沒提到,那頁面是如何渲染的呢?

舊版 PHP 頁面中,我們是直接引入了一個 CSS 和一個 JS,淘寶這邊採用的是 git 版本迭代釋出,這些靜態資源都是直接放在一個 git 倉庫中。也就是這樣:

每次釋出完 git 檔案,再修改 PHP 的版本號,然後釋出 PHP 程式碼。當然,也做了相關的優化,比如釋出 git 時自動更新版本號等。

一個模組的 CSS/JS 和模板放在一起,CSS/JS 與頁面其他模組的靜態資源是相互獨立的,目的就是希望單個模組也能夠完整的跑起來,更加利於模組的複用。

而模組的挖坑,也從模板中獨立了出來,採用 JSON Schema 的形式定義資料格式:

模組之間相互獨立隔離,所以會存在一定程度的冗餘,不過模組解偶帶來的收益要比這點冗餘要多得多。事實上,我們是通過一個倉庫去管理單個模組的。頁面的渲染就比較簡單了,源站 Node 容器會將所有的 合併成一個 ,為減少頁面請求,css 和 js 也會 combo 成一個檔案。

任何模組的更新,頁面都會有感知,下次進入系統時,就會提示是否需要升級模組和頁面。

  三、淘寶首頁的效能優化

首頁模組眾多,如果一口氣吐出來,DOM 數量必然超過 4k 個,其結果就是首屏時間極長。按照 TMS 的開發規範,每個 TMS 模組都包含一個 和 ,最後展示出來兩個 combo 的 js 和 css。首頁載入的時候也不會一口氣執行所有 ,否則剛開始頁面阻塞會十分嚴重。

頁面的渲染邏輯

· 遍歷所有 TMS 模組(包含一個 J_Module 的鉤子);

· 部分 TMS 模組無 JS 內容,但是載入了一個 ,為模組新增 tb-pass 的 class,用於跳過該模組 JS 的執行;

· 將頁面分為兩塊,首屏為一塊,非首屏整體為第二塊,先將首屏模組加入到懶載入監控;

· 待首屏模組載入完成,或者使用者處理了頁面互動時(滾動、滑鼠移動等),將非首屏模組加入到懶載入監控;

· 處理一些特殊模組,它們會在進入視窗之前幾百畫素就開始載入;

· 監控滾動,按照以上邏輯,渲染模組;

· 部分模組即便是被執行了,也不一定渲染出來,因為它的優先順序不高,在模組內部加了事件監聽,比如等到 mouseover/onload 事件觸發的時候再渲染這些內容。

程式碼的效能優化是一個精細活,如果你要在一個龐大的未經優化的頁面上做效能優化,可能會面臨一次重構程式碼。上面的文章提到的是頁面內部的細節優化,但是在開發流程中做的規範化、標準化,以及線上訪問通路中的各個環節優化還沒有提及。

  四、淘寶首頁的穩定性保障

在大流量下,任何小問題都會被放大成大問題,所以開發環節遇到的任何偶發性問題都需要引起重視。不過很多偶發性問題在我們的測試環境中是找不到的,比如與地域相關的問題(如上海的某個 CDN 節點掛了),使用者屬性問題(如 nickname 最後一個為字母 s 的使用者頁面天窗),瀏覽器外掛問題,運營商廣告注入問題等等。

難以在上線之前把所有問題考慮周全,但是有兩點是必須做好的:兜底容災 + 監控預警。

1、兜底容災機制

兜底容災有兩個層面的考慮:

· 非同步介面請求錯誤,包括介面資料格式錯誤,介面請求超時等;

· 同步渲染,源站頁面渲染出錯。

非同步介面請求,主要涉及到的是後臺系統,對接系統較多,各個系統的穩定性和抗壓能力各不相同,這方面的保障有多種方案。

每次資料請求都快取到本地,並且為每個介面都提供一個硬兜底。還有一種方案是「重試」,請求一次不成功那就請求第二次。

對於同步渲染,它只需要頁面模板和同步資料,兩者中任一種存在錯誤,源站都會報錯,此時回源返回的內容就是一個 error 頁面,狀態碼為 5xx。這個錯誤不一定是開發者造成的,有可能是系統鏈路出現同步異常或者斷路問題。

一旦源站任何異常,Nginx 都會轉到與 Cache CDN 同機房的首頁映象上去,這個映象內容就是淘寶首頁的 HTML 備份原始碼。

2、監控預警機制

監控也有兩個層面:

· 模組級別的監控,介面請求布點、模組天窗檢測等;

· 頁面的監控,在頁面上新增特殊標記,定時迴歸所有 CDN 節點,檢視特殊標記是否存在。

模組層面的監控,內容還是相當多的,監控的點越多越詳細,到最後定位問題的效率就會越高,比如在一個稍微複雜的模組上,我會埋下這些監控:

· 介面請求格式錯誤、請求失敗、請求超時,至少三個埋點;

· 硬兜底資料請求失敗埋點;

· 模組 5s 內沒有渲染完成統計埋點;

· 模組內連結和圖片黑白名單匹配埋點。

其中部分監控還會自動處理明確的錯誤,比如 https 頁面下出現了 http 的圖片,會立即自動處理掉這些問題。

3、上線前的自動化檢測

這屬於淘寶整個工程化環境的一部分,前端自動化測試。一般會在上線之前處理這些問題:

· 檢測 HTML 是否符合規範

· 檢測 https 升級情況

· 檢測連結合法性

· 檢測靜態資源合法性

· 檢測 JavaScript 報錯

· 檢測頁面載入時是否有彈出框

· 檢測頁面是否呼叫 console.*

· 頁面 JS 記憶體記錄

當然,也可以自己新增測試用例,比如檢測介面資料格式、模組天窗問題等。自動化檢測也可以設定定時迴歸,還是比較有保障的。

  五、淘寶首頁的敏捷措施

1、健康檢查

頁面模組眾多,為了能夠追蹤頁面上每一個小點的變化,我在請求、渲染的每一個環節都做了詳細的統計。

一旦介面請求失敗,或者介面走了容災邏輯,或者模組渲染超過 5s,控制檯都會有黃色警報,當然此時,也已經向伺服器傳送了警報統計。

2、介面 Hub

介面 Hub 是對資料請求的管理工具。

頁面很多模組的渲染都需要一個以上的資料來源,一旦運營反饋頁面渲染資料異常,可以直接通過 Hub 找到資料,加速 Bug 定位效率。同時 Hub 也可以用來切換環境,將一個介面的請求切換到日常或者預發環境的介面之中,它是除錯的利器。

3、快捷通道

我在頁面指令碼執行前後都放了一個快捷操作通道,一旦遇到緊急線上問題,比如樣式錯亂溢位、介面報錯導致天窗等,可以通過快捷通道直接修改頁面的 CSS 和 JS,兩分鐘內上線。

不過這類通道只適合緊急問題的修復,畢竟隨意插入 JS 程式碼是存在很大風險的。