眾所周知,人工智能的測(cè)試具有相當(dāng)大的難度,不論是以前在互聯(lián)網(wǎng)就經(jīng)??吹降膬?nèi)容推薦系統(tǒng),還是金融領(lǐng)域常用的信息分類系統(tǒng)。測(cè)試介入的都不多。那么如何測(cè)試人工智能相關(guān)的產(chǎn)品。
我們最常做的測(cè)試其實(shí)就是直接看模型效果,效果不好就慢慢調(diào)。 為了改變這種現(xiàn)狀,我們希望測(cè)試人員也能做一些事情,參與到人工智能服務(wù)的質(zhì)量保證當(dāng)中來(lái)。在日常工作中總結(jié)了一些經(jīng)驗(yàn)跟大家討論一下。
什么是人工智能
簡(jiǎn)而言之,現(xiàn)階段的人工智能就是:人工智能=大數(shù)據(jù)+機(jī)器學(xué)習(xí)。
現(xiàn)階段的人工智能是使用機(jī)器學(xué)習(xí)算法在大量的歷史數(shù)據(jù)下進(jìn)行訓(xùn)練,從歷史數(shù)據(jù)中找到一定的規(guī)律并對(duì)未來(lái)做出的預(yù)測(cè)行為。舉例說(shuō)明,就好比銀行做過(guò)的反欺詐項(xiàng)目。
在銀行里有一群專家,他們的工作就是根據(jù)經(jīng)驗(yàn)向系統(tǒng)中輸入一些規(guī)則。例如某一張卡在一個(gè)城市有了一筆交易,之后1小時(shí)內(nèi)在另一個(gè)城市又有了一筆交易。這些專家根據(jù)以前的經(jīng)驗(yàn)判斷這種情況是有盜刷的風(fēng)險(xiǎn)的。
他們?cè)谙到y(tǒng)中輸入了幾千條這樣的規(guī)則,組成了一個(gè)專家系統(tǒng)。 這個(gè)專家系統(tǒng)是建立在人類對(duì)過(guò)往的數(shù)據(jù)所總結(jié)出的經(jīng)驗(yàn)下建立的。 后來(lái)我們引入了機(jī)器學(xué)習(xí)算法,對(duì)過(guò)往所有的歷史數(shù)據(jù)進(jìn)行訓(xùn)練,最后在25億個(gè)特征中抽取出8000萬(wàn)條有效特征。
我們把這些特征就暫且當(dāng)成是專家系統(tǒng)中的規(guī)則。8000萬(wàn)對(duì)不到1萬(wàn),效果是可以預(yù)想的。當(dāng)時(shí)對(duì)第一版模型上線后的數(shù)據(jù)做統(tǒng)計(jì),反欺詐效果提升了7倍, 這就是二分類算法典型的業(yè)務(wù)場(chǎng)景。
為什么叫機(jī)器學(xué)習(xí)呢,因?yàn)樗o人一種感覺,機(jī)器能像人類一樣從過(guò)去的數(shù)據(jù)中學(xué)習(xí)到經(jīng)驗(yàn),只不過(guò)機(jī)器的能力更強(qiáng)。 如果想再稍微深究一下機(jī)器學(xué)習(xí)訓(xùn)練出來(lái)的模型到底是什么,那大家可以暫且理解為一個(gè)二分類的模型主要是就是一個(gè)key,value的數(shù)據(jù)庫(kù)。
key就是在數(shù)據(jù)中抽取出來(lái)的特征,value就是這個(gè)特征的權(quán)重。 當(dāng)我們想要預(yù)測(cè)一個(gè)用戶的行為的時(shí)候,就會(huì)從用戶的數(shù)據(jù)中提取特征并在模型中查找對(duì)應(yīng)的權(quán)重。 最后根據(jù)這些特征的權(quán)重算出一個(gè)分,也可以說(shuō)是一個(gè)概率。 如果大家看過(guò)最強(qiáng)大腦這個(gè)節(jié)目的話。
應(yīng)該記得第一次人機(jī)大戰(zhàn)項(xiàng)目是人臉識(shí)別,第三回合的時(shí)候機(jī)器給出了兩個(gè)答案。因?yàn)楫?dāng)時(shí)做人臉識(shí)別項(xiàng)目的志愿者中有一對(duì)雙胞胎。所以機(jī)器計(jì)算出的這兩個(gè)人的概率只差了0.1%,最后為了謹(jǐn)慎起見機(jī)器輸出兩個(gè)答案出來(lái)。以至于吳恩達(dá)先生也很糾結(jié)到底該選哪一個(gè)答案。
再之后的人機(jī)對(duì)戰(zhàn)項(xiàng)目里我們也能看到雖然小度一路高歌,毫無(wú)敗績(jī)。但是其中是有選錯(cuò)過(guò)幾次的。所以大家可以看到我們得到的答案其實(shí)是一個(gè)概率,是一個(gè)根據(jù)以往的數(shù)據(jù)進(jìn)行總結(jié)并作出預(yù)測(cè)的一個(gè)行為。并不是100%準(zhǔn)確的。即便是阿爾法狗當(dāng)初也是輸過(guò)一局的。所以其實(shí)我們測(cè)試的痛點(diǎn)也就來(lái)了,你怎么測(cè)試一個(gè)概率呢。
這個(gè)圖就是一個(gè)人工智能服務(wù)的略縮圖。 在歷史數(shù)據(jù)上訓(xùn)練出模型,并發(fā)布一個(gè)預(yù)測(cè)服務(wù),這個(gè)預(yù)測(cè)服務(wù)可能就是一個(gè)http的接口。 然后新的數(shù)據(jù)過(guò)來(lái)以后,根據(jù)模型算出一個(gè)預(yù)測(cè)值。經(jīng)過(guò)剛才的說(shuō)明,我們看到數(shù)據(jù)是人工智能的根本。擁有的數(shù)據(jù)越多,越豐富,越真實(shí),那么訓(xùn)練出的模型效果越好。
測(cè)試思路
·數(shù)據(jù)測(cè)試
·分層測(cè)試
·訓(xùn)練集與測(cè)試集對(duì)比
數(shù)據(jù)測(cè)試
根據(jù)我們之前對(duì)人工智能的定義,我們發(fā)現(xiàn)數(shù)據(jù)是人工智能的根據(jù)。 保證數(shù)據(jù)的正確定是非常必要的。 而且?guī)缀跛械臋C(jī)器學(xué)習(xí)算法對(duì)數(shù)據(jù)的容錯(cuò)能力都很強(qiáng),即便數(shù)據(jù)稍有偏差,它們也能通過(guò)一次一次的迭代和對(duì)比來(lái)減少誤差。 所以即便我們的數(shù)據(jù)有一點(diǎn)問題最后得出的模型效果可能還不差, 但是這個(gè)時(shí)候我們不能認(rèn)為模型就沒問題了。 因?yàn)楹芸赡茉谀承┨囟▓?chǎng)景下就會(huì)出現(xiàn)雪崩效應(yīng)。
再舉個(gè)例子。當(dāng)初阿爾法狗與李世石一戰(zhàn)成名。如果說(shuō)前三盤的結(jié)果令各路專家大跌眼鏡的話。那第四盤可能是讓所有人都大跌眼鏡了。阿爾法狗連出昏招,幾乎是將這一局拱手相讓。那阿爾法狗出bug了?DeepMind團(tuán)隊(duì)說(shuō),這是一個(gè)系統(tǒng)問題。那我們來(lái)看看這個(gè)系統(tǒng)到底有什么問題。根據(jù)當(dāng)時(shí)公布出來(lái)的數(shù)據(jù)我們發(fā)現(xiàn)阿爾法狗的養(yǎng)成方法是這樣的。
阿爾法狗如何養(yǎng)成
1.整理過(guò)去人類對(duì)弈的80多萬(wàn)盤棋局
2.拿1的棋譜,訓(xùn)練一只狗狗,能夠預(yù)測(cè)人類下一步會(huì)下在哪里
3.拿2得到的狗狗,每天自己和自己下100萬(wàn)盤棋
4.拿1和3的棋譜,再訓(xùn)練一只狗狗,這就是阿爾法狗。
阿爾法狗是基于1億+盤機(jī)器棋局和80萬(wàn)人類棋局訓(xùn)練出來(lái)的狗狗。問題出在哪?我們看到,訓(xùn)練阿爾法狗所用的棋譜,只有80萬(wàn)是人類棋局,總數(shù)上億的棋局是機(jī)器對(duì)弈的。它下的每一步,都是將局面導(dǎo)向歷史上(也就是80萬(wàn)人類棋局和1億自己對(duì)弈的棋局)勝率最大的局面。
問題就恰恰出在這里,80萬(wàn)和1億。相差甚多。那么阿爾法狗選擇的所謂勝率最大,一定是贏自己的概率最大,而不是贏人類的概率最大。這樣的標(biāo)準(zhǔn)在順豐棋尚且不容易出問題,一旦遇到逆風(fēng)局,它的選擇就變成了,選擇對(duì)手犯錯(cuò)概率最大的棋,而這個(gè)對(duì)手恰恰就是它自己。
這就是為什么當(dāng)初阿爾法狗在逆風(fēng)局中下出一些匪夷所思的棋。當(dāng)然這些都只是行業(yè)內(nèi)的人的猜測(cè)。但從這個(gè)例子就可以看到數(shù)據(jù)的重要性。數(shù)據(jù)出現(xiàn)偏差會(huì)直接導(dǎo)致不可估計(jì)的后果。
所以我們總結(jié)出的第一個(gè)突破口就是數(shù)據(jù)測(cè)試。保證我們用來(lái)建模的數(shù)據(jù)是正確的。在這里的數(shù)據(jù)測(cè)試會(huì)跟我們以往的測(cè)試有些不一樣。
首先是數(shù)據(jù)規(guī)模的增長(zhǎng)。數(shù)據(jù)大了里面的有些數(shù)據(jù)可能會(huì)發(fā)生一些很詭異的事情。然后是存儲(chǔ)介質(zhì)和技術(shù)棧的變化,我們用來(lái)訓(xùn)練模型的數(shù)據(jù)都會(huì)存放在hadoop集群上,所以一般都會(huì)用spark或者Hbase來(lái)編寫測(cè)試腳本。最后是驗(yàn)證方式的變化,之前我們測(cè)試的時(shí)候都是精確的測(cè)試每條數(shù)據(jù)的正確性。 但是現(xiàn)在我們需要根據(jù)業(yè)務(wù)設(shè)定每一個(gè)字段的規(guī)則。然后掃描每一行數(shù)據(jù),如果這條數(shù)據(jù)超出了這個(gè)字段的規(guī)定范圍,會(huì)發(fā)出報(bào)警。 假如用戶年齡這個(gè)字段,正常值可能是0~100歲。如果突然出現(xiàn)個(gè)300歲,那么這條數(shù)據(jù)肯定是有問題的。我們之前曾經(jīng)碰見過(guò)這樣的數(shù)據(jù)。本來(lái)這條數(shù)據(jù)應(yīng)該是30歲的,但卻多了個(gè)0。
針對(duì)這方面的測(cè)試,一般都是使用spark或者Hbase這種大數(shù)據(jù)處理框架把任務(wù)提交到集群上去掃描每一張表。
分層測(cè)試
雖然我們能測(cè)試用來(lái)做訓(xùn)練的數(shù)據(jù)是正確的。但是一個(gè)人工智能系統(tǒng)是很復(fù)雜的, 我們只是保證了作為源頭的數(shù)據(jù)貌似是不夠的。以前我們測(cè)試的時(shí)候都知道把系統(tǒng)拆解開做分層測(cè)試,所以我們的第二個(gè)突破口就是基于這個(gè)思路。我們先來(lái)了解一下,一個(gè)模型的誕生都經(jīng)理了哪些步驟。
模型誕生的步驟:
·數(shù)據(jù)引入
·數(shù)據(jù)處理(清洗,拆分,拼接等)
·特征工程
·模型訓(xùn)練
·模型上線
數(shù)據(jù)引入:將歷史數(shù)據(jù)引入到系統(tǒng)中,并做第一步的預(yù)處理。例如處理一些明顯的異常的行為。
數(shù)據(jù)處理: 其中又包含很多種操作。 例如對(duì)數(shù)據(jù)進(jìn)行清洗,拆分。 把兩張表進(jìn)行拼接等。
特征工程:我們從數(shù)據(jù)中按一定規(guī)律提取一些特征出來(lái)。之后需要將提取的樣本表傳遞給機(jī)器學(xué)習(xí)算法進(jìn)行訓(xùn)練。
可以看到我們把數(shù)據(jù)引入到系統(tǒng)后,先是用SQL算子對(duì)數(shù)據(jù)做了拼接,然后清洗一些無(wú)效數(shù)據(jù)。 再把數(shù)據(jù)拆分為訓(xùn)練集和測(cè)試集。分別對(duì)兩個(gè)數(shù)據(jù)集做特征抽取。之后訓(xùn)練集傳遞給邏輯回歸這個(gè)機(jī)器學(xué)習(xí)算法進(jìn)行訓(xùn)練。訓(xùn)練之后使用測(cè)試集來(lái)測(cè)試一下模型的效果。大家看到這個(gè)圖了,這是創(chuàng)建一個(gè)模型比較常見的流程。
圖中的邏輯歸回就是一種機(jī)器學(xué)習(xí)算法,也是一種最簡(jiǎn)單的二分類算法,其他的算法諸如 GBDT,SVM,DNN等算法的模型都是這個(gè)流程。我們可以看到算法上面的流程。全部與機(jī)器學(xué)習(xí)無(wú)關(guān)。他們都屬于大數(shù)據(jù)處理范疇。而且一個(gè)成型的系統(tǒng)在每一個(gè)模塊都會(huì)提供一些固定的接口。
例如我們公司在特征抽取算法上就提供了近百個(gè)特征抽取的接口,可以根據(jù)不同的情況使用不同的方式提取數(shù)據(jù)中的特征。 數(shù)據(jù)拆分也有很多種不同的拆分方法,按隨機(jī)拆分,分層拆分,規(guī)則拆分。
每個(gè)子模塊都會(huì)提供一些接口供上層調(diào)用。 所以既然提到接口層面的東西了,大家應(yīng)該都知道怎么測(cè)了吧。 只不過(guò)有些接口并不是http或者RPC協(xié)議的。 有時(shí)候需要我們?cè)诋a(chǎn)品的repo里寫測(cè)試用例。
訓(xùn)練集與測(cè)試集對(duì)比
這是我們的第三種測(cè)試思路。 我們剛才一直用來(lái)舉例的分類算法是一種監(jiān)督學(xué)習(xí)。 什么是監(jiān)督學(xué)習(xí)呢,就是我們的歷史數(shù)據(jù)中是有答案的。還拿剛才的反欺詐的例子說(shuō),就是我們的數(shù)據(jù)中都有一個(gè)字段標(biāo)明了這條數(shù)據(jù)是否是欺詐場(chǎng)景。 所以我們完全可以把歷史數(shù)據(jù)拆分為訓(xùn)練集和測(cè)試集。將測(cè)試集輸入到模型中以評(píng)價(jià)模型預(yù)測(cè)出的結(jié)果的正確率如何。所以每次版本迭代都使用同樣的數(shù)據(jù),同樣的參數(shù)配置。 統(tǒng)計(jì)模型效果并進(jìn)行對(duì)比。當(dāng)然這種測(cè)試方式是一種模糊的方式。就如我再剛開始說(shuō)的一樣,這種方式無(wú)法判斷問題出在哪里。是bug,還是參數(shù)設(shè)置錯(cuò)了?我們無(wú)法判斷。
常見的測(cè)試場(chǎng)景
1.自學(xué)習(xí)
幾乎所有的人工智能服務(wù)都必須要支持自學(xué)習(xí)場(chǎng)景。就像阿爾法狗一樣,它輸了一局,就會(huì)從輸?shù)倪@一局中學(xué)習(xí)到經(jīng)驗(yàn),以后他就不會(huì)那么下了,這也是機(jī)器學(xué)習(xí)恐怖的地方,它會(huì)變的越來(lái)越無(wú)懈可擊,以前人類還能贏上一局,但是未來(lái)可能人類再也贏不了阿爾法狗了。 做法就是我們的數(shù)據(jù)每天都是在更新的,用戶行為也是一直在變化的。所以我們的模型要有從最新的數(shù)據(jù)中進(jìn)行學(xué)習(xí)的能力。
上面是常見的自學(xué)習(xí)場(chǎng)景流程圖。假如我們用歷史上n天的數(shù)據(jù)訓(xùn)練出一個(gè)模型并發(fā)布成了一個(gè)預(yù)測(cè)的服務(wù)。 那么到了隔天的時(shí)候。我們拋棄之前第一天的數(shù)據(jù),使用第二天到第n+1天的數(shù)據(jù)重新訓(xùn)練一個(gè)模型并代替之前的模型發(fā)布一個(gè)預(yù)測(cè)服務(wù)。這樣不停的循環(huán),每一天都收集到最新的數(shù)據(jù)參與模型訓(xùn)練。 這時(shí)候大家應(yīng)該明白該測(cè)試什么了。每天收集到的新數(shù)據(jù),就是測(cè)試重點(diǎn)。就是我們剛才說(shuō)的第一種測(cè)試思路,使用spark,Hbase這些技術(shù),根據(jù)業(yè)務(wù)指定規(guī)則,掃描這些數(shù)據(jù)。一旦有異常就要報(bào)警。
2.預(yù)測(cè)服務(wù)
下面一個(gè)場(chǎng)景是預(yù)測(cè)服務(wù)的。預(yù)測(cè)服務(wù)的架構(gòu)一般都滿復(fù)雜的,為了實(shí)現(xiàn)高可用,負(fù)載均衡等目的,所以一般都是標(biāo)準(zhǔn)的服務(wù)發(fā)現(xiàn)架構(gòu)。以etcd這種分布式存儲(chǔ)機(jī)制為載體。 所有的預(yù)測(cè)服務(wù)分別以自注冊(cè)的方式來(lái)提供服務(wù)。
上面的一個(gè)圖是一個(gè)比較流行的預(yù)測(cè)服務(wù)的架構(gòu)。當(dāng)然我做了相應(yīng)的簡(jiǎn)化,隱去了一些細(xì)節(jié)。所有的部署任務(wù)由master寫入ETCD。 所有agent以自注冊(cè)的方式將自己的信息寫入ETCD以接受master的管理并執(zhí)行部署任務(wù)。 而router也同樣讀取etcd獲取所有agent提供的預(yù)測(cè)服務(wù)的信息并負(fù)責(zé)負(fù)載均衡。 有些公司為了做高可用和彈性伸縮甚至將agent納入了kubernetes的HPA中進(jìn)行管理。由此我們需要測(cè)試這套機(jī)制能實(shí)現(xiàn)他該有的功能。例如:
·router會(huì)按規(guī)則把壓力分發(fā)到各個(gè)agent上。
·把某個(gè)agent的預(yù)測(cè)服務(wù)被kill掉后,router會(huì)自動(dòng)切換。
·預(yù)估服務(wù)掛掉,agent會(huì)自動(dòng)感知并重新拉起服務(wù)。
·agent被kill掉后,也會(huì)被自動(dòng)拉起。
·如果做了彈性伸縮,需要將預(yù)測(cè)服務(wù)壓到臨界點(diǎn)后觀察系統(tǒng)是否做了擴(kuò)容等等。
性能測(cè)試
我們要接觸的性能測(cè)試跟互聯(lián)網(wǎng)的不太一樣。我們知道預(yù)測(cè)服務(wù)仍然還是訪問密集型業(yè)務(wù)。但是模型調(diào)研的過(guò)程是屬于計(jì)算密集型業(yè)務(wù)。我們要模擬的情況不再是高并發(fā)。而是不同的數(shù)據(jù)規(guī)模,數(shù)據(jù)分布和數(shù)據(jù)類型。我們?nèi)粘5男阅軠y(cè)試都是需要在各種不同的數(shù)據(jù)下跑各種不同的算子和參數(shù)。所以我們首先需要一種造數(shù)機(jī)制,能幫助我們按需求生成大規(guī)模的數(shù)據(jù)。我們選擇的是spark,利用分布式計(jì)算在hadoop集群上生成大量的數(shù)據(jù)。
原理也很簡(jiǎn)單,接觸過(guò)spark的同學(xué)肯定都知道在spark中生成一個(gè)RDD有兩種方式, 一種是從文件中讀取,另一種是從內(nèi)存中的一個(gè)list種解析。第一種方式肯定不是我們想要的, 所以從內(nèi)存中的list解析就是我們選擇的方式。假如我們想生成一個(gè)10億行的數(shù)據(jù)。就可以先使用python 的xrange造一個(gè)生成器以防止內(nèi)存被撐爆。然后用這個(gè)生成器初始化一個(gè)有著10億行的空的RDD,定義并操作RDD的每一行去生成我們想要的數(shù)據(jù),然后設(shè)置RDD的分片以及消耗的container,內(nèi)存,cpu等參數(shù)。提交到集群上利用集群龐大的計(jì)算資源幫助我們?cè)诙螘r(shí)間內(nèi)生成我們需要的數(shù)據(jù)。 前兩天我再一個(gè)3個(gè)節(jié)點(diǎn)的集群上造過(guò)一個(gè)1.5T的數(shù)據(jù),大概用了5個(gè)小時(shí)。這樣一開始的時(shí)候我們是寫spark腳本來(lái)完成這些事。后來(lái)需求越來(lái)越多,我們發(fā)現(xiàn)可以造數(shù)做成一個(gè)工具。把表和字段都提取到配置文件中進(jìn)行定義。就這樣我們成立了shannon這個(gè)項(xiàng)目。慢慢的從造數(shù)腳本到造數(shù)工具再到造數(shù)平臺(tái)。
它的架構(gòu)特別簡(jiǎn)單,就是對(duì)原生spark的應(yīng)用,這里我就不展示spark的架構(gòu)是什么樣了。就貼一下造數(shù)工具的設(shè)計(jì)圖吧。
簡(jiǎn)單來(lái)說(shuō)shannon分了3層。最底層是基本數(shù)據(jù)類型層。負(fù)責(zé)字段實(shí)例化,定義并實(shí)現(xiàn)了shannon支持的所有數(shù)據(jù)類型。例如,隨機(jī),枚舉,主鍵,unique key,控制分布,大小,范圍等等。
測(cè)試環(huán)境管理
常見的測(cè)試場(chǎng)景我們基本上都說(shuō)完了。 我們?cè)僬f(shuō)一說(shuō)測(cè)試環(huán)境管理的問題。 為了能夠保證研發(fā)和測(cè)試效率,一個(gè)能夠支撐大規(guī)模測(cè)試環(huán)境的基礎(chǔ)設(shè)施是十分必要的。為什么這么說(shuō)呢?
首先但凡是涉及到機(jī)器學(xué)習(xí)的業(yè)務(wù),運(yùn)行時(shí)間都非常慢。 有時(shí)候做測(cè)試的時(shí)候跑一個(gè)模型要幾個(gè)小時(shí)甚至一天都是有的。也就是說(shuō),我們運(yùn)行測(cè)試的成本比較高。如果在運(yùn)行測(cè)試的途中環(huán)境出了什么問題那么損失還是很大的。多人共用一套環(huán)境難免會(huì)有互相踩踏的情況,例如一個(gè)RD在測(cè)試自己的模塊,另一個(gè)人上來(lái)把服務(wù)重啟了。這時(shí)候我們心里一般就是一萬(wàn)頭某種動(dòng)物飄過(guò)。所以我們一般希望每個(gè)人都能擁有一套獨(dú)立的環(huán)境甚至一個(gè)人多套環(huán)境。這就增加了測(cè)試環(huán)境的數(shù)量。尤其是團(tuán)隊(duì)越來(lái)越大的時(shí)候,測(cè)試環(huán)境的數(shù)量已經(jīng)到達(dá)了一個(gè)恐怖的量級(jí)。
其次如果各位所在的公司也像我們一樣做TO B的業(yè)務(wù),那么我們的測(cè)試環(huán)境就需要多版本管理,要有能力隨時(shí)快速的搭建起特定版本的產(chǎn)品環(huán)境供開發(fā),產(chǎn)品,測(cè)試,以及技術(shù)支持人員使用。所以這無(wú)疑又增加了環(huán)境管理設(shè)置的復(fù)雜度。
再有就是隨著環(huán)境數(shù)量的擴(kuò)張,我們的環(huán)境從單節(jié)點(diǎn)走向集群,這時(shí)候我們對(duì)環(huán)境調(diào)度能力的要求會(huì)比較高,例如我們要對(duì)環(huán)境的資源進(jìn)行計(jì)算和限制,保證最大化利用資源的同時(shí)不會(huì)撐爆系統(tǒng)。例如我們要保證系統(tǒng)有足夠的冗余,在某些環(huán)境出現(xiàn)故障的時(shí)候能夠自動(dòng)檢測(cè)出來(lái)并在冗余節(jié)點(diǎn)進(jìn)行恢復(fù)。例如我們需要能夠?qū)崿F(xiàn)多租戶管理,執(zhí)行資源管控,限制超售行為. 例如我們希望系統(tǒng)有一定能力的無(wú)人值守運(yùn)維能力等等。
所以我們經(jīng)過(guò)一段時(shí)間的討論和實(shí)驗(yàn),引入了k8s+docker來(lái)完成這個(gè)目標(biāo)。docker的優(yōu)勢(shì)大家應(yīng)該都知道,快速,標(biāo)準(zhǔn)化,隔離性,可遷移性都不錯(cuò)。 通過(guò)鏡像我們可以迅速的將測(cè)試環(huán)境的數(shù)量提升一個(gè)量級(jí),鏡像的版本管理正適合TO B業(yè)務(wù)的多版本管理。 之所以選擇k8s,是因?yàn)閗8s相較于swarm和mesos 都擁有著更強(qiáng)大的功能和更簡(jiǎn)單的部署方式。剛才說(shuō)的預(yù)測(cè)服務(wù)需要部署很多個(gè)agent,使用k8s的話只需要設(shè)置一下replica set的數(shù)量,k8s就會(huì)自動(dòng)幫我們維護(hù)好這個(gè)數(shù)量的實(shí)例了,很方便 。k8s的調(diào)度機(jī)制能很輕松的滿足我們剛才說(shuō)的對(duì)于災(zāi)難恢復(fù),冗余,多租戶,高可用,負(fù)載均衡,資源管理等要求。所以我們當(dāng)初懷揣著對(duì)google莫名的憧憬走上了k8s的踩坑之旅。
首先說(shuō)一下我們都用容器做什么。主要三大類,第一種是諸如testlink,jenkins這種基礎(chǔ)服務(wù)。第二種是產(chǎn)品的測(cè)試環(huán)境,這是占比最多的。然后就是我們的測(cè)試執(zhí)行機(jī)器了。例如UI自動(dòng)化,我們采取的是分別將selenium hub和node docker化的做法。如下圖:
當(dāng)UI自動(dòng)化的case增多的時(shí)候,分布式運(yùn)行往往是最好的解決方案。 目前我們通過(guò)這種方式容器化了20個(gè)瀏覽器進(jìn)行并發(fā)測(cè)試。這些鏡像都有官方的版本,使用起來(lái)還是蠻方面的。
然后說(shuō)一下比較關(guān)鍵的網(wǎng)絡(luò)解決方案,我們從單機(jī)到集群,中途歷經(jīng)了集中網(wǎng)絡(luò)模型的變化。從一開始的端口映射,到利用路由規(guī)則給容器分配真實(shí)的ip,再到給每個(gè)容器在DHCP和DNS服務(wù)器上注冊(cè)和續(xù)租。到最后我們演進(jìn)出了下面這個(gè)k8s的網(wǎng)絡(luò)模型。
我們知道每個(gè)docker宿主機(jī)都會(huì)自己維護(hù)一個(gè)私有網(wǎng)絡(luò)。如果想讓容器跨主機(jī)通訊或者外部訪問容器。一般就是通過(guò)三種方式: 端口映射,路由規(guī)則以及overlay網(wǎng)絡(luò)。我們選擇在k8s中引入的overlay網(wǎng)絡(luò)是weave,以解決夸主機(jī)通信問題。安裝kube-dns實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)。之后為了能讓外部訪問容器服務(wù), 使用了k8s提供的ingress機(jī)制來(lái)實(shí)現(xiàn)。這個(gè)ingress網(wǎng)絡(luò)其實(shí)就是在集群中啟動(dòng)一個(gè)容器,這個(gè)容器既能訪問容器網(wǎng)絡(luò)的同是還監(jiān)聽了宿主機(jī)的80端口。容器里是一個(gè)nginx,它會(huì)負(fù)責(zé)幫忙轉(zhuǎn)發(fā)請(qǐng)求。nginx負(fù)責(zé)轉(zhuǎn)發(fā)的有servicename和path,這里我們是無(wú)法使用路徑進(jìn)行轉(zhuǎn)發(fā)的。所以我們?cè)诠緝?nèi)部的DNS上做了泛域名解析。所有testenv為后綴的域名都會(huì)解析成集群的master節(jié)點(diǎn)的ip。這樣我們的請(qǐng)求就能命中nginx中固定的servicename并做轉(zhuǎn)發(fā)了。通過(guò)這種機(jī)制我們就可以很方面的訪問容器提供的服務(wù)。當(dāng)然ingress的缺點(diǎn)是暫時(shí)還無(wú)法做4層轉(zhuǎn)發(fā)。如果要訪問4層協(xié)議的服務(wù)暫時(shí)還是只能暴露node port。
我們這個(gè)測(cè)試環(huán)境的管理平臺(tái)主要的架構(gòu)是這樣的:
集群中所有的鏡像都過(guò)公司內(nèi)部搭建的鏡像倉(cāng)庫(kù)進(jìn)行共享,我們?cè)诩褐习惭b了各種服務(wù)來(lái)滿足測(cè)試環(huán)境的需要。例如使用NFS做數(shù)據(jù)持久化,Heapster+Grafana+InfluxDB做性能監(jiān)控,kube-DNS做服務(wù)發(fā)現(xiàn),dashboard提供web管理界面,weave做集群網(wǎng)絡(luò),ingress做服務(wù)的轉(zhuǎn)發(fā)。并且我們?cè)谶@個(gè)整體上針對(duì)k8s的APIserver做了一層cli的封裝。我們嘗試過(guò)腳本管理,web服務(wù)管理,但是發(fā)現(xiàn)大家對(duì)這些方式的接受度都不高。我們面對(duì)的大多數(shù)都是一幫做夢(mèng)都在寫代碼的人,所以我們換做提供一個(gè)cli的方式可以讓使用者更靈活來(lái)定制自己需要的服務(wù)。通過(guò)這種形式,我們?cè)诠緝?nèi)部搭建了一個(gè)可以提供測(cè)試資源的私有云,配合jenkins我們可以很方便的一鍵部署我們需要的環(huán)境并執(zhí)行UT,接口,UI自動(dòng)化測(cè)試等等,并提供一個(gè)詳細(xì)的測(cè)試報(bào)告。下面是我們的部署一個(gè)環(huán)境后所提供的測(cè)試報(bào)告。
