京東服務(wù)市場(fw.jd.com)是為第三方軟件服務(wù)商和京東商家提供服務(wù)的交易平臺。京東服務(wù)市場是一個業(yè)務(wù)極度復(fù)雜的系統(tǒng),在業(yè)務(wù)上涵蓋了服務(wù)類商品、促銷、計費、訂購、訂單、支付、結(jié)算、退款和發(fā)票等邏輯,幾乎涉及到電商的所有元素。
京東服務(wù)市場架構(gòu)
如上圖所示,商家訂購服務(wù)從單品頁進入,然后查詢很多信息,如價格、評價。在商家點擊立即訂購之前,商家會不停地對比各類服務(wù),從前端到后端所有的服務(wù)基本上都會刷新,那么,每一次刷新,調(diào)用服務(wù)就會承受一次服務(wù)的調(diào)用。當訂單量增加一倍的時候,實際服務(wù)訪問量最少是 10 倍。
那么為了應(yīng)對如此大的調(diào)用量,每年的 618、雙 11,京東服務(wù)市場又做了什么?下面我們會講講 618、雙 11 備戰(zhàn)后面,系統(tǒng)進行重構(gòu),都從哪些方面進行了優(yōu)化,去提高了系統(tǒng)的容災(zāi)性,提高了系統(tǒng)應(yīng)對峰值流量的能力。
首先要整理自己的重構(gòu)思路,大致整理為幾個階段:梳理薄弱點、系統(tǒng)改造、上線和復(fù)盤。
詳細來說,重構(gòu)開始要對系統(tǒng)做一次全面的梳理診斷,其目的就是要找到系統(tǒng)薄弱點。而梳理方法可以從系統(tǒng)部署耦合、UMP 報警 & 日志、慢 SQL & 外部依賴等不同層面作為切入點進行。
在系統(tǒng)改造階段,通過對系統(tǒng)薄弱點的梳理,進行系統(tǒng)架構(gòu)改造方案的設(shè)計,利用二八原理,集中精力到最重要的環(huán)節(jié),即黃金流程的優(yōu)化,最后制定計劃排期。當然,我們可以利用敏捷的思想,小步快跑,持續(xù)優(yōu)化改進。
上線就是臨門一腳,臺上一分鐘,臺下十年功。為了保證上線成功,要進行充分的上線籌備。首先要整理上線計劃和切流方案,其中包括分階段上線、灰度上線等。計劃準備好之后就要進行反復(fù)的壓測和演練,包括極端情況的降級和預(yù)案的啟用等等。經(jīng)驗來講,大多數(shù)上線失敗,反復(fù)回滾的案例,大多一無計劃,二無預(yù)案。
即使進行了周密的上線籌備,上線仍然可能出現(xiàn)意想不到的問題,所以我們要對每一次上線進行復(fù)盤總結(jié),從教訓(xùn)中成長,并總結(jié)出快速定位問題的技能,以及提升工具使用的能力。
我們以此為思路,通過京東服務(wù)市場進行逐一介紹。
一、梳理薄弱點
找出薄弱點的方法有很多,服務(wù)市場作為一個前臺系統(tǒng),我們從最影響用戶感知和體驗的角度進行梳理。
二、系統(tǒng)改造
通過梳理系統(tǒng)薄弱點,甄別出確認的改造點。
1. UMP 監(jiān)控報警 & 日志
我們常說,研發(fā)人員有兩只眼睛,一只是監(jiān)控報警,另一只就是日志,所以無論什么情況監(jiān)控報警日志一定不能少。通過采用 AOP 的方式,對工程所有層進行統(tǒng)一切面添加監(jiān)控報警和日志。
特別要說的是,設(shè)置了報警一定要即時處理和優(yōu)化,無論是性能報警還是可用率報警,需專人跟進推動優(yōu)化,如果改動量很大或風(fēng)險很高,可調(diào)整報警閾值備注后期優(yōu)化,警醒狼來了的情況。
2. 確認大流量頁面超時時間
超時時間的設(shè)置采用少超時、多重試,這實際上是一種快速失敗策略,如第三方接口調(diào)用超時,如果設(shè)置過長,在訪問量大的時候,就會導(dǎo)致請求線程積壓、CPU 飆高等問題。
超時設(shè)置一是全面檢查 MySQL、JimDB、JSF 等 RPC 調(diào)用的超時設(shè)置,尤其是大流量入口的調(diào)用鏈路,二是根據(jù)壓測結(jié)果結(jié)合具體業(yè)務(wù)場景進行設(shè)置調(diào)整。
3. 解決慢 SQL 問題
慢 SQL 問題大多數(shù)情況下都是沒有索引或者索引使用錯誤引起的,如索引字段是 varchar 類型,但是程序中請求 DB 的時候傳的是 long 類型,造成索引失效。
首先通過 DBA 找出慢 SQL,其中重點關(guān)注調(diào)用次數(shù)高和響應(yīng)速度慢的 SQL,通過 Query ID 找到對應(yīng)的 SQL,然后通過 EXPLAIN 執(zhí)行計劃查看 SQL 命中的索引。添加索引一定要結(jié)合 MySQL 執(zhí)行計劃來判斷,同時添加 Index 要注意區(qū)分度,區(qū)分度 =count(Distinct 索引值)/總條數(shù),區(qū)分度越接近 1,說明區(qū)分度越高,查詢的時候就會過濾掉更多的行數(shù)據(jù)。如果某些 SQL 操作有大量的 JOIN 操作,就要想辦法拆分 SQL,修改代碼邏輯,這也是一種平衡的過程。
4. 降級開關(guān)
降級開關(guān)可以防止問題發(fā)生的時候準備好的功能不可用,以下圖 Solr 降級開關(guān)為例,當 so 出問題時,我們可以關(guān)閉 so 的寫邏輯,sa 和 sb 不影響繼續(xù)寫,同時將讀邏輯切換到 sa,做到平滑切換。當 so 恢復(fù)之后,開啟 so 的寫邏輯,將讀邏輯開關(guān)切換到 so,也能做到平滑恢復(fù)。當然,要注意 so 故障時段可能出現(xiàn)的數(shù)據(jù)不一致問題。
5. 讀寫分離 + 多級緩存策略
緩存策略可以有效防止請求直達數(shù)據(jù)庫,造成數(shù)據(jù)庫壓力大的問題。本次重構(gòu)采用的緩存策略是 JVM+JimDB+DB,緩存的數(shù)據(jù)主要是列表頁 / 頻道頁和單品頁的服務(wù)類目和服務(wù)信息。在啟動緩存策略的過程中,也要考慮緩存的穿透率,以此來調(diào)整緩存最優(yōu)的過期時間。
不僅如此,我們還要將緩存 JimDB 中間件的不穩(wěn)定因素的考慮放到備案中,如多機房的部署采用幾主幾從,主從之間是否支持自動切換等等。
服務(wù)信息多級緩存策略架構(gòu)
在使用 JimDB 緩存時:
要注意大 Key 問題,否則量一上來很容易引起緩存集群的單片熱點問題,如服務(wù)信息可以根據(jù) SpuId 的緯度來設(shè)置 Key,但緩存服務(wù)信息會造成實時價格延遲,可以通過數(shù)據(jù)異構(gòu)的方式同步價格數(shù)據(jù)。
要注意緩存過期的問題,不建議使用 JimDB 的過期設(shè)置,而是自定義 timestamp 由應(yīng)用程序判斷是否過期,這樣可以在 DB 宕機不確定恢復(fù)時間的情況下,仍能從緩存獲取數(shù)據(jù)。
對于那些“尺寸較小”、“高頻的讀取操作”、“變更操作較少”的數(shù)據(jù)應(yīng)全部由 JimDB 來抗量,如服務(wù)類目,每個類目 ID 作為緩存 Key,可以通過雙寫或數(shù)據(jù)異構(gòu)的方式。
6. Solr 災(zāi)備策略(列表頁 / 頻道頁)
Solr 的使用主要服務(wù)于搜索和列表頁多維度的檢索,但是 Solr 集群情況非常不樂觀,如果 Solr 宕機,不僅搜索不可用,更糟糕的是服務(wù)市場列表頁完全不可用,所以對 Solr 的災(zāi)備成為當務(wù)之急。
當然 Solr 的災(zāi)備策略可以參考服務(wù)類目和服務(wù)信息的多級緩存策略,但是列表頁可能涉及到的熱點問題和分頁邏輯都使問題變得更加復(fù)雜。其實 Solr 的最優(yōu)替換方案應(yīng)該是 ES,但一方面限于資源問題,另一方面原檢索邏輯復(fù)雜,改造限于時間條件,又可能風(fēng)險極大,所以主要考慮用 DB+JimDB 進行容災(zāi)。
如果用 Solr 搜索切 DB&JimDB 拖底,如果 Solr 降級 DB,那 DB 是否有足夠的抗壓能力支持多維度的檢索?無論怎么想,這都不是一個好主意,而且經(jīng)驗告訴我們,DB 就不是用來抗量的。那如果 Solr 降級 JimDB,如何針對多維度檢索設(shè)計 JimDB 的 Key?過多的 Key 不僅會產(chǎn)生大量的數(shù)據(jù),還會有相當?shù)某杀颈WC數(shù)據(jù)一致性,所以 JimDB 拖底作為一個過渡方案,當 Solr 降級 JimDB 時,同時也進行了降緯,只保證通常檢索方式。
綜上,雖然 Sorl 可以降級 JimDB,但 Solr 的單機問題是必須解決的問題,所以 Solr 集群部署采用二主一備的災(zāi)備架構(gòu),當廊坊機房 Solr 主 s0 或馬駒橋的 Solr 主 S1 出問題,可以切換 Solr 備,如果此過程中,Solr 備直接被流量擊垮,則直接降級切換對應(yīng)機房的 Jimdb 從,如果還是扛不住,就啟動靜態(tài)頁拖底。
7. 首頁分流加載
官網(wǎng)首頁是一個網(wǎng)站的門戶,如果首頁進不去,那作為一個交易平臺更不能進入列表頁、單品頁或結(jié)算頁了,所以特別需要注意首頁的加載性能和開天窗的問題,也正基于此,對首頁的加載采用異步分流加載,不同的區(qū)域調(diào)用不同的請求,不同的請求數(shù)據(jù)又相互隔離,并通過分流加載提升加載速度,同時不把雞蛋都放在一個籃子里,保證頁面的容災(zāi)和降級。
8. 單品頁加載優(yōu)化
分流加載的思想也可以應(yīng)用在單品頁中,以保證可細粒度地降級。單品頁的特殊性在于實時價格,直接采用緩存可能會造成價格延遲,導(dǎo)致在單品頁看到的價格與結(jié)算頁不一致,所以對單品頁添加緩存時處理實時價格需要進行雙寫操作,以此保證單品頁價格的實時性。
發(fā)布服務(wù)更新價格,寫 MySQL,通過異步任務(wù)更新主 JimDB 價格數(shù)據(jù)。服務(wù)信息讀取主 JimDB 中價格,無過期則直接返回,過期或未命中則訪問主 MySQL,獲取最新數(shù)據(jù)返回用戶,同時異步更新主 JimDB 價格。
三、上線
1. 壓測
通過梳理系統(tǒng)薄弱點并進行系統(tǒng)改造部署上線之后,我們就要對線上真正能承載能力進行壓測,通過壓測知道系統(tǒng)的極限值是多大,當系統(tǒng)承受不住訪問時,就會再暴露出瓶頸,如服務(wù)器 CPU、數(shù)據(jù)庫、內(nèi)存、響應(yīng)速度等,從而促使我們再進行優(yōu)化。線上壓測是在凌晨一兩點,從線上剝離出一小部分集群,所有服務(wù)器和配置使用的都是線上真實的場景進行壓測,壓測場景分為讀業(yè)務(wù)和寫業(yè)務(wù)。
首先,我們進行了兩次壓測,在未優(yōu)化前進行了一次壓測,通過對壓測結(jié)果的分析,看看系統(tǒng)瓶頸主要出現(xiàn)在哪里。第一次壓測結(jié)果發(fā)現(xiàn)大量請求穿透直接調(diào)用 DB,造成 DB 的性能急劇下降,數(shù)據(jù)庫服務(wù)器的 CPU 多次飆高,這成為我們重構(gòu)優(yōu)化的重點,優(yōu)化慢 SQL,進行數(shù)據(jù)庫讀寫分離,添加多級緩存,優(yōu)化系統(tǒng)調(diào)用等。
根據(jù)第一次壓測結(jié)果結(jié)果進行優(yōu)化后,第二次壓測性能有了很大的提升。
2. 演練
在壓測演練過程中,也暴露出很多問題,如數(shù)據(jù)配置錯誤未校驗、服務(wù)器內(nèi)存未調(diào)整、使用新擴容機器壓測等,這導(dǎo)致出現(xiàn)了一連串的問題。壓測開始服務(wù)器 CPU90%,數(shù)據(jù)庫無任何響應(yīng),因為數(shù)據(jù)庫配置錯誤導(dǎo)致服務(wù)器根本沒有連接到數(shù)據(jù)庫。服務(wù)器內(nèi)存 1G 造成頻繁 Full GC,性能總是提升不上去。新服務(wù)器造成很多配置未同步、權(quán)限未申請,花費很多時間解決,影響壓測主流程。
3. 預(yù)案
預(yù)案的執(zhí)行包括發(fā)現(xiàn)問題、定位問題和解決問題。發(fā)現(xiàn)問題要結(jié)合軟硬件問題,定位問題包括監(jiān)控報警和日志分析,這就要看之前添加監(jiān)控的粒度和日志是否打的有用,最后就是解決問題。
系統(tǒng)上線之后,系統(tǒng)性能負載也略有飄高,UMP 報警也接踵而至,通過監(jiān)控和日志迅速排查線上隱患和風(fēng)險,供不同程度啟用降級預(yù)案。
關(guān)于一些技術(shù)實現(xiàn)方面的我找朋友錄制了一些視頻感興趣可以看看,很多問題其實答案很簡單,但是背后的思考和邏輯不簡單,要做到知其然還要知其所以然。如果想學(xué)習(xí)Java工程化、高性能及分布式、深入淺出。微服務(wù)、Spring,MyBatis,Netty源碼分析的朋友可以加我的Java進階群:318261748 群里有阿里大牛直播講解技術(shù),以及Java大型互聯(lián)網(wǎng)技術(shù)的視頻免費分享給大家。
四、復(fù)盤
服務(wù)市場這次系統(tǒng)重構(gòu)還是非常順利的。而在整個過程中也暴露出了很多問題,有一點是上述沒有提到的,那就是心理因素的培訓(xùn)。如在壓測演練時,前期由于遇到各種問題導(dǎo)致結(jié)果遲遲不能到達預(yù)期效果,整體團隊開始出現(xiàn)急躁,處理操作開始變形,出現(xiàn)質(zhì)疑聲音進行自我否定等,還好后期即時調(diào)整,過程逐漸進入正軌,大家開始慢慢恢復(fù)常態(tài)。
所以,真正上線前我們就開始進行了小復(fù)盤,針對心理心態(tài)進行了調(diào)整和培訓(xùn),并完善了預(yù)案等內(nèi)容。在上線時出現(xiàn)的問題,團隊保持很好的心態(tài)處理線上的問題,而整個系統(tǒng)也非常給力地穩(wěn)定運行。
總結(jié)
最后,總結(jié)歷次的大促所面臨的技術(shù)難點,最重要的還是服務(wù)治理,因為我們要打造的不是一個系統(tǒng),也不是一堆系統(tǒng),而是一個平臺生態(tài),要能夠持續(xù)地提高系統(tǒng)的運營能力。這里還是以“精打細算,大道至簡”這句話結(jié)束此次京東服務(wù)市場的總結(jié)。