京東上千頁面搭建基石——CMS前后端分離演進(jìn)史
京東CMS簡介
CMS即內(nèi)容管理系統(tǒng)(ContentManagementSystem),目的是用于快速進(jìn)行網(wǎng)站建設(shè)或者網(wǎng)頁開發(fā)。對于京東網(wǎng)站部門來說,CMS核心目的是用來快速開發(fā)和上線各種頁面,諸如各種垂直頻道頁,訪問www.jd.com將看到如下頁面,如點(diǎn)擊“服裝城”、“家用電器”等都會(huì)跳轉(zhuǎn)到一個(gè)垂直頻道頁;這些頁面中有許多頁面風(fēng)格是類似的,因此很適合使用CMS進(jìn)行快速搭建。
對于我們來說,CMS最核心的目的就是進(jìn)行數(shù)據(jù)和模板的統(tǒng)一管理、頁面的統(tǒng)一發(fā)布,從而減少之前的很多重復(fù)工作。
京東CMS是2014年提出來的,經(jīng)過兩年多的完善,目前已經(jīng)發(fā)展為一個(gè)集標(biāo)準(zhǔn)服務(wù)管理、標(biāo)準(zhǔn)組件服務(wù)和智能投放于一體的標(biāo)準(zhǔn)化導(dǎo)購運(yùn)營系統(tǒng)。具有以下特點(diǎn):
1. 搭建快速,統(tǒng)一發(fā)布,統(tǒng)一架構(gòu);
2. 前后端分離,后端不再負(fù)責(zé)頁面渲染,只提供高性能、可復(fù)用的API;
3. 移動(dòng)端頁面支持;
4. 數(shù)據(jù)分析、智能投放的特點(diǎn);
業(yè)務(wù)支持場景:
首頁、頻道頁、垂直頁、活動(dòng)頁的搭建及單品頁、列表頁部分可維護(hù)的業(yè)務(wù)等。
從基本功能及架構(gòu)來看,可以分為三個(gè)階段:
CMS 1.0——虛擬分類系統(tǒng)
CMS 2.0——CMS系統(tǒng)
CMS 3.0——CMS-portal系統(tǒng)
CMS 1.0—虛擬分類系統(tǒng)
虛擬分類系統(tǒng)是一個(gè)獨(dú)立的促銷商品、促銷文字維護(hù)系統(tǒng),與具體前端業(yè)務(wù)架構(gòu)脫離,哪條線接入虛擬分類,需要根據(jù)自己的業(yè)務(wù)邏輯單獨(dú)開發(fā)、維護(hù)、部署自己的架構(gòu)。說白了,虛擬分類系統(tǒng)提供一些基礎(chǔ)數(shù)據(jù);然后比如我要搭建一個(gè)家電頻道頁,則需要開發(fā)一個(gè)Web項(xiàng)目,然后調(diào)用虛擬分類系統(tǒng)獲取數(shù)據(jù)然后進(jìn)行模板渲染處理處理。因此虛擬分類系統(tǒng)當(dāng)時(shí)只是一個(gè)基礎(chǔ)數(shù)據(jù)維護(hù)平臺(tái),無法實(shí)現(xiàn)信息的共享、復(fù)用和集約化管理。這就會(huì)存在各種各樣的頻道頁系統(tǒng),導(dǎo)致管理混亂,性能上各有差異,出現(xiàn)過很多次事故。而且各系統(tǒng)需要獨(dú)立配置,導(dǎo)致工作量大,占用資源多,無法快速響應(yīng)業(yè)務(wù)需求。
下圖是當(dāng)時(shí)不同業(yè)務(wù)體系的架構(gòu):
可以看出部分頻道頁和活動(dòng)頁用的nginx+tomcat,部分頻道及垂直站用的nginx+php-fpm,與虛擬分類聯(lián)系不大,總體遵循各業(yè)務(wù)層獲取虛擬分類的數(shù)據(jù),分別獨(dú)立上線、部署、維護(hù),應(yīng)用層直連mysql,mysql 抗不住,會(huì)增加一層 memcache。
CMS 2.0—CMS系統(tǒng)
Cms2.0總結(jié)了1.0時(shí)的不足,從節(jié)省資源、控制成本的角度考慮,把導(dǎo)購類的個(gè)體頁面業(yè)務(wù)進(jìn)行了統(tǒng)一,模板能復(fù)用的復(fù)用,以前虛擬分類系統(tǒng)的頻道也需要遷移到新的系統(tǒng)。
我們做了以下改動(dòng):
1. CMS 2.0數(shù)據(jù)結(jié)構(gòu)適合虛擬分類體系,方便新老數(shù)據(jù)兼容;
2. 升級架構(gòu),統(tǒng)一配置、發(fā)布流程;去memcache為redis,做大量性能壓測來調(diào)優(yōu)php-fpm配置,單機(jī)TPS能達(dá)到3000+; 配置定時(shí)任務(wù),保證redis數(shù)據(jù)實(shí)時(shí)性;
3. 單點(diǎn)發(fā)布,一鍵預(yù)覽增強(qiáng)采銷維護(hù)數(shù)據(jù)的機(jī)動(dòng)性;
4. 單機(jī)閉環(huán),單機(jī)閉環(huán)服務(wù)設(shè)計(jì)是CMS整體架構(gòu)的核心部分,需要展示的內(nèi)容在本機(jī)獲取、封裝、校驗(yàn);
5. 模塊化、動(dòng)態(tài)數(shù)據(jù)類型初期版本(CMS 3.0會(huì)細(xì)說);
架構(gòu)圖:
對比1.0,新的CMS可以讓頻道頁的開發(fā)周期降低2~4周,大大提高了業(yè)務(wù)需求的響應(yīng)速度;它看起來更獨(dú)立,更像一個(gè)整體,在容災(zāi)、規(guī)避風(fēng)險(xiǎn)方面做了嚴(yán)謹(jǐn)?shù)膬?yōu)化;同時(shí)讓采銷在維護(hù)數(shù)據(jù)時(shí),更方便、更簡單。
后續(xù)由于個(gè)性化的需求越來越多,大量的頻道業(yè)務(wù)需要開發(fā)人員一個(gè)一個(gè)套模板來實(shí)現(xiàn),大大加大了開發(fā)人員的工作強(qiáng)度,之前的模板復(fù)用方式已經(jīng)無法滿足業(yè)務(wù)的需求,同時(shí)太簡單的數(shù)據(jù)模塊,需要手工來綁定數(shù)據(jù)類型也增加了開發(fā)成本,這時(shí)候需要我們必須做出改變。
CMS 3.0—CMS-portal系統(tǒng)
CMS 2.0后也存在很多痛點(diǎn),因此我們也想在CMS3.0上解決這些問題:
1. 本質(zhì)問題就是要快:快速支持、響應(yīng)業(yè)務(wù)越來越多的垂直化頁面改版;
2. 前后端分離,頁面渲染讓前端實(shí)現(xiàn),解放后端讓后端做高大上的事情;
3. 減輕運(yùn)營人員的工作量,系統(tǒng)簡單好用,提高導(dǎo)購類商品的轉(zhuǎn)化率;
4. 其他系統(tǒng)的支撐,實(shí)現(xiàn)CMS的集約化管理;
5. 兼容手機(jī)端;
6. 站點(diǎn)管理、統(tǒng)一架構(gòu)、容災(zāi)、高性能、水平擴(kuò)容;
通過兩版CMS系統(tǒng)的開發(fā),我們發(fā)現(xiàn)CMS無外乎管理的是數(shù)據(jù)和模板,另外需要好的預(yù)覽、一鍵發(fā)布支持。而傳統(tǒng)數(shù)據(jù)管理都是靜態(tài)數(shù)據(jù)類型,而我們做了動(dòng)態(tài)數(shù)據(jù)類型的設(shè)計(jì);另外我們做了模板管理中心,并抽象了模板、樓層、元件、模塊的概念,從而實(shí)現(xiàn)更好的復(fù)用性。
統(tǒng)一架構(gòu)
主要分為如下幾部分
- CMS系統(tǒng):統(tǒng)一管理CMS相關(guān)數(shù)據(jù),并進(jìn)行頁面的生成和發(fā)布;
- 數(shù)據(jù)Worker管理中心:調(diào)用第三方服務(wù)進(jìn)行數(shù)據(jù)校驗(yàn)(如庫存不足補(bǔ)貨),并調(diào)用CMS系統(tǒng)進(jìn)行頁面生成和發(fā)布,發(fā)布到單點(diǎn)服務(wù)器上;
- 單點(diǎn)服務(wù)器:相關(guān)頁面的單機(jī)閉環(huán)實(shí)現(xiàn),即CMS發(fā)布的頁面會(huì)存儲(chǔ)在這些單點(diǎn)服務(wù)器上;每個(gè)機(jī)房會(huì)部署一臺(tái);
- 頁面定時(shí)更新Worker:定期同步單點(diǎn)服務(wù)器內(nèi)容到靜態(tài)應(yīng)用服務(wù)器集群,并保存歷史版本,當(dāng)出現(xiàn)問題時(shí)可以切換回上一個(gè)版本;
- 靜態(tài)應(yīng)用服務(wù)器集群:靜態(tài)托底實(shí)現(xiàn),會(huì)存儲(chǔ)相關(guān)的靜態(tài)頁面文件,當(dāng)單點(diǎn)服務(wù)器掛了時(shí),降級到該集群;
- 異步加載的個(gè)性化服務(wù):有些數(shù)據(jù)不能存儲(chǔ)到靜態(tài)頁,如價(jià)格/庫存/推薦等數(shù)據(jù),此時(shí)通過異步加載這些數(shù)據(jù),實(shí)現(xiàn)個(gè)性化服務(wù);
- 接入層Nginx:接入層Nginx負(fù)責(zé)請求的路由和服務(wù)的降級。
主要思路
1. 引入動(dòng)態(tài)數(shù)據(jù)類型;
2. 頁面模板管理中心,模板、樓層、元件、模塊設(shè)計(jì),實(shí)現(xiàn)可復(fù)用;
3. 使用元件實(shí)現(xiàn)前后端分離;
4. 動(dòng)態(tài)服務(wù)和業(yè)務(wù)數(shù)據(jù)閉環(huán);
5. 預(yù)覽、一鍵發(fā)布,單點(diǎn)管理;
6. H5版直接搭建,native版 API 支持;
7. 大數(shù)據(jù)智能選品應(yīng)用;
動(dòng)態(tài)數(shù)據(jù)類型
所謂的動(dòng)態(tài)是指能靈活擴(kuò)展的,不需要上線也不需要修改數(shù)據(jù)庫字段,支持自由擴(kuò)展;這樣做的好處是能夠快速響應(yīng)電商網(wǎng)站的日益靈活多變的促銷需求。比如促銷語:
目前常用的數(shù)據(jù)類型為文字鏈、小圖文、商品池等。
操作界面:
動(dòng)態(tài)數(shù)據(jù)類型數(shù)據(jù)結(jié)構(gòu):
fields是json串,用于動(dòng)態(tài)定義字段。
使用元件實(shí)現(xiàn)前后端分離
使用動(dòng)態(tài)數(shù)據(jù)類型定義了數(shù)據(jù)之后,需要在模板中使用它。而在我們CMS系統(tǒng)中進(jìn)行了頁面、模板、樓層、元件、模塊的劃分。模塊是某種數(shù)據(jù)類型的具體化,即有了數(shù)據(jù)的數(shù)據(jù)類型。元件是由模塊和HTML代碼段(根據(jù)模塊數(shù)據(jù)進(jìn)行渲染的一小段模板)組成;樓層通過一系列元件組成,而模板會(huì)引入多個(gè)樓層,當(dāng)然也會(huì)引入一些JS、CSS等,最終通過模板渲染出相應(yīng)頁面。
type是數(shù)據(jù)類型表,module是模塊表,source是數(shù)據(jù)表,按照上面的邏輯我們是通過數(shù)據(jù)類型獲取到數(shù)據(jù)模塊,并同時(shí)能拿到該模塊所對應(yīng)的商品數(shù)據(jù)(商品池)。
有了這個(gè)元件之后,就可以徹底解放后端,頁面渲染工作完全交由前端來開發(fā),實(shí)現(xiàn)了前后端的分離。
即CMS研發(fā)只負(fù)責(zé)平臺(tái)和基礎(chǔ)數(shù)據(jù)(動(dòng)態(tài)服務(wù))的維護(hù),業(yè)務(wù)人員進(jìn)行模塊的維護(hù),而前端人員獨(dú)立完成元件開發(fā)、模板設(shè)計(jì)、開發(fā)和發(fā)布。
動(dòng)態(tài)服務(wù)
跨線條業(yè)務(wù)間的資源復(fù)用、獨(dú)立調(diào)用時(shí)需要提供相關(guān)的API,如三級地址服務(wù),類目服務(wù)、動(dòng)態(tài)加載的數(shù)據(jù)(如爆款特賣、今日推薦等)等。數(shù)據(jù)格式滿足數(shù)據(jù)閉環(huán)原則。Lua+redis架構(gòu)實(shí)現(xiàn),單機(jī)(16U)QPS能達(dá)到20000+。
頻道業(yè)務(wù)數(shù)據(jù)閉環(huán)
數(shù)據(jù)閉環(huán),即數(shù)據(jù)的自我管理,或者說數(shù)據(jù)都在自己系統(tǒng)維護(hù),不依賴與其他任何系統(tǒng),去依賴化,這樣得到的好處是別人抖動(dòng)與我沒關(guān)系。因此我們先要數(shù)據(jù)異構(gòu)。
數(shù)據(jù)異構(gòu)是數(shù)據(jù)閉環(huán)的***步,將依賴系統(tǒng)的數(shù)據(jù)拿過來,按照自己的業(yè)務(wù)需求存儲(chǔ)起來。頻道業(yè)務(wù)需要異構(gòu)的數(shù)據(jù)主要是三部分:商品基本信息、第三方數(shù)據(jù)、大數(shù)據(jù)。
數(shù)據(jù)原子化處理,數(shù)據(jù)異構(gòu)的數(shù)據(jù)是原子化數(shù)據(jù),這樣未來我們可以對這些數(shù)據(jù)再加工再處理而響應(yīng)變化的需求。我們有了一份原子化異構(gòu)數(shù)據(jù)雖然方便處理新需求,但恰恰因?yàn)?**份數(shù)據(jù)是原子化的,那么它會(huì)很分散,前端讀取時(shí)mget的話 性能不是很好,因此我們又做了數(shù)據(jù)聚合。
數(shù)據(jù)聚合,是將多個(gè)原子數(shù)據(jù)聚合為一個(gè)大JSON數(shù)據(jù),這樣前端展示只需要一次get,當(dāng)然要考慮系統(tǒng)架構(gòu),比如我們使用的Redis改造,Redis又是單線程系統(tǒng),我們需要部署更多的Redis來支持更高的并發(fā),另外存儲(chǔ)的值要盡可能的小。
容災(zāi)
應(yīng)用層容災(zāi)
1. 數(shù)據(jù)校驗(yàn),CMS在頁面預(yù)覽有一層嚴(yán)格的數(shù)據(jù)校驗(yàn)邏輯,比如數(shù)據(jù)格式、數(shù)據(jù)大小、敏感詞等,保證頁面生成100%沒有問題。
2. 版本降級,靜態(tài)頁面出現(xiàn)問題,除了頁面本身數(shù)據(jù)有問題外,潛入的js、css出現(xiàn)問題也會(huì)影響頁面展示,這時(shí)候會(huì)版本降低為前一天的正確版本;
3. 異步服務(wù),異步化數(shù)據(jù)容災(zāi)方面主要是監(jiān)聽服務(wù)的狀態(tài)及響應(yīng)時(shí)間;降級訪問有隱藏該功能和切換服務(wù)器實(shí)現(xiàn);
服務(wù)器容災(zāi)
主要是通過多機(jī)房部署,監(jiān)控80端口,出現(xiàn)問題可以自動(dòng)把流量水平切走。
智能選品
智能選品,是服務(wù)于前臺(tái)的流量運(yùn)營,為采銷及運(yùn)營人員提供運(yùn)營支持,為每一次訪問提供最合適和匹配的商品、品牌以及促銷活動(dòng)。是根據(jù)用戶的行為推薦出相關(guān)的商品及活動(dòng)。可以分為群體特征和個(gè)體特征。群體特征分為兩部分,數(shù)據(jù)部分及規(guī)則部分。
數(shù)據(jù)部分是從大數(shù)據(jù)平臺(tái)異構(gòu)過來,當(dāng)然這個(gè)數(shù)據(jù)是海量的,我們選擇熱點(diǎn)TOP 5000的數(shù)據(jù)來異構(gòu)。
規(guī)則部分是通過京智后臺(tái)創(chuàng)建,在審核通過后,觸發(fā)MQ,通過ES 跑出對應(yīng)數(shù)據(jù),然后由頻道頁動(dòng)態(tài)服務(wù)系統(tǒng)對外提供json格式的http服務(wù)。前端業(yè)務(wù)以異步的方式傳遞相關(guān)規(guī)則參數(shù)進(jìn)行調(diào)用。
智能選品實(shí)現(xiàn)數(shù)據(jù)化、定制化、個(gè)性化、自動(dòng)及半自動(dòng)化內(nèi)容運(yùn)營。它可以模擬人腦選貨邏輯,以運(yùn)營指標(biāo)為導(dǎo)向(GMV、訂單轉(zhuǎn)化率、點(diǎn)擊量、毛利等),分區(qū)域、分用戶選取最匹配的內(nèi)容。目前應(yīng)用于京東超市、行業(yè)頻道以及618大促主會(huì)場,帶來優(yōu)于人工選品的轉(zhuǎn)化效果,并解放采銷運(yùn)營人員日常繁瑣的運(yùn)營工作,提高了整體效率。
遇到的坑
rsync文件同步
上面的介紹過,我們的靜態(tài)頁面為了保持?jǐn)?shù)據(jù)的一致性由單點(diǎn)服務(wù)器通過rsync同步靜態(tài)文件到其他服務(wù)器,有時(shí)候會(huì)發(fā)現(xiàn)服務(wù)器負(fù)載無端的被打滿。
分析問題發(fā)現(xiàn)如果定時(shí)任務(wù)腳本的同步未在規(guī)定時(shí)間內(nèi)完成,crontab接下來的還會(huì)執(zhí)行此腳本,這樣就會(huì)產(chǎn)生相同的rsync的進(jìn)程。按照這種狀態(tài),長時(shí)間就會(huì)衍生出很多個(gè)rsync進(jìn)程,就會(huì)導(dǎo)致負(fù)載過高,甚至有些服務(wù)器會(huì)掛掉。這時(shí)候我們用到了rsync的進(jìn)程鎖,在目錄下生成一個(gè)rsync.lock文件,當(dāng)crontab執(zhí)行時(shí),rsync會(huì)判斷鎖文件是否存在,如果存在說明本次同步未完成,則不執(zhí)行rsync。
數(shù)據(jù)一定要閉環(huán)
別人的接口抖動(dòng)以及返回?cái)?shù)據(jù)的異常,影響到前端展示對我們來說說是不能容忍的,這就需要我們針對各種情況一一校驗(yàn)。
CMS總結(jié)
目前通過CMS搭建、正在搭建以及使用CMS API支持的PC端、移動(dòng)端頁面約有上千個(gè),這對CMS來說意義重大,隨著業(yè)務(wù)需求量的越來越大,也給我們帶來了新的期望。接下來,我們會(huì)從可視化編輯、數(shù)據(jù)統(tǒng)計(jì)分析、關(guān)鍵詞管理、商品下架預(yù)警等方面進(jìn)行相關(guān)的優(yōu)化工作。
作者:于林坤,2012年加入京東,網(wǎng)站移動(dòng)研發(fā)部頻道業(yè)務(wù)技術(shù)負(fù)責(zé)人,先后多次主導(dǎo)京東商城首頁、頻道頁技改及架構(gòu)升級,在高并發(fā)系統(tǒng)架構(gòu)、前端系統(tǒng)架構(gòu)與優(yōu)化方面有豐富經(jīng)驗(yàn),PHPer。
【本文來自51CTO專欄作者張開濤的微信公眾號(hào)(開濤的博客),公眾號(hào)id: kaitao-1234567】