作為技術(shù)研發(fā)人員启绰,我們常戲稱(chēng)京東每年只干兩件事跋破,一個(gè)是618簸淀,另外一個(gè)是雙11.確實(shí)每一次的大促都是一場(chǎng)全兵演練,技術(shù)人員在這場(chǎng)戰(zhàn)斗中毒返,從團(tuán)隊(duì)合作租幕、技術(shù)提升、用戶意識(shí)上都有一個(gè)立體的提高拧簸。實(shí)難想象還有比這樣規(guī)模的促銷(xiāo)再有更好的鍛煉方式劲绪。
京麥平臺(tái)是目前京東所有商家唯一使用的一站式店鋪運(yùn)營(yíng)管理平臺(tái),商家借助京麥可以實(shí)現(xiàn)商品發(fā)布盆赤、打印訂單贾富、出庫(kù)、訂單消息接收等等一系列的日常工作牺六,京麥平臺(tái)更是集合了眾多ISV廠商為商家提供了更加豐富的功能颤枪,更好的賦能于商家。京麥平臺(tái)的技術(shù)架構(gòu)也在隨著京東業(yè)務(wù)的飛速發(fā)展不斷演化著淑际。從早期的簡(jiǎn)單nginx+tomcat部署畏纲,到現(xiàn)在功能服務(wù)模塊化,獨(dú)立部署春缕,享受著微服務(wù)帶來(lái)的便利盗胀,但同時(shí)也給我們大促的備戰(zhàn)帶來(lái)了幾多挑戰(zhàn)。
首先確定自己的備戰(zhàn)思路锄贼,梳理核心流程读整、找出薄弱點(diǎn),對(duì)薄弱點(diǎn)具體優(yōu)化,同時(shí)協(xié)調(diào)壓測(cè)對(duì)優(yōu)化結(jié)果驗(yàn)證米间,優(yōu)化和壓測(cè)會(huì)有一個(gè)反復(fù)的過(guò)程强品,后面我們還要實(shí)際演練,比如降級(jí)開(kāi)關(guān)屈糊,防止實(shí)際情況發(fā)生的時(shí)候準(zhǔn)備好的功能不可用的榛,最后我們要做一輪培訓(xùn),在工具使用逻锐,快速定位問(wèn)題夫晌,歷來(lái)的教訓(xùn)總結(jié)都過(guò)一遍,從心理層面上我們也要輔導(dǎo)昧诱,大促期間發(fā)生的問(wèn)題都不是小問(wèn)題晓淀,研發(fā)人員在這種壓力下處理問(wèn)題有時(shí)候會(huì)變形,我們會(huì)在這方面做一次心理疏解盏档。這中間我們可以利用幾個(gè)規(guī)則凶掰,二八法則,找出20%重要核心的功能蜈亩,比如京麥的登錄懦窘、交易、價(jià)格門(mén)消息推送稚配。在找薄弱點(diǎn)的時(shí)候我們可以試試墨菲定律的幾點(diǎn)規(guī)則畅涂,“可能出錯(cuò)的事總會(huì)出錯(cuò)”,“如果你擔(dān)心某種情況發(fā)生道川,那么他就有可能發(fā)生”午衰,最后我們還會(huì)找大家一起列出你心中最不可能出現(xiàn)問(wèn)題的系統(tǒng)和功能點(diǎn),那么列出來(lái)重點(diǎn)對(duì)待冒萄,沒(méi)錯(cuò)臊岸,是重點(diǎn)對(duì)待。
我們常用的備戰(zhàn)技術(shù)宦言,肯定不是重啟扇单,回滾,加機(jī)器奠旺,^_^蜘澜。這里面?zhèn)€人總結(jié)有分離技術(shù),緩存技術(shù)响疚,SQL優(yōu)化鄙信,快速失敗,降級(jí)限流忿晕。我們來(lái)逐一介紹装诡。
分離技術(shù):
話說(shuō)“天下大事,合久必分,分久必合”鸦采,但在軟件架構(gòu)領(lǐng)域宾巍,一直是一個(gè)分的趨勢(shì),比如京麥平臺(tái)有提供ISV的服務(wù)渔伯、提供京麥自有客戶端的服務(wù)顶霞、提供其他平臺(tái)的服務(wù),同時(shí)還有監(jiān)控服務(wù)锣吼,日志服務(wù)选浑,消息服務(wù)等,需要將業(yè)務(wù)服務(wù)隔離部署玄叠,線下分析和線上運(yùn)行隔離古徒,同時(shí)還可以采取線程隔離,比如JSF里面為每個(gè)不同重要的服務(wù)分別一個(gè)線程組的方式读恃。數(shù)據(jù)庫(kù)層面上主從分離隧膘,京麥平臺(tái)的業(yè)務(wù)都是讀多寫(xiě)少,可以充分利用分庫(kù)的資源狐粱。還可以再將數(shù)據(jù)庫(kù)細(xì)分舀寓,按照主要業(yè)務(wù)拆分不同的數(shù)據(jù)庫(kù)胆数,結(jié)合RPC使用肌蜻,更大降低數(shù)據(jù)庫(kù)層面的耦合程度。
緩存技術(shù):
如果軟件里面真的有一種銀彈的話必尼,我認(rèn)為就是緩存蒋搜,當(dāng)你性能優(yōu)化遇到瓶頸的時(shí)候,當(dāng)你想抗量的時(shí)候判莉,你都會(huì)想到緩存豆挽。這里有一個(gè)鐵律,那就是券盅,對(duì)外暴露的接口一定不能直達(dá)數(shù)據(jù)庫(kù)帮哈。我們常用的緩存是redis+jvmcache。計(jì)算redis穿透率的時(shí)候我們可以锰镀,通過(guò)UMP來(lái)實(shí)現(xiàn)娘侍,在一個(gè)方法的總?cè)肟诼顸c(diǎn),比如統(tǒng)計(jì)出1分鐘調(diào)用M次泳炉,在請(qǐng)求redis的入口埋點(diǎn)憾筏,統(tǒng)計(jì)出1分鐘調(diào)用N次,計(jì)算命中率:N/M.花鹅。在使用redis的時(shí)候要注意含有大數(shù)值的key氧腰,常常量一上來(lái)會(huì)造成redis集群的熱點(diǎn)訪問(wèn),直接將單一節(jié)點(diǎn)打死。這樣的情況下我們就要拆分這樣的大key古拴。同時(shí)將緩存DB化箩帚,就是不設(shè)置超時(shí)時(shí)間,這樣全部用redis來(lái)抗量黄痪。本地緩存這塊我們常用的有Guava-cache膏潮,通過(guò)本地緩存我們可以做三級(jí)防護(hù),或者做托底數(shù)據(jù)等满力。如果數(shù)據(jù)“尺寸較小”、“高頻的讀取操作”油额、“變更操作較少”使用這種嵌入式緩存將非常合適。
SQL優(yōu)化:
每次大促前我們都要將系統(tǒng)中性能慢的sql抓出來(lái)潦嘶,而且這種工作投入產(chǎn)出比極高涩嚣,也就是可以花費(fèi)較小代價(jià)帶來(lái)極大的性能收益掂僵。sql性能問(wèn)題,大多數(shù)情況下是沒(méi)有索引引起的锰蓬,這可能是后續(xù)業(yè)務(wù)變化迅速幔睬,上線前代碼review的遺漏,需要這個(gè)時(shí)候統(tǒng)一過(guò)一遍芹扭。還有就是索引使用錯(cuò)誤舱卡,比如索引字段是字符串類(lèi)型,但是程序中請(qǐng)求DB的時(shí)候傳的是long類(lèi)型轮锥,索引失效,表中數(shù)量過(guò)多新娜,做了一次全表掃描蝴簇,性能會(huì)很差。還有時(shí)候我們添加索引的時(shí)候要看區(qū)分度旁钧,計(jì)算索引區(qū)分度的方法,不重復(fù)的索引值/總記錄數(shù)嚎幸,值越接近1寄猩,說(shuō)明區(qū)分度越高,查詢的時(shí)候mysql就會(huì)過(guò)濾掉更多的行數(shù)據(jù)替废。還有泊柬,添加索引最好結(jié)合mysql執(zhí)行計(jì)劃來(lái)判斷。有時(shí)候做了過(guò)多的join操作兽赁,比如超過(guò)3張表以上,我們就要想著去拆解這些sql語(yǔ)句惊科。在就是數(shù)據(jù)庫(kù)層面我可以把歷史數(shù)據(jù)轉(zhuǎn)出減少數(shù)據(jù)量來(lái)達(dá)到提高查詢速度的目的亮钦。
快速失敗:
快速失敗策略實(shí)際上是一種自我保護(hù)措施孙咪,比如調(diào)用第三方接口超時(shí)巡语,如果超時(shí)時(shí)間設(shè)置過(guò)長(zhǎng)男公,訪問(wèn)量大的時(shí)候合陵,就會(huì)導(dǎo)致請(qǐng)求線程積壓,如果此時(shí)有線程隔離還好踏拜,若剛好沒(méi)有低剔,那么訪問(wèn)量一上來(lái)就會(huì)迅速導(dǎo)致cpu飆高肮塞。京麥平臺(tái)的特點(diǎn)之一枕赵,會(huì)大量調(diào)用第三方接口服務(wù)位隶,我們會(huì)對(duì)每個(gè)方法動(dòng)態(tài)的設(shè)置超時(shí)時(shí)間,如果UMP報(bào)警再結(jié)合JVM性能數(shù)據(jù)篮昧,我們會(huì)將這個(gè)接口的超時(shí)時(shí)間閾值調(diào)小笋妥。通過(guò)zookeeper下發(fā)到每一個(gè)服務(wù)節(jié)點(diǎn)上。在大促前疚颊,我們會(huì)重點(diǎn)檢查mysql信认、redis嫁赏、jsf等rpc調(diào)用的超時(shí)設(shè)置,確保每一次rpc調(diào)用都要有上限閾值款熬。關(guān)于RPC調(diào)用超時(shí)攘乒,這里多說(shuō)一下,有時(shí)候我們會(huì)發(fā)現(xiàn)調(diào)用端性能比如超過(guò)500ms殉簸,但是服務(wù)端確是在100ms上線徘徊沽讹。這里面我們除了檢查網(wǎng)關(guān)延時(shí),tcp重傳蝠检,還要注意一點(diǎn)挚瘟,就是任何一個(gè)成熟的rpc框架都不會(huì)讓業(yè)務(wù)線程直接參與網(wǎng)絡(luò)請(qǐng)求,rpc會(huì)提供一個(gè)消息隊(duì)列本慕,調(diào)用端直接跟消息隊(duì)列打交道锅尘。此時(shí),我們就要想到隊(duì)列這塊是否有問(wèn)題了浪腐。
降級(jí)限流:
這種技術(shù)實(shí)際上是保命的措施顿乒。降級(jí)一般有屛蔽降級(jí)和容錯(cuò)降級(jí)兩種璧榄,對(duì)一些非核心的功能,比如京麥的麥圈涂身,服務(wù)號(hào)搓蚪,論壇等功能,而他們恰恰又請(qǐng)求著mysql悴能,redis等公共資源雳灾,為了減少這種競(jìng)爭(zhēng)我們就會(huì)對(duì)這些功能進(jìn)行屛蔽降級(jí)佑女,直接切斷RPC調(diào)用,不再發(fā)起遠(yuǎn)程調(diào)用团驱,返回空或者其它異常提示嚎花,減少公共資源的訪問(wèn)呀洲。容錯(cuò)降級(jí)啼止,是一種放通献烦,則不顯得像屛蔽降級(jí)那樣暴力卖词,往往會(huì)有托底措施保證用戶更好的體驗(yàn),托底措施比如我們常用的本地緩存數(shù)據(jù)等即横。再說(shuō)下降級(jí)開(kāi)關(guān)裆赵,目前京麥?zhǔn)遣捎媒y(tǒng)一配置中心來(lái)使用战授。同樣,限流技術(shù)在京麥平臺(tái)中也是異常重要的一個(gè)措施惕橙,尤其是對(duì)京麥網(wǎng)關(guān)的調(diào)用钉跷。我們目前是采用令牌桶的方法,實(shí)現(xiàn)方式是Guava RateLimter彬坏,簡(jiǎn)單有效膝晾,再結(jié)合統(tǒng)一配置中心血当,我們可以動(dòng)態(tài)調(diào)整限流閾值。不用重啟服務(wù)器即可實(shí)現(xiàn)快速限流策略調(diào)整落恼。我們?cè)诰W(wǎng)關(guān)里面還有一個(gè)設(shè)置离熏,就是并發(fā)度,這個(gè)是方法粒度的钻蔑,對(duì)每一個(gè)調(diào)用第三方的接口都有一個(gè)并發(fā)度數(shù)值設(shè)置咪笑,而且是動(dòng)態(tài)設(shè)置,也是通過(guò)zookeeper下發(fā)到每一個(gè)服務(wù)節(jié)點(diǎn)上窗怒。并發(fā)度的具體實(shí)現(xiàn)是通過(guò)jdk的Semaphore兜粘。
我們?cè)賮?lái)說(shuō)一下孔轴,監(jiān)控配置和性能壓測(cè)。
監(jiān)控配置是一定不能缺少贷洲,我們要求自己一定要第一時(shí)間早于用戶發(fā)現(xiàn)問(wèn)題晋柱。平時(shí)開(kāi)發(fā)在上線的時(shí)候我們都應(yīng)該有統(tǒng)一要求每一個(gè)RPC調(diào)用都要有監(jiān)控和錯(cuò)誤棧的輸出。在備戰(zhàn)期間實(shí)際是對(duì)監(jiān)控配置的一個(gè)治理過(guò)程钦椭,監(jiān)控配置key要規(guī)則化碑诉,比如***.mysql.***,***.redis.***等讓我們一眼便知到是操作的哪一個(gè)資源进栽。京麥平臺(tái)這次備戰(zhàn)的過(guò)程中通過(guò)采用AOP的方式,把所有類(lèi)似的調(diào)用統(tǒng)一規(guī)范化處理格嗅,后續(xù)結(jié)合Python腳本對(duì)監(jiān)控閾值進(jìn)行統(tǒng)一調(diào)整唠帝。這樣走下來(lái)一方面把我們平時(shí)可能漏掉的監(jiān)控給補(bǔ)全没隘,另外一方面我們的監(jiān)控配置按照統(tǒng)一的規(guī)則來(lái)生成。
性能壓測(cè)這一塊阀湿,可以很好的檢驗(yàn)我們優(yōu)化的結(jié)果瑰妄,壓測(cè)的過(guò)程中我們關(guān)注qps的同時(shí)间坐,還要結(jié)合服務(wù)器的cpu、io劳澄、內(nèi)存等機(jī)器性能指標(biāo)來(lái)定位我們的性能瓶頸蜈七。最后來(lái)預(yù)估我們系統(tǒng)的承載能力飒硅,提供數(shù)據(jù)支撐來(lái)申請(qǐng)服務(wù)器或者docker資源。壓測(cè)工具研發(fā)可以自己寫(xiě)腳本庵芭,借助jmeter雀监、loadrunner等工具,也可以有計(jì)劃的聯(lián)系性能壓測(cè)組他們協(xié)助執(zhí)行好乐。最困難的還是產(chǎn)生真實(shí)的壓力曹宴。
還有一個(gè)備戰(zhàn)點(diǎn)歉提,返璞歸真苔巨,回到代碼,重點(diǎn)核心功能檢查一遍礁芦,把壞味道的代碼查出來(lái)。比如join了很多張表的sql語(yǔ)句肖方,日志輸出沒(méi)有采用條件方式或者占位符的方式未状,日志重復(fù)打印司草,try代碼塊放到了事務(wù)中,循環(huán)體中含有低性能的語(yǔ)句猜憎,鎖代碼塊中進(jìn)行RPC調(diào)用搔课,等等。
最后旦事,我們可以想一下備戰(zhàn)備的是什么急灭,總結(jié)歷次的大促葬馋,我認(rèn)為主要在,工具蛋逾、知識(shí)窗悯、經(jīng)驗(yàn)三個(gè)方面的備戰(zhàn)蒋院。工欲善其事,必先利其器姑丑,我們要有一些個(gè)好的工具輔助我們解決問(wèn)題辞友,比如MDC(里面含有CPU,網(wǎng)絡(luò)等監(jiān)控)留拾、UMP(京東自研方法性能间驮,可用率等監(jiān)控平臺(tái))马昨、CAP(容器的總體監(jiān)控,也含有cpu負(fù)載等信息查看)屹篓。知識(shí)層面堆巧,是我們歷來(lái)的積累泼菌,我們的認(rèn)識(shí)的提高哗伯,使用工具時(shí)候的指導(dǎo)。經(jīng)驗(yàn)是我們以往的大大小小的教訓(xùn)的總結(jié)系任,前車(chē)之鑒虐块,防止我們?cè)俅伟l(fā)生類(lèi)似的事情贺奠。
以“結(jié)硬寨,打呆賬”這句話結(jié)束此次618備戰(zhàn)的總結(jié)挂据,最重要的一點(diǎn)喉悴,還是要求我們備戰(zhàn)在平時(shí)箕肃。