Author:放翁(文初)
Date:2010/4/2
過年到現(xiàn)在還沒有更新過blog,就和年前說的一樣,到了淘寶就要真的踏實做實事了(起碼Q3前)。和以前在阿軟不同的是現(xiàn)在更加關(guān)注產(chǎn)品的設計和實現(xiàn),對于新技術(shù)的嘗試缺少了一些空間和時間。可以拿程序員對新技術(shù)的追求做個類比,就好比結(jié)婚前的浪漫,而到了你真的結(jié)婚有了家庭和小孩,那需要的是更多的責任感和務實的工作。當然如果生活成為一種生存,那么就失去了意義,如何在責任和浪漫之間找到平衡點,是一個技術(shù)人員成長的挑戰(zhàn)。我們不可能永遠是一個長不大的小孩,也不會是老氣橫秋的中年男人。有點廢話了,言歸正傳,談一下這年后短短的一個多月的工作心得,一點分享,一點記錄。
系統(tǒng)透明化
去年就加入了淘寶的虛擬小組(穩(wěn)定性小組),同時在開放平臺團隊內(nèi)最大的一個職責也是穩(wěn)定性。對于客戶來說并不關(guān)心你的技術(shù)實現(xiàn)是如何fancy,對他來說能夠快速、穩(wěn)定、方便的滿足他的需求就是一個好網(wǎng)站,一個好系統(tǒng),一套好服務。因此穩(wěn)定,高效成為了淘寶主站和開放平臺的根本。前兩天看了黃裳在infoq的一些關(guān)于淘寶技術(shù)展望的文章,就兩個字“實在”,沒有啥潮流的詞匯,沒有很炫的技術(shù)推薦,有的就是如何用最有效的手段滿足用戶需求。
記得在最近一次穩(wěn)定小組會議上大家談到了這些年發(fā)展帶來的問題,其實我們在解決問題的同時也在不斷地引入問題,同時在規(guī)模化的驅(qū)使下,不斷地采用松耦合及去中心化的設計,但是帶來的問題就是系統(tǒng)復雜度的不斷增加,同時系統(tǒng)間的交互和依賴也變得越來越復雜和混沌。我在Q1的工作計劃中,大部分的工作為了一個目標:系統(tǒng)透明化。
系統(tǒng)透明化能夠為海量請求的系統(tǒng)帶來什么?
1. 實實在在的性能優(yōu)化。
2. 簡單有效的問題排查和定位。
3. 系統(tǒng)風險預警。
4. 有效地系統(tǒng)健康監(jiān)控和業(yè)務健康監(jiān)控。
過去我們總在線下做各種壓力測試,同時對于一些優(yōu)化策略也都是通過線下來驗證,但是實際的業(yè)務場景往往會和具體的數(shù)據(jù)相關(guān),而線下無法做到的就是數(shù)據(jù)模擬。在開放平臺系統(tǒng)基礎(chǔ)框架重構(gòu)以后,首先是采用了管道鏈的插拔模式,直接通過對當前運行數(shù)據(jù)的在線分析就可以看出系統(tǒng)消耗的環(huán)節(jié),同時加上控制臺對集群單臺機器的配置推送,這樣比對兩臺不同處理策略的服務器就能夠很明顯看出性能優(yōu)化的效果以及后續(xù)的改進點。舉個例子,在我們業(yè)務方需求中要求對某一部分業(yè)務數(shù)據(jù)去掉本地緩存,全部啟用純粹的集中式緩存,我們通過批次的關(guān)閉本地緩存,比對了自身系統(tǒng)和外部依賴系統(tǒng)的壓力增長情況,當3/4的機群機器采用純集中式緩存的時候,兩方服務器都出現(xiàn)了load較高的問題,因此考慮采用更細粒度的業(yè)務數(shù)據(jù)來決定是否啟用本地緩存,滿足了用戶請求,同時也大大降低了雙方的壓力情況,同時由于業(yè)務數(shù)據(jù)配置可運行期推送,因此隨著壓力的增大可以在線調(diào)整策略。
在新架構(gòu)上線后,發(fā)現(xiàn)運行一段時間會有“內(nèi)存泄露”的問題,64位機器最后3個G的內(nèi)存都被吃光。當時就是擔心新架構(gòu)可能產(chǎn)生一些問題,因此允許系統(tǒng)通過控制臺切換新老引擎。線上一臺新引擎的服務器跑了一段時候就把內(nèi)存dump出來,然后拖到線下分析,發(fā)現(xiàn)有大量的tomcat的Session被保存在Manager中沒有被釋放(1.7G),然后通過線下卸載管道做測試,最終發(fā)現(xiàn)是由于其中一個管道需要在運行期獲取到spring的容器,去掉用了request.getsession().getContext方法,結(jié)果容器創(chuàng)建了有效期為30分鐘的session,對于平臺這么大的訪問量,其實這種非內(nèi)存泄露的問題,也足以使得高壓力下OOM。
透明化另一方面就是需要對依賴系統(tǒng)及自身的健康狀況有所了解。當前TOP在這方面主要做的工作被定義成為免疫系統(tǒng),其主要的職責

流程管道化
這些年一直都在談面向服務,模塊化,這些概念。但是就其目標來說,就是希望能夠讓設計者更多的考慮流程之間的松耦合,無依賴。因為一旦服務之間沒有過多的依賴,服務本身沒有中間狀態(tài),那么任務就可以并行處理,一旦并行處理,那么對于流程的關(guān)鍵路徑優(yōu)化就有很大的幫助。
下面是重構(gòu)前和重構(gòu)后的兩個流程對比:
老框架流程:

新框架流程:

具體的框架類圖如下:

看了以后,可能很多同學會說,其實就那么簡單一個設計么,但其實系統(tǒng)的設計目標就是用簡單的設計來滿足復雜的需求。其實對于開放平臺來說,再復雜的業(yè)務都是可以抽象成管道,同時大部分情況下都是無狀態(tài)的服務管道,基于業(yè)務的不同需求,管道的執(zhí)行會有所不同。
這里設計的幾個原則:
1. 管道之間無關(guān)聯(lián)性。管道與管道之間完全沒有任何關(guān)聯(lián),因為在管道看來就只有輸入和輸出的數(shù)據(jù)流,其他管道對于它來說是透明的。獨立性降低業(yè)務耦合度,支持運行期變更。
2. 管道之間通過上下文的方式交互數(shù)據(jù),減少數(shù)據(jù)輸入帶來的適配依賴。
3. 業(yè)務處理權(quán)及流程中斷權(quán)交給管道,管道可以通過實現(xiàn)ignoreit來判斷是否要處理此次請求,也可以在IPipeResult中設置isBreakPipeChain來主動中斷流程。(對于資源回收最好不要交給一個管道執(zhí)行,因為隨時可能因為流程中斷而沒有被執(zhí)行到)
4. 管道設計盡量為無狀態(tài),線程安全,便于擴展,防止產(chǎn)生資源競爭帶來的處理瓶頸。
5. 監(jiān)控管道執(zhí)行狀況,必要時自動降級卸載管道,保護系統(tǒng)穩(wěn)定性。
早先考慮是否能夠啟動線程池來執(zhí)行管道鏈,這么做的目標是能夠控制超時執(zhí)行的管道鏈,避免系統(tǒng)的不穩(wěn)定性。但最大的問題就是線程切換代價以及線程池的容量問題,因此作罷,改為事后記錄降級處理。
安全還是安全
開放平臺成立之初,就要面對著安全的問題,主站有很多的約束和限制,但是開放平臺成為淘寶對外的窗口,為了業(yè)務需要,作了必要的妥協(xié),但是安全方面也是一直在抓的事情。最近就處理淘寶訪客應用的問題,有些軟件開發(fā)者就利用302轉(zhuǎn)跳的方式,在商品或者店鋪的頁面上留痕跡,來獲取訪客信息,可謂用盡心思,封一個漏洞找一個漏洞。對于這種轉(zhuǎn)跳來獲取訪客信息,簡單的處理就這些,禁止get請求(由于都是頁面圖片的get請求轉(zhuǎn)跳,因此無法簡單的變成post請求),然后如果是post需要加上動態(tài)會話碼的校驗,最后在加上對于請求的refer檢查,來屏蔽這類的問題。不過對于釣魚網(wǎng)站,真的沒有啥太好的處理方式,個人感覺最靠譜的就是寫瀏覽器的插件。
標簽化開放
開放平臺現(xiàn)在都是數(shù)據(jù)服務開放,很多場景下會有標簽化開放的需求。還是看圖說話吧:

剩下的就是基于Map-Reduce的可配置分析引擎的優(yōu)化,當前支持文件數(shù)據(jù)源和數(shù)據(jù)庫數(shù)據(jù)源,支持增量分析和離線一次性分析,分析模型運行期可改變,提供實時的監(jiān)控預警。太晚了,最后貼一個開放平臺的技術(shù)當前總體架構(gòu)圖:
