Web服務(wù)請(qǐng)求異步化介紹(實(shí)踐篇)
Author:放翁(文初)
Date: 2010/8/5
Email:fangweng@taobao.com
圍脖: http://t.sina.com.cn/fangweng
在概念篇介紹完以后,開始實(shí)際的對(duì)TOP開始做技術(shù)改造。(這篇東西更像是對(duì)短期工作的總結(jié)和匯報(bào),寫的不是很詳實(shí),后續(xù)會(huì)有一個(gè)ppt來深化異步化的一些思想)下面將第一階段的工作做個(gè)總結(jié),第一階段主要做了以下幾個(gè)方面的事情:
1. 典型taobao后臺(tái)應(yīng)用(主要是用到了多個(gè)內(nèi)部組件)的Jetty遷移。
2. TOP管道化體系的異步改造。
3. 測試不同容器不同模式下的應(yīng)用處理能力,并通過數(shù)據(jù)得出結(jié)論。
一.應(yīng)用遷移及容器部署
這次遷移主要的工作就是在服務(wù)框架的遷移,服務(wù)框架內(nèi)部是小的OSGI容器,和當(dāng)初在阿軟做服務(wù)平臺(tái)一樣,當(dāng)時(shí)是SCA容器,道理都一樣,如何打通SCA和OSGI與應(yīng)用服務(wù)器,主要涉及的就是ClassLoader的互通。
服務(wù)框架組的同學(xué)當(dāng)時(shí)做過一個(gè)Jetty的內(nèi)置互通支持版本,其是修改了Jetty的代碼,在啟動(dòng)過程中植入了外部應(yīng)用容器的初始化和循環(huán)互通。考慮到將來Jetty升級(jí)的方便,自己還是從新考慮做一個(gè)外部互通的支持版本。(期間波折就不再此說了,大概說一兩點(diǎn)關(guān)鍵之處),首先是要啟動(dòng)外部容器,由于Jetty可以支持LifeCycle的Bean在Jetty容器啟動(dòng)時(shí)優(yōu)先裝載,因此外部容器就實(shí)現(xiàn)接口,在Jetty的Server配置中設(shè)置即可。然后需要將兩個(gè)容器互通(相互可以引用對(duì)方的服務(wù)接口),這需要在應(yīng)用上下文構(gòu)建的時(shí)候相互關(guān)聯(lián)兩者的classLoader,一種方式在Server的AppDeployer部署過程中植入,一種在指定的AppContext部署中植入。這兩種方式就是Jetty支持的兩種模式,一種配置在etc目錄下的jetty總配置文件中(Server配置中),一種配置在contexts目錄下(這種就是現(xiàn)在比較推崇的片段化部署),我選擇了后一種,因?yàn)閷?duì)我來說不是所有應(yīng)用都需要支持容器互通的,當(dāng)前只有TOP這個(gè)應(yīng)用。
容器部署,Jetty真的是太干凈了,首先類似于xml的解析實(shí)現(xiàn)沒有(jdk可只有框架接口),log4j沒有,jndi需要另外引入插件支持,lib下的jetty插件按需載入(在start.ini,start.config和啟動(dòng)腳本中可指定),遙想當(dāng)年的jboss也應(yīng)該是很干凈,回顧今天的部署應(yīng)用的jboss已經(jīng)被貼了N多膏藥。因此最終要的幾個(gè)配置就是:啟動(dòng)腳本,etc下的jetty.xml(可以指定其他配置),start.config (可以從jetty的jar包中獲取出來自己指定和配置),start.ini(啟動(dòng)的默認(rèn)配置),contexts下的應(yīng)用上下文配置。
容器部署和外部插件遷移雖然不是異步化的工作,但是在異步化以前一定要搞定,否則就無法談到后續(xù)的應(yīng)用遷移,總的來說jetty的模塊化和擴(kuò)展做的很好,基本上任何步驟都能夠替換和實(shí)現(xiàn)新的邏輯。(有需要jetty配置和hsf外部插件支持的同學(xué)可以直接找我)
二.TOP管道化體系異步改造
TOP的服務(wù)接入層就是由很多個(gè)管道切面組成的,流控,安全,業(yè)務(wù)校驗(yàn),路由,協(xié)議轉(zhuǎn)換,響應(yīng)格式轉(zhuǎn)換等等,因此TOP自身很適合采用管道化流程體系來構(gòu)建,同時(shí)采用管道化體系構(gòu)建能夠簡單的隔離業(yè)務(wù)邏輯,實(shí)現(xiàn)服務(wù)降級(jí),新功能beta發(fā)布。引入異步化概念后,對(duì)于開發(fā)者其實(shí)不需要過多了解,僅僅只需要配置異步化的管道,交由管道框架和容器協(xié)作來完成異步化的請(qǐng)求處理。
這里順帶在提一下上一篇中說到的異步化的作用:差別化耦合系統(tǒng)的體系設(shè)計(jì),差別化流程中流程處理。異步化不會(huì)節(jié)省業(yè)務(wù)事務(wù)處理時(shí)間(反而會(huì)增加),也不一定會(huì)提高系統(tǒng)可用性和穩(wěn)定性(起碼全局上來看,整體復(fù)雜度增加,異常波及會(huì)被隔離,但是可能發(fā)現(xiàn)也較晚),也不一定會(huì)節(jié)省資源(異步化往往是空間換時(shí)間,將業(yè)務(wù)狀態(tài)獨(dú)立于處理,提高處理線程的利用率,代價(jià)是增加了交互和存儲(chǔ)的成本)。
因此一直困擾TOP的服務(wù)分流和隔離可以通過異步化方式得以實(shí)現(xiàn),方式就是將系統(tǒng)處理和業(yè)務(wù)處理流程隔離,系統(tǒng)處理用少量線程就可以支持大并發(fā)請(qǐng)求,同時(shí)將后續(xù)的業(yè)務(wù)處理交給業(yè)務(wù)工作池,而業(yè)務(wù)工作池的資源分配完全可以通過業(yè)務(wù)特征設(shè)置權(quán)重,也可以通過后臺(tái)服務(wù)質(zhì)量的反饋來自動(dòng)調(diào)整,最終實(shí)現(xiàn)對(duì)服務(wù)使用者服務(wù)差別化,對(duì)不同質(zhì)量的服務(wù)提供差別化的流量引入。
同樣和上一篇文章談到的多種模式一樣,改造支持兩種模式,適合不同場景。純粹的異步方式往往需要借助于類似于epoll的io事件驅(qū)動(dòng)模式來徹底高效的分開兩個(gè)系統(tǒng),否則就是采用偽異步。
1. Pull & Check Status & Resume Mode
這種模式對(duì)于后端服務(wù)的要求較高,首先服務(wù)使用需要支持異步方式,其次要求在完成服務(wù)后修改任務(wù)狀態(tài),而對(duì)于依賴方來說,會(huì)通過輪詢的方式去獲取結(jié)果。流程圖如下,不過第二個(gè)是第一個(gè)的改進(jìn),效果不錯(cuò),前者是檢查所有的任務(wù)狀態(tài),確定是否完成,放入任務(wù)的是前端系統(tǒng),后者是不需要檢測任務(wù)狀態(tài),凡是獲得任務(wù),即表示任務(wù)完成,放入任務(wù)的是后端服務(wù)提供系統(tǒng)。


2. Push & Complete Mode
這種模式下對(duì)于后端服務(wù)來說可以只提供同步服務(wù)或者也支持異步服務(wù),TOP一期改造采用這種模式,后端服務(wù)采用同步模式,具體測試結(jié)果參看后面的測試部分。

三.測試
場景:
后臺(tái)服務(wù)執(zhí)行時(shí)間為1秒,no think time,容器為Nginx+Jetty
并發(fā)用戶數(shù)
|
Jetty連接池線程數(shù)量
|
業(yè)務(wù)線程池線程數(shù)量
|
load
|
TPS
|
200(異步)
|
200
|
200
|
0.8
|
180
|
400(異步)
|
200
|
200
|
0.7
|
208
|
200(同步)
|
200
|
200
|
1.16
|
190
|
400(同步)
|
200
|
200
|
1
|
190
|
200(異步)
|
200
|
400
|
0.95
|
195
|
400(異步)
|
200
|
400
|
0.84
|
390
|
200(同步)
|
200
|
400
|
0.82
|
195
|
400(同步)
|
200
|
400
|
0.88
|
195
|
200(同步)
|
400
|
400
|
0.7
|
174
|
400(同步)
|
400
|
400
|
0.85
|
350
|
結(jié)論:TPS還是取決于兩個(gè)線程池的線程多少,在異步化后系統(tǒng)消耗并沒有明顯增加,容器連接池的放大和業(yè)務(wù)線程池的放大都可以提高處理效率,同時(shí)業(yè)務(wù)線程池較為輕量,容量翻倍處理基本也是翻倍,容器的線程池放大處理能力會(huì)有衰減。
場景:
200并發(fā)用戶,調(diào)用user.get服務(wù),no think time,容器線程池400,業(yè)務(wù)線程池500.
容器
|
load
|
TPS
|
Nginx + Jetty
|
6
|
800
|
Jetty
|
8
|
620
|
結(jié)論:沒有前段Nginx對(duì)于數(shù)據(jù)緩沖處理,jetty處理效率一般,因此需要假設(shè)Jetty作為前段預(yù)處理容器(必要的時(shí)候也可以作為反向代理)
場景:
200并發(fā)用戶,調(diào)用user.get服務(wù),no think time,容器線程池200,業(yè)務(wù)線程池500.
容器
|
并發(fā)用戶
|
請(qǐng)求處理模式
|
TPS
|
Apache + Jboss
|
200
|
同步
|
507
|
Nginx + Jetty
|
200
|
同步
|
1060
|
Nginx + Jetty
|
200
|
異步
|
1027
|
Jetty
|
200
|
異步
|
670
|
結(jié)論:同步模式下Apache+Jboss與Nginx+Jetty相差很大的級(jí)別(load也相差一倍多)。異步模式下的Nginx+Jetty與同步模式相差不大,因此異步帶來的損耗可以忽略。沒有Nginx作為前端整體性能下降很大。
場景:
200并發(fā)用戶,no think time,容器線程池200,業(yè)務(wù)線程池500.
容器
|
請(qǐng)求服務(wù)
|
請(qǐng)求處理模式
|
TPS
|
Nginx + Jetty
|
Time.get
|
同步
|
1534
|
Nginx + Jetty
|
Time.get
|
異步
|
1068
|
Nginx + Jetty
|
User.get
|
同步
|
1060
|
Nginx + Jetty
|
User.get
|
異步
|
1027
|
結(jié)論:異步占用事務(wù)整體時(shí)間的比例越高,TPS的影響也越大。
長時(shí)間運(yùn)行測試:
半個(gè)多小時(shí)Full GC一次(當(dāng)前內(nèi)存開到1.5G),線上64位可以開的再大一些,沒有內(nèi)存泄漏現(xiàn)象。