背景
京東活動系統(tǒng) 是一個可在線編輯卤妒、實時編輯更新和發(fā)布新活動则披,并對外提供頁面訪問服務的系統(tǒng)洗出。其高時效性、靈活性等特征阱洪,極受青睞,已發(fā)展成京東幾個重要流量入口之一承璃。近幾次大促蚌本,系統(tǒng)所承載的pv已經(jīng)達到數(shù)億級。隨著京東業(yè)務的高速發(fā)展玻佩,京東活動系統(tǒng)的壓力會越來越大席楚。急需要一個更高效,穩(wěn)定的系統(tǒng)架構烦秩,來支持業(yè)務的高速發(fā)展。本文主要對活動頁面瀏覽方面的性能兜蠕,進行探討抛寝。
活動頁面瀏覽性能提升的難點:
1. 活動與活動之間差異很大盗舰,不像商品頁有固定的模式。每個頁面能抽取的公共部分有限钻趋,可復用性差蛮位。
2. 活動頁面內容多樣,業(yè)務繁多尸曼。依賴大量外部業(yè)務接口萄焦,數(shù)據(jù)很難做到閉環(huán)。外部接口的性能解幽,以及穩(wěn)定性,嚴重制約了活動頁的渲染速度片部、穩(wěn)定性霜定。
經(jīng)過多年在該系統(tǒng)下的開發(fā)實踐,提出“頁面渲染辖所、瀏覽異步化”的思想磨德,并以此為指導典挑,對該系統(tǒng)進行架構升級改造。通過近幾個月的運行拙寡,各方面性能都有顯著提升琳水。在分享"新架構"之前,先看看我們現(xiàn)有web系統(tǒng)的架構現(xiàn)狀诚啃。
一浑玛、web架構發(fā)展與現(xiàn)狀
1.開發(fā)階段
以京東活動系統(tǒng)架構的演變?yōu)槔苏茫@里沒有畫出具體的業(yè)務邏輯胃碾,只是簡單的描述下架構:
2.第二步仆百,一般是在消耗性能的地方加緩存,這里對部分查庫操作加redis緩存
3.對頁面進行整頁redis緩存:由于活動頁面內容繁多吁讨,渲染一次頁面的成本是很高。這里可以考慮把渲染好的活動內容整頁緩存起來排龄,下次請求到來時翎朱,如果緩存中有值拴曲,直接獲取緩存返回。
以上是系統(tǒng)應用服務層面架構演進的竞川,簡單示意叁熔。為了減少應用服務器的壓力者疤,可以在應用服務器前面,加cdn和nginx的proxy_caxhe革砸,降低回源率糯累。
4.整體架構(老)
除了前3步講的“瀏覽服務”泳姐,老架構還做了其他兩個大的優(yōu)化:“接口服務”、靜態(tài)服務
1.訪問請求缎患,首先到達瀏覽服務阎肝,把整個頁面框架返回給瀏覽器(有cdn风题、nginx嫉父、redis等各級緩存)眼刃。
2.對于實時數(shù)據(jù)(如秒殺)擂红、個性化數(shù)據(jù)(如登陸、個人坐標)弟头,采用前端實時接口調用涉茧,前端接口服務。
3.靜態(tài)服務:靜態(tài)資源分離伦连,所有靜態(tài)js钳垮、css訪問靜態(tài)服務饺窿。
要點:瀏覽服務、接口服務分離绢馍。頁面固定不變部分走瀏覽服務肠套,實時變化、個性化采用前端接口服務實現(xiàn)瓷耙。
接口服務:分兩類刁赖,直接讀redis緩存宇弛、調用外部接口。這里可以對直接讀redis的接口采用nginx+lua進行優(yōu)化( openresty )轿钠,不做詳細講解病苗。 本次分享主要對“瀏覽服務”架構
二硫朦、新老架構性能對比
在講新架構之前先看看新老架構下的新能對比
1.老架構瀏覽服務新能:
擊穿cdn緩存、nginx緩存泽裳,回源到應用服務器的流量大約為20%-40%之間破婆,這里的性能對比,只針對回源到應用服務器的部分瀑梗。
2015雙十一抛丽, 瀏覽方法tp99如下:(物理機)
Tp99? 1000ms左右饰豺,且抖動幅度很大冤吨,內存使用近70%,cpu 45%左右其馏。
1000ms內沒有緩存爆安,有阻塞甚至掛掉的風險。
2.新架構瀏覽服務新能
本次2016 618采用新架構支持褐奥,瀏覽tp99如下(分app端活動和pc端活動):
移動活動瀏覽tp99穩(wěn)定在8ms, pc活動瀏覽tp99 穩(wěn)定在15ms左右撬码。全天幾乎一條直線呜笑,沒有性能抖動。
新架構支持叫胁,服務器(docker)cpu性能如下
cpu消耗一直平穩(wěn)在1%,幾乎沒有抖動驼鹅。
對比結果:新架構tp99從1000ms降低到 15ms,cpu消耗從45%降低到1%豺型,新架構性能得到質的提升买乃。
why!!!
下面我們就來揭開新架構的面紗姻氨。
三.新架構探索
1.?頁面瀏覽为牍,頁面渲染 異步化
再來看之前的瀏覽服務架構,20%-40%的頁面請求會重新渲染頁面抖韩,渲染需要重新計算杂数、查詢、創(chuàng)建對象等導致 cpu返干、內存消耗增加,tp99性能下降谓厘。
如果能保證每次請求都能獲取到redis整頁緩存,這些性能問題就都不存在了属桦。
即:頁面瀏覽他爸,與頁面渲染 異步诊笤。
2.直接改造后的問題以及解決方案:
理想情況下,如果頁面數(shù)據(jù)變動可以通過 手動觸發(fā)渲染(頁面發(fā)布新內容)纪他、外部數(shù)據(jù)變化通過監(jiān)聽mq 自動觸發(fā)渲染。
但是有些外部接口不支持mq馆类、或者無法使用mq,比如活動頁面置入的某個商品句喜,這個商品名稱變化咳胃。
為了解決這個問題,view工程每隔指定時間销睁,向engine發(fā)起重新渲染請求-最新內容放入redis存崖。下一次請求到來時即可獲取到新內容。由于活動很多冗栗,也不能確定哪些活動在被訪問隅居,所以不建議使用timer葛虐。通過加一個緩存key來實現(xiàn),處理邏輯如下:
好處就是涕蚤,只對有訪問的活動定時重新發(fā)起渲染赞季。
四奢驯、新架構講解:
? 整理架構(不包含業(yè)務):
?view工程職責:
? a.直接從緩存或者硬盤中獲取靜態(tài)html返回瘪阁,如果沒有返回錯誤頁面邮偎。(文件系統(tǒng)的存取性能比較低禾进,超過 ? 100ms級別廉涕,這里沒有使用)
? b.根據(jù)緩存key2是否過期,判斷是否向engine重新發(fā)起渲染宠纯。(如果婆瓜,你的項目外面接口都支持mq贡羔,這個 ? ? ?功能就不需要了)
?engine工程職責:渲染活動頁面,把結果放到 硬盤猴蹂、redis晕讲。
?publish工程马澈、mq 職責:頁面發(fā)生變化,向engine重新發(fā)起渲染勤婚。 具體的頁面邏輯涤伐,這里不做講解
Engine工程的工作 就是當頁面內容發(fā)生變化時凝果,重新渲染頁面器净,并將整頁內容放到redis,或者推送到硬盤纠俭。
2.view工程架構(redis 版)
View工程的工作冤荆,就是根據(jù)鏈接從redis中獲取頁面內容返回。
3.view工程架構 (硬盤?版)
?
兩個版本對比
a.Redis版
優(yōu)點:接入簡單乌妒、 性能好芥被,尤其是在大量頁面情況下坐榆,沒有性能抖動 冗茸。單個docker tps達到 700夏漱。
缺點:嚴重依賴京東redis服務,如果redis服務出現(xiàn)問題屎篱,所有頁面都無法訪問葵蒂。
b.硬盤版
優(yōu)點:不依賴任何其他外部服務践付,只要應用服務不掛、網(wǎng)絡正常 就可以對外穩(wěn)定服務隧土。
在頁面數(shù)量不大的情況下命爬,性能優(yōu)越饲宛。單個docker tps達到 2000。
缺點:在頁面數(shù)據(jù)量大的情況下(系統(tǒng)的所有活動頁有xx個G左右)亥啦,磁盤io消耗增加(這里采用的java io,如果采用nginx+lua奴拦,io消耗應該會控制在10%以內)届吁。
解決方案:
a. 對所有頁面訪問和存儲 采用url hash方式,所有頁面均勻分配到各個應用服務器上疚沐。
b. 采用nginx+lua? 利用nginx的異步io亮蛔,代替java io。
4.Openresty+硬盤版
現(xiàn)在通過nginx+lua做應用服務辣吃,所具有的高并發(fā)處理能力芬探、高性能偷仿、高穩(wěn)定性已經(jīng)越來越受青睞。通過上述講解节榜,view工程沒有任何業(yè)務邏輯全跨∫谒欤可以很輕易的就可以用lua實現(xiàn)蛇数,從redis或者硬盤獲取頁面,實現(xiàn)更高效的web服務碌上。如果想學習Java工程化、高性能及分布式天梧、深入淺出呢岗。微服務蛹尝、Spring,MyBatis挫酿,Netty源碼分析的朋友可以加我的Java進階qun:694549689早龟,里面有阿里大牛直播講解技術猫缭,以及Java大型互聯(lián)網(wǎng)技術的視頻免費分享給大家饵骨。
1.具有1-5工作經(jīng)驗的茫打,面對目前流行的技術不知從何下手,需要突破技術瓶頸的可以加轮洋。
2.在公司待久了弊予,過得很安逸开财,但跳槽時面試碰壁责鳍。需要在短時間內進修、跳槽拿高薪的可以加正塌。
3.如果沒有工作經(jīng)驗乓诽,但基礎非常扎實,對java工作機制讼育,常用設計思想粮宛,常用java開發(fā)框架掌握熟練的可以加。
通過測試對比忧饭,view工程讀本地硬盤的速度词裤,比讀redis還要快(同一個頁面鳖宾,讀redis是15ms鼎文,硬盤是8ms)。所以終極版架構我選擇用硬盤周偎,redis做備份蓉坎,硬盤讀不到時在讀redis胡嘿。
這里前置機的url hash是自己實現(xiàn)的邏輯,engine工程采用同樣的規(guī)則推送到view服務器硬盤即可衷敌,具體邏輯這里不細講勿侯。后面有時間再單獨做一次分享。?
優(yōu)點:具備硬盤版的全部優(yōu)點逢享,同時去掉tomcat罐监,直接利用nginx高并發(fā)能力,以及io處理能力瞒爬。各項性能弓柱、以及穩(wěn)定性達到最優(yōu)沟堡。
缺點:1、硬盤壞掉航罗,影響訪問。2.方法監(jiān)控屁药,以及日志打印粥血,需使用lua腳本重寫。
五:總結
無論是redis版酿箭、硬盤版复亏、openresty+硬盤版,基礎都是頁面瀏覽與頁面渲染異步化缭嫡。
優(yōu)勢:
1缔御、所有業(yè)務邏輯都剝離到engine工程,新view工程理論上永遠無需上線妇蛀。
2耕突、災備多樣化(redis、硬盤评架、文件系統(tǒng))眷茁,且更加簡單,外部接口或者服務出現(xiàn)問題后纵诞,切斷engine工程渲染上祈,不再更新redis和硬盤即可。
3浙芙、新view工程雇逞,與業(yè)務邏輯完全隔離,不依賴外部接口和服務茁裙,大促期間,即便外部接口出現(xiàn)新能問題节仿,或者有外部服務掛掉晤锥,絲毫不影響view工程正常訪問。
4廊宪、性能提升上百倍矾瘾,從1000ms提升到10ms左右。詳見前面的性能截圖箭启。
5壕翩、穩(wěn)定性:只要view服務器的網(wǎng)絡還正常,可以做到理論上用不掛機傅寡。
6放妈、大幅度節(jié)省服務器資源北救,按此架構,4+20+30=54個docker足以支持10億級pv芜抒。(4個nginx proxy_cache珍策、20個view,30個engine)
六:結束語
?從事開發(fā)已有近10載宅倒,一直就像寄生蟲一樣吸取著網(wǎng)絡上的資源攘宙。前段時間受“張開濤”大神所托,對活動系統(tǒng)新架構做了一次簡單整理分享給大家拐迁,希望能給大家?guī)硪唤z幫助蹭劈。第一次在網(wǎng)上做分享,難免有些沒有考慮周全的地方线召,以后會慢慢的多分享一些自己的心得铺韧,大家一起成長。最后再來點心靈雞湯灶搜。祟蚀。。