新聞中心
一次 serverless 架構(gòu)改造實踐:基因樣本比對
作者:佚名 2018-05-25 14:41:56
云計算 本文將從代碼的角度,通過改造一個 Python 應(yīng)用來幫助讀者從側(cè)面理解 Serverless,讓應(yīng)用繼承 Serverless 架構(gòu)的優(yōu)點。

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),績溪企業(yè)網(wǎng)站建設(shè),績溪品牌網(wǎng)站建設(shè),網(wǎng)站定制,績溪網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,績溪網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。
Serverless 是一種新興的無服務(wù)器架構(gòu),使用它,開發(fā)者只需專注于代碼,無需關(guān)心運維、資源交付或者部署。
本文將從代碼的角度,通過改造一個 Python 應(yīng)用來幫助讀者從側(cè)面理解 Serverless,讓應(yīng)用繼承 Serverless 架構(gòu)的優(yōu)點。
現(xiàn)有資源:
- 一個成熟的基因?qū)Ρ人惴?Python實現(xiàn),運行一次的時間花費為 2 秒)
- 2020 個基因樣本文件(每個文件的大小為 2M,可以直接作為算法的輸入)
- 一臺 8 核心云主機
基因檢測服務(wù)
我們使用上面的資源來對比兩個人的基因樣本并 print 對比結(jié)果(如:有直系血緣關(guān)系的概率)
我們構(gòu)造目錄結(jié)構(gòu)如下:
- .
- ├── relation.py
- └── samples
- ├── one.sample
- └── two.sample
relations.py 代碼如下:
- import sys
- def relationship_algorithm(human_sample_one, human_sample_two):
- # it's a secret
- return result
- if __name__ == "__main__":
- length = len(sys.argv)
- # sys.argv is a list, the first element always be the script's name
- if length != 3:
- sys.stderr.write("Need two samples")
- else:
- # read the first sample
- with open(sys.argv[1], "r") as sample_one:
- sample_one_list = sample_one.readlines()
- # read the second sample
- with open(sys.argv[2], "r") as sample_two:
- sample_two_list = sample_two.readlines()
- # run the algorithm
- print relationship_algirithm(sample_one_list, sample_two_list)
使用方法如下:
- python relation.py ./samples/one.sample ./samples/two.sample
- 0.054
流程比較簡單,從本地磁盤讀取兩個代表基因序列的文件,經(jīng)過算法計算,***返回結(jié)果
我們接到了如下業(yè)務(wù)需求
假設(shè)有 2000 人尋找自己的孩子,20 人尋找自己的父親
首先收集唾液樣本經(jīng)過專業(yè)儀器分析后,然后生成樣本文件并上傳到我們的主機上,一共 2020 個樣本文件,***我們需要運行上面的算法
- 2000 * 20 = 40000(次)
才可完成需求,我們計算一下總花費的時間:
- 40000(次) * 2(秒)= 80000 (秒)
- 80000(秒)/ 60.0 / 60.0 ≈ 22.2(小時)
串行需要花費 22 小時才能算完,太慢了,不過我們的機器是 8 核心的,開 8 個進程一起算:
- 22.2 / 8 ≈ 2.76(小時)
也要快 3 個小時,還是太慢,假設(shè) 8 核算力已經(jīng)到極限了,接下來如何優(yōu)化呢?
1.1.1 介紹一種 Serverless 產(chǎn)品:UGC
UCloud General Compute
與 AWS 的 lambda 不同,UGC 允許你將計算密集型算法封裝為 Docker Image (后文統(tǒng)稱為「算法鏡像」),只需將算法鏡像 push 到指定的算法倉庫中,UGC 會將算法鏡像預(yù)先 pull 到一部分計算節(jié)點上,當(dāng)你使用以下兩種形式:
- 算法鏡像的名字和一些驗證信息通過 querystring 的形式 (例如:http://api.ugc.service.ucloud.cn?ImageName=relation&Token=!Q@W#E)
- 算法鏡像所需的數(shù)據(jù)通過 HTTP body 的形式
特別構(gòu)造的 HTTP 請求發(fā)送到 UGC 的 API 服務(wù)時,「任務(wù)調(diào)度器」會幫你挑選已經(jīng) pull 成功算法鏡像的節(jié)點,并將請求調(diào)度過去,然后啟動此算法鏡像「容器」將此請求的 HTTP body 以標(biāo)準(zhǔn)輸入 stdin 的形式傳到容器中,經(jīng)過算法計算,再把算法的標(biāo)準(zhǔn)輸出 stdout 和標(biāo)準(zhǔn)錯誤 stderr 打成一個 tar 包,以 HTTP body 的形式返回給你,你只需要把返回的 body 當(dāng)做 tar 包來解壓即可得到本次算法運行的結(jié)果。
講了這么多,這個產(chǎn)品使你可以把密集的計算放到了數(shù)萬的計算節(jié)點上,而不是我們小小的 8 核心機器,有數(shù)萬核心可供使用,那么如何使用如此海量的計算資源呢,程序需要小小的改造一下
1.1.2 針對此 Serverless 架構(gòu)的改造
兩部分:
- 改造算法中元數(shù)據(jù)從「文件輸入」改為「標(biāo)準(zhǔn)輸入」,輸出改為「標(biāo)準(zhǔn)輸出」
- 開發(fā)客戶端構(gòu)造 HTTP 請求,并提高并發(fā)
1. 改造算法輸入輸出
① 改造輸入為 stdin
- cat ./samples/one.sample ./samples/two.sample | python relation.py
這樣把內(nèi)容通過管道交給 relation.py 的 stdin,然后在 relation.py 中通過以下方式拿到:
- import sys
- mystdin = sys.stdin.read()
- # 這里的 mystdin 包含 ./samples/one.sample ./samples/two.sample 的全部內(nèi)容,無分隔,實際使用可以自己設(shè)定分隔符來拆分
② 將算法的輸出數(shù)據(jù)寫入 stdout
- # 把標(biāo)準(zhǔn)輸入拆分為兩個 sample
- sample_one, sample_two = separate(mystdin)
- # 改造算法的輸出為 STDOUT
- def relationship_algorithm(sample_one, sample_two)
- # 改造前
- return result
- # 改造后
- sys.stdout.write(result)
到此就改造完了,很快吧
2. 客戶端與并發(fā)
剛才我們改造了算法鏡像的邏輯(任務(wù)的執(zhí)行),現(xiàn)在我們來看一下任務(wù)的提交:
構(gòu)造 HTTP 請求并讀取返回結(jié)果
- imageName = "cn-bj2.ugchub.service.ucloud.cn/testbucket/relationship:0.1"
- token = tokenManager.getToken() # SDK 有現(xiàn)成的
- # summitTask 構(gòu)造 HTTP 請求并將鏡像的 STDOUT 打成 tar 包返回
- response = submitTask(imageName, token, data)
它也支持異步請求
之前提到,此 Serverless 產(chǎn)品會將算法的標(biāo)準(zhǔn)輸出打成 tar 包放到 HTTP body 中返回給客戶端,所以我們準(zhǔn)備此解包函數(shù):
- import tarfile
- import io
- def untar(data):
- tar = tarfile.open(fileobj=io.BytesIO(data))
- for member in tar.getmembers():
- f = tar.extractfile(member)
- with open('result.txt','a') as resultf:
- strs = f.read()
- resultf.write(strs)
解開 tar 包,并將結(jié)果寫入 result.txt 文件
假設(shè)我們 2200 個樣本文件的絕對路徑列表可以通過 get_sample_list 方法拿到
sample_2000_list, sample_20_list = get_sample_list()
計算 2000 個樣本與 20 個樣本的笛卡爾積,我們可以直接使用 itertools.product
- import itertools
- all = list(itertools.product(sample_2000_list, sample_20_list))
- assert len(all) == 40000
結(jié)合上面的代碼段,我們封裝一個方法:
- def worker(two_file_tuple):
- sample_one_dir, sample_two_dir = two_file_tuple
- with open(sample_one_dir) as onef:
- one_data = onef.read()
- with open(samle_two_dir) as twof:
- two_data = twof.read()
- data = one_data + two_data
- response = summitTask(imageName, token, data)
- untar(response)
因為構(gòu)造 HTTP 請求提交是 I/O 密集型而非計算密集型,所以我們使用協(xié)程池處理是非常高效的:
- import gevent.pool
- import gevent.monkey
- gevent.monkey.patch_all() # 猴子補丁
- pool = gevent.pool.Pool(200)
- pool.map(worker, all)
只是提交任務(wù) 200 并發(fā)很輕松
全部改造完成,我們來簡單分析一下:
之前是 8 個進程跑計算密集型算法,現(xiàn)在我們把計算密集型算法放到了 Serverless 產(chǎn)品中,因為客戶端是 I/O 密集型的,單機使用協(xié)程可以開很高的并發(fā),我們不貪心,按 200 并發(fā)來算:
進階閱讀:上面這種情況下帶寬反而有可能成為瓶頸,我們可以使用 gzip 來壓縮 HTTP body,這是一個計算比較密集的操作,為了 8 核心算力的高效利用,可以將樣本數(shù)據(jù)分為 8 份,啟動 8 個進程,進程中再使用協(xié)程去提交任務(wù)就好了。
- 40000 * 2 = 80000(秒)
- 80000 / 200 = 400(秒)
也就是說進行
一組檢測只需要 400 秒,從之前的 7 天提高到 400 秒,成果斐然,圖表更直觀:
而且算力瓶頸還遠(yuǎn)未達(dá)到,任務(wù)提交的并發(fā)數(shù)還可以提升,再給我們一臺機器提交任務(wù),便可以縮短到 200 秒,4 臺 100 秒,8 臺 50 秒...
最重要的是改造后的架構(gòu)還繼承了 Serverless 架構(gòu)的優(yōu)點:
- 免運維
- 高可用
- 按需付費
- 發(fā)布簡單
1. 免運維 -- 因為你沒有服務(wù)器了...
2. 高可用 -- Serverless 服務(wù)一般依托云計算的強大基礎(chǔ)設(shè)施,任何模塊都不會只有單點,都盡可能做到跨可用區(qū),或者跨交換機容災(zāi),而且本次使用的服務(wù)有一個有趣的機制:同一個任務(wù),你提交一次,會被多個節(jié)點執(zhí)行,如果一個計算節(jié)點掛了,其他節(jié)點還可以正常返回,哪個先執(zhí)行完,先返回哪個。
3. 按需付費 -- 文中說每個算法執(zhí)行一次花費單核心 CPU 時間 2 秒,我們直接算一下花費
- 2000 * 20 * 2 = 80000(秒)
- 80000 / 60 / 60 = 22.22(小時)
- 22.22(小時) * 0.09(元) * 1(核心) ~= 2(元)
- 每核時 0.09 元(即單核心 CPU 時間 1 小時,計費 9 分錢)
4. 發(fā)布簡單 -- 因為使用 Docker 作為載體,所以它是語言無關(guān)的,而且發(fā)布也很快,代碼寫好直接上傳鏡像就好了,至于灰度,客戶端 imageName 指定不同版本即可區(qū)分不同代碼了
不同的 Serverless 產(chǎn)品可能有不同的改造方法,作為工程師,我比較喜歡這種方式,改造成本低,靈活性高,你覺得呢?如果對 Serverless 架構(gòu)或者 UGC 感興趣的話可以添加 u_nknow 微信拉你進交流群哦
網(wǎng)站名稱:一次Serverless架構(gòu)改造實踐:基因樣本比對
網(wǎng)頁地址:http://www.dlmjj.cn/article/cooedep.html


咨詢
建站咨詢
