- 相關(guān)推薦
有關(guān)淘寶首頁的基礎(chǔ)知識
很多人都用淘寶,但是對淘寶首頁并不了解,小編這里帶來一位淘寶首頁的設(shè)計師的講解,希望可以讓你對淘寶首頁有一個基本的認(rèn)識。
一、相關(guān)背景介紹
淘寶首頁是淘寶的門面,承載著幾乎淘系所有業(yè)務(wù)的入口,流量很大,量級單位為億。近幾年無線端崛起,業(yè)務(wù)重點開始向無線終端偏移(目前不能叫偏移,基本以無線為主了),所以淘寶 PC 端首頁的流量也有削減,不過即便如此,它的日均 PV 依然相當(dāng)高。
淘寶首頁一向是內(nèi)部平臺和技術(shù)的試驗田,它一直在變化著。最新的框架和系統(tǒng)都會找淘寶首頁試點,可以試想下,如果某一項需要推動的升級或者優(yōu)化措施在淘寶首頁已經(jīng)上線,并且拿到了良好的數(shù)據(jù)和穩(wěn)定性,其他業(yè)務(wù)還有什么理由不去嘗試和更迭呢?同時,去年一年身在淘寶前端的技術(shù)架構(gòu)組,自然而然也會主動去 push 一些實驗性的內(nèi)容到業(yè)務(wù)上。
淘系的站點頁面包括首頁、其他頻道頁和活動頁等,這些頁面并不都由淘寶前端一行一行的代碼碼出來,業(yè)務(wù)如此之多,這種玩法即便人數(shù) double 也忙不過來。事實上,大多數(shù)頁面都是依托內(nèi)部的搭建平臺——運營或者前端通過模塊搭建的方式——構(gòu)建的,而前端 focus 的重點在于搭建平臺的建設(shè)自身以及模塊的通用性和復(fù)用率的保障,當(dāng)然,還有一些工程化的東西。
使用搭建平臺搭建的頁面,前端只需要考慮組成頁面的原子模塊的開發(fā),整體的渲染由搭建平臺提供的統(tǒng)一腳本全權(quán)負(fù)責(zé)。而在淘寶首頁上,考慮到頁面模塊數(shù)量巨多,加上還有少量跨部門、跨團(tuán)隊的溝通,渲染模型略微不同。
二、淘寶首頁的整體變遷
背景中提到,淘寶首頁依托于內(nèi)部搭建平臺,它的變遷自然也是跟著搭建系統(tǒng)的變化而變化的。
1、PHP 下的淘寶首頁
接手淘寶首頁不久,便遇到了一年一度的改版,那時它還運行在 PHP 環(huán)境中。這里需要說明的是,淘寶首頁的所有代碼完全由前端掌控,前端不會直接跟數(shù)據(jù)庫打交道,其數(shù)據(jù)來源分為兩部分。
數(shù)據(jù)來源
一是運營填寫的數(shù)據(jù)。 采用前端挖坑的形式,預(yù)留坑位讓運營獲取填寫數(shù)據(jù),
運營填寫這些坑位就會產(chǎn)生這份 PHP 模板對應(yīng)的數(shù)據(jù),最后渲染出來就是一個完整的 HTML 片段(實時性渲染)。
舊版搭建系統(tǒng)中就是通過這種方式構(gòu)造一個子模塊。我描述得十分簡單,但作為一個平臺它需要考慮的東西還有很多,比如數(shù)據(jù)順序的控制、定時發(fā)布、回滾機制、過濾機制、篩選機制、數(shù)據(jù)的同步、數(shù)據(jù)的更新、版本控制、權(quán)限控制、其他系統(tǒng)的引用等等。
二是后端或者個性化平臺提供的數(shù)據(jù)。 不同的業(yè)務(wù)有不同的訴求。一些業(yè)務(wù)有自己的后端,他們要求使用自己業(yè)務(wù)產(chǎn)出的數(shù)據(jù);有的業(yè)務(wù)希望用戶看到的內(nèi)容不一樣,千人千面,期望接入算法;一些業(yè)務(wù)跟賣家直接打交道,期望使用招商數(shù)據(jù);而有些業(yè)務(wù)期望采用運營從數(shù)據(jù)池篩選出來的數(shù)據(jù)……總之,淘寶首頁需要對接形形色色的系統(tǒng),接口繁多。后面會提到對動態(tài)數(shù)據(jù)源的整合。
并且這些系統(tǒng)對應(yīng)的域名是不一樣的,JSONP 格式自然也就成了首選。但一些特殊的系統(tǒng),比如廣告,它的渲染并不是一個簡單的 JSONP 請求,可能它還要干預(yù)整個廣告的渲染流程,比如加載他們的 JS,把渲染的控制權(quán)交過去。
頁面的架構(gòu)
上面介紹了數(shù)據(jù)的來源和子模塊的結(jié)構(gòu),那么整個頁面又是如何構(gòu)成的呢?模塊的搭建分為兩種,一種是可視化搭建,運營或者前端可以將開發(fā)好的模塊(或者模塊庫中選取的模塊)拖拽到容器內(nèi),形成一個頁面:
當(dāng)然,上圖也只是一個模型,作為一個系統(tǒng)需要考慮的問題還有很多很多,如頁面的布局、多終端適配、模塊的臨時隱藏、位置調(diào)整、皮膚選擇、模塊的復(fù)制等等。
通過模塊 id 將模塊引入,并且添加一些類似 lazyload 的標(biāo)記,方便控制渲染節(jié)奏和數(shù)據(jù)入口。源碼搭建和模塊搭建的區(qū)別在于,前者更易于控制模塊的結(jié)構(gòu)以及模塊的渲染順序。
動態(tài)數(shù)據(jù)源
首頁面對一大堆接口和平臺,對接幾十個業(yè)務(wù)方,接口是個很大的問題,由于后臺系統(tǒng)的差異,基本沒有辦法統(tǒng)一數(shù)據(jù)源的格式,一旦運營哪天心血來潮要換一個他自己覺得用的更爽的或者數(shù)據(jù)更好的系統(tǒng),前后端估計又得溝通和對接幾次。
平臺具備數(shù)據(jù)源接入的能力,也就是說我們挖的坑不僅僅可以讓運營填數(shù)據(jù),還可以從各種數(shù)據(jù)源中直接導(dǎo)入數(shù)據(jù),當(dāng)然,這里需要進(jìn)行一次數(shù)據(jù)字段的映射轉(zhuǎn)換。
綁定之后,數(shù)據(jù)既可以同步輸出,也可以異步輸出,這些都是平臺提供的能力。這個方案基本上解決了后端系統(tǒng)/接口變化的問題,并且減少了前后端之間的溝通成本。
不過這里需要注意的是,雖然頁面上的接口都通過平臺統(tǒng)一梳理了一次,這也意味著,頁面所有的請求會先流經(jīng)平臺,然后分發(fā)到各個后端,平臺的抗壓能力要求很高。
2、PHP 到 Node 的變遷
淘寶首頁日均請求的這個量級,不可能是十幾二十臺臺服務(wù)器抗得住的,支撐它必須有一個服務(wù)集群。
每一個 CDN 節(jié)點上都具備 PHP 渲染的能力,當(dāng)頁面發(fā)布時,我們把該頁面所有的模塊和數(shù)據(jù)同步到全部 CDN 節(jié)點上,基本模式大概就是如此了?雌饋磉挺不錯,但是經(jīng)過一段時間的運維,很多安全、性能問題都慢慢浮現(xiàn)出來了:
性能問題。 每個 PHP 頁面包含多個子模塊,而子模塊也有可能引用了其他的子模塊,PHP 的 include 操作是存在消耗的,每一次引用都是一次磁盤 IO,一個渲染節(jié)點上跑了成千上萬個類似淘寶首頁的 PHP 頁面,并發(fā)一高其效率可想而知。
推送機制問題。 文件同步是一種比較惡心的機制。首先,時間上沒法控制,一個文件同步到所有的節(jié)點,快則幾秒鐘,慢的話耗時會超過一兩分鐘;并且同步過程還有可能失敗,健康檢測的成本也是相當(dāng)高的。發(fā)布比較緊湊時,需要同步的文件也很多,很容易造成隊列堆積,加劇同步差的體驗。
實時性強需求問題。 文件在推送之前,還可能經(jīng)過一些前置系統(tǒng),發(fā)布鏈路越長,線上生效時間越慢,慢的時候大約五分鐘才生效,這樣的延時對于實時性要求很高(如秒殺)的需求來說是完全不能接受的。
當(dāng)然,還有很多其他問題,如運維成本增高、安全風(fēng)險增高、PHP 資深人才儲備不足等等。所以 PHP 渲染容器的命運,就是,被干掉。
服務(wù)集群為 Cache CDN,它只有靜態(tài)文件處理能力,沒有 PHP/Node 的渲染能力,所以處理效率高,性能也好,抗壓能力相當(dāng)強,并且扛不住的時候還可以花錢買服務(wù),拓展 Cache 集群。
用戶訪問時,Nginx 轉(zhuǎn)到 Cache CDN,如果命中緩存則直接返回,沒有命中便回源到源站服務(wù)器。源站服務(wù)器是具備模塊渲染能力的 Node 服務(wù),它可以做很多事情:
· 控制 Cache 響應(yīng)頭,通過 max-age 和 s-maxage 控制頁面在客戶端的緩存時間以及在 Cache 上的緩存時間,這個緩存時間可以根據(jù)需求隨時做調(diào)整,比如大促的時候調(diào)長一些;
· 控制內(nèi)外網(wǎng)環(huán)境,和 AB 測試狀態(tài);
· 融合前端相關(guān)的工具鏈,比如檢測、壓縮、過濾等等。
它的優(yōu)勢有很多,這里不一一列舉了。這個模式中還添加了一層容災(zāi),源站服務(wù)器每隔一段時間將數(shù)據(jù)推送到于 Cache 同機房的備份服務(wù)器,一點源站掛了,還能夠自動容災(zāi)到備份數(shù)據(jù)上。
模式的變化不僅在運維上有了突破,CDN 被攻擊時的安全風(fēng)險也低了很多,同時也省卻了 sync 所需的各種檢測機制,每年節(jié)約成本也是百萬以上,優(yōu)勢還是相當(dāng)明顯。
3、Node,不一樣的模式
上面 PHP 模塊中,我們只說了 HTML 和數(shù)據(jù)部分,用心的讀者應(yīng)該已經(jīng)發(fā)現(xiàn),CSS 和 JS 這些靜態(tài)資源都沒提到,那頁面是如何渲染的呢?
舊版 PHP 頁面中,我們是直接引入了一個 CSS 和一個 JS,淘寶這邊采用的是 git 版本迭代發(fā)布,這些靜態(tài)資源都是直接放在一個 git 倉庫中。也就是這樣:
每次發(fā)布完 git 文件,再修改 PHP 的版本號,然后發(fā)布 PHP 代碼。當(dāng)然,也做了相關(guān)的優(yōu)化,比如發(fā)布 git 時自動更新版本號等。
一個模塊的 CSS/JS 和模板放在一起,CSS/JS 與頁面其他模塊的靜態(tài)資源是相互獨立的,目的就是希望單個模塊也能夠完整的跑起來,更加利于模塊的復(fù)用。
而模塊的挖坑,也從模板中獨立了出來,采用 JSON Schema 的形式定義數(shù)據(jù)格式:
模塊之間相互獨立隔離,所以會存在一定程度的冗余,不過模塊解偶帶來的收益要比這點冗余要多得多。事實上,我們是通過一個倉庫去管理單個模塊的。頁面的渲染就比較簡單了,源站 Node 容器會將所有的 index.xtpl 合并成一個 page.xtpl,為減少頁面請求,css 和 js 也會 combo 成一個文件。
任何模塊的更新,頁面都會有感知,下次進(jìn)入系統(tǒng)時,就會提示是否需要升級模塊和頁面。
三、淘寶首頁的性能優(yōu)化
首頁模塊眾多,如果一口氣吐出來,DOM 數(shù)量必然超過 4k 個,其結(jié)果就是首屏?xí)r間極長。按照 TMS 的開發(fā)規(guī)范,每個 TMS 模塊都包含一個 index.js 和 index.css,最后展示出來兩個 combo 的 js 和 css。首頁加載的時候也不會一口氣執(zhí)行所有 index.js,否則剛開始頁面阻塞會十分嚴(yán)重。
頁面的渲染邏輯
· 遍歷所有 TMS 模塊(包含一個 J_Module 的鉤子);
· 部分 TMS 模塊無 JS 內(nèi)容,但是加載了一個 index.js,為模塊添加 tb-pass 的 class,用于跳過該模塊 JS 的執(zhí)行;
· 將頁面分為兩塊,首屏為一塊,非首屏整體為第二塊,先將首屏模塊加入到懶加載監(jiān)控;
· 待首屏模塊加載完成,或者用戶處理了頁面交互時(滾動、鼠標(biāo)移動等),將非首屏模塊加入到懶加載監(jiān)控;
· 處理一些特殊模塊,它們會在進(jìn)入視窗之前幾百像素就開始加載;
· 監(jiān)控滾動,按照以上邏輯,渲染模塊;
· 部分模塊即便是被執(zhí)行了,也不一定渲染出來,因為它的優(yōu)先級不高,在模塊內(nèi)部加了事件監(jiān)聽,比如等到 mouseover/onload 事件觸發(fā)的時候再渲染這些內(nèi)容。
代碼的性能優(yōu)化是一個精細(xì)活,如果你要在一個龐大的未經(jīng)優(yōu)化的頁面上做性能優(yōu)化,可能會面臨一次重構(gòu)代碼。上面的文章提到的是頁面內(nèi)部的細(xì)節(jié)優(yōu)化,但是在開發(fā)流程中做的規(guī)范化、標(biāo)準(zhǔn)化,以及線上訪問通路中的各個環(huán)節(jié)優(yōu)化還沒有提及。
四、淘寶首頁的穩(wěn)定性保障
在大流量下,任何小問題都會被放大成大問題,所以開發(fā)環(huán)節(jié)遇到的任何偶發(fā)性問題都需要引起重視。不過很多偶發(fā)性問題在我們的測試環(huán)境中是找不到的,比如與地域相關(guān)的問題(如上海的某個 CDN 節(jié)點掛了),用戶屬性問題(如 nickname 最后一個為字母 s 的用戶頁面天窗),瀏覽器插件問題,運營商廣告注入問題等等。
難以在上線之前把所有問題考慮周全,但是有兩點是必須做好的:兜底容災(zāi) + 監(jiān)控預(yù)警。
1、兜底容災(zāi)機制
兜底容災(zāi)有兩個層面的考慮:
· 異步接口請求錯誤,包括接口數(shù)據(jù)格式錯誤,接口請求超時等;
· 同步渲染,源站頁面渲染出錯。
異步接口請求,主要涉及到的是后臺系統(tǒng),對接系統(tǒng)較多,各個系統(tǒng)的穩(wěn)定性和抗壓能力各不相同,這方面的保障有多種方案。
每次數(shù)據(jù)請求都緩存到本地,并且為每個接口都提供一個硬兜底。還有一種方案是「重試」,請求一次不成功那就請求第二次。
對于同步渲染,它只需要頁面模板和同步數(shù)據(jù),兩者中任一種存在錯誤,源站都會報錯,此時回源返回的內(nèi)容就是一個 error 頁面,狀態(tài)碼為 5xx。這個錯誤不一定是開發(fā)者造成的,有可能是系統(tǒng)鏈路出現(xiàn)同步異常或者斷路問題。
一旦源站任何異常,Nginx 都會轉(zhuǎn)到與 Cache CDN 同機房的首頁鏡像上去,這個鏡像內(nèi)容就是淘寶首頁的 HTML 備份源碼。
2、監(jiān)控預(yù)警機制
監(jiān)控也有兩個層面:
· 模塊級別的監(jiān)控,接口請求布點、模塊天窗檢測等;
· 頁面的監(jiān)控,在頁面上添加特殊標(biāo)記,定時回歸所有 CDN 節(jié)點,查看特殊標(biāo)記是否存在。
模塊層面的監(jiān)控,內(nèi)容還是相當(dāng)多的,監(jiān)控的點越多越詳細(xì),到最后定位問題的效率就會越高,比如在一個稍微復(fù)雜的模塊上,我會埋下這些監(jiān)控:
· 接口請求格式錯誤、請求失敗、請求超時,至少三個埋點;
· 硬兜底數(shù)據(jù)請求失敗埋點;
· 模塊 5s 內(nèi)沒有渲染完成統(tǒng)計埋點;
· 模塊內(nèi)鏈接和圖片黑白名單匹配埋點。
其中部分監(jiān)控還會自動處理明確的錯誤,比如 https 頁面下出現(xiàn)了 http 的圖片,會立即自動處理掉這些問題。
3、上線前的自動化檢測
這屬于淘寶整個工程化環(huán)境的一部分,前端自動化測試。一般會在上線之前處理這些問題:
· 檢測 HTML 是否符合規(guī)范
· 檢測 https 升級情況
· 檢測鏈接合法性
· 檢測靜態(tài)資源合法性
· 檢測 JavaScript 報錯
· 檢測頁面加載時是否有彈出框
· 檢測頁面是否調(diào)用 console.*
· 頁面 JS 內(nèi)存記錄
當(dāng)然,也可以自己添加測試用例,比如檢測接口數(shù)據(jù)格式、模塊天窗問題等。自動化檢測也可以設(shè)定定時回歸,還是比較有保障的。
五、淘寶首頁的敏捷措施
1、健康檢查
頁面模塊眾多,為了能夠追蹤頁面上每一個小點的變化,我在請求、渲染的每一個環(huán)節(jié)都做了詳細(xì)的統(tǒng)計。
一旦接口請求失敗,或者接口走了容災(zāi)邏輯,或者模塊渲染超過 5s,控制臺都會有黃色警報,當(dāng)然此時,也已經(jīng)向服務(wù)器發(fā)送了警報統(tǒng)計。
2、接口 Hub
接口 Hub 是對數(shù)據(jù)請求的管理工具。
頁面很多模塊的渲染都需要一個以上的數(shù)據(jù)源,一旦運營反饋頁面渲染數(shù)據(jù)異常,可以直接通過 Hub 找到數(shù)據(jù),加速 Bug 定位效率。同時 Hub 也可以用來切換環(huán)境,將一個接口的請求切換到日常或者預(yù)發(fā)環(huán)境的接口之中,它是調(diào)試的利器。
3、快捷通道
我在頁面腳本執(zhí)行前后都放了一個快捷操作通道,一旦遇到緊急線上問題,比如樣式錯亂溢出、接口報錯導(dǎo)致天窗等,可以通過快捷通道直接修改頁面的 CSS 和 JS,兩分鐘內(nèi)上線。
不過這類通道只適合緊急問題的修復(fù),畢竟隨意插入 JS 代碼是存在很大風(fēng)險的。
【淘寶首頁的基礎(chǔ)知識】相關(guān)文章:
淘寶客服基礎(chǔ)知識06-29
淘寶網(wǎng)頁美工設(shè)計如何制作網(wǎng)店首頁03-07
詳解手淘首頁的流量導(dǎo)入方式03-07
網(wǎng)站首頁權(quán)重比內(nèi)頁高的原因分析03-18
關(guān)鍵詞做到首頁未必有訂單03-23
Keepalived的基礎(chǔ)知識03-21
滑雪的基礎(chǔ)知識03-20