日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
如何調(diào)用一個只支持batch_call的服務(wù)?

為了更好的理解我說的是啥,我們來舉個例子。

10年的鳳縣網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。營銷型網(wǎng)站建設(shè)的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整鳳縣建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)從事“鳳縣網(wǎng)站設(shè)計”,“鳳縣網(wǎng)站推廣”以來,每個客戶項目都認(rèn)真落實執(zhí)行。

假設(shè)你現(xiàn)在在做一個類似B站的系統(tǒng),里面放了各種視頻。

用戶每天在里頭上傳各種視頻。

按理說每個視頻都要去審查一下有沒有搞顏色,但總不能人眼挨個看吧。

畢竟唐老哥表示這玩意看多了,看太陽都是綠色的,所以會有專門訓(xùn)練過的算法服務(wù)去做檢測。

但也不能上來就整個視頻每一幀都拿去做審查吧,所以會在每個視頻里根據(jù)時長和視頻類型隨機抽出好幾張圖片去做審查,比如視頻標(biāo)簽是美女的,算法愛看,那多抽幾張。標(biāo)簽是編程的,狗都不看,就少抽幾張。

將這些抽出來的圖片,送去審查。

為了實現(xiàn)這個功能,我們會以視頻為維度去做審核,而每個視頻里都會有N張數(shù)量不定的圖片,下游服務(wù)是個使用GPU去檢測圖片的算法服務(wù)。

現(xiàn)在問題來了,下游服務(wù)的算法開發(fā)告訴你,這些個下游服務(wù),它不支持很高的并發(fā),但請求傳參里給你加了個數(shù)組,你可以批量(batch)傳入一個比較大的圖片數(shù)組,通過這個方式可以提升點圖片處理量。

于是,我們的場景就變成。

上游服務(wù)的入?yún)⑹且粋€視頻和它的N張圖片,出參是這個視頻是否審核通過。

下游服務(wù)的入?yún)⑹荖張圖片的,出參是這個視頻是否審核通過。

batch_call上下游

現(xiàn)在我們想要用上游服務(wù)接入下游服務(wù)。該怎么辦?

看上去挺好辦的,一把梭不就完事了嗎?

當(dāng)一個視頻進(jìn)來,就拿著視頻的十多張圖片作為一個batch去進(jìn)行調(diào)用。

有幾個視頻進(jìn)來,就開幾個這樣的并發(fā)。

這么做的結(jié)果就是,當(dāng)并發(fā)大一點時,你會發(fā)現(xiàn)性能很差,并且性能非常不穩(wěn)定,比如像下面的監(jiān)控圖一樣一會3qps,一會15qps。處理的圖片也只支持20qps左右。

狗看了都得搖頭。

圖1-直接調(diào)用時qps很低

這可如何是好?

為什么下游需要batch call

本著先問是不是,再問為什么的精神,我們先看看為啥下游的要求會如此別致。

為什么同樣都是處理多張圖片,下游不搞成支持并發(fā)而要搞成批量調(diào)用(batch call)?

這個設(shè)定有點奇怪?

其實不奇怪,在算法服務(wù)中甚至很常見,舉個例子你就明白了。

同樣是處理多張圖片,為了簡單,我就假設(shè)是三張吧。如果是用單個cpu去處理的話。那不管是并發(fā)還是batch進(jìn)來,由于cpu內(nèi)部的計算單元有限,所以你可以簡單理解為,這三張圖片,就是串行去計算的。

cpu處理圖片時的流程

我計算第一張圖片是否能審核通過,跟第二張圖片是否能審核通過,這兩者沒有邏輯關(guān)聯(lián),因此按道理兩張圖片是可以并行計算。

奈何我CPU計算單元有限啊,做不到啊。

但是。

如果我打破計算單元有限的這個條件,給CPU加入超多計算單元,并且弱化一些對于計算沒啥用處的組件,比如cache和控制單元。那我們就有足夠的算力可以讓這些圖片的計算并行起來了。

并行處理圖片

是的,把CPU這么一整,它其實就變成了GPU。

GPU和CPU的區(qū)別

上面的講解只是為了方便理解,實際上,gpu會以更細(xì)的粒度去做并發(fā)計算,比如可以細(xì)到圖片里的像素級別。

這也是為什么如果我們跑一些3d游戲的時候,需要用到顯卡,因為它可以快速的并行計算畫面里每個地方的光影,遠(yuǎn)近效果啥的,然后渲染出畫面。

回到為什么要搞成batch call的問題中。

其實一次算法服務(wù)調(diào)用中,在數(shù)據(jù)真正進(jìn)入GPU前,其實也使用了CPU做一些前置處理。

因此,我們可以簡單的將一次調(diào)用的時間理解成做了下面這些事情。

GPU處理圖片時的流程

服務(wù)由CPU邏輯和GPU處理邏輯組成,調(diào)用進(jìn)入服務(wù)后,會有一些前置邏輯,它需要CPU來完成,然后才使用GPU去進(jìn)行并行計算,將結(jié)果返回后又有一些后置的CPU處理邏輯。中間的GPU部分,管是計算1張圖,還是計算100張圖,只要算力支持,那它們都是并行計算的,耗時都差不多。

如果把這多張圖片拆開,并發(fā)去調(diào)用這個算法服務(wù),那就有 N組這樣的CPU+GPU的消耗,而中間的并行計算,其實沒有利用到位。

并且還會多了前置和后置的CPU邏輯部分,算法服務(wù)一般都是python服務(wù),主流的一些web框架幾乎都是以多進(jìn)程,而不是多線程的方式去處理外部請求,這就有可能導(dǎo)致額外的進(jìn)程間切換消耗。

當(dāng)并發(fā)的請求多了,請求處理不過來,后邊來的請求就需要等前邊的處理完才能被處理,后面的請求耗時看起來就會變得特別大。這也是上面圖1里,接口延時(latency)像過山車那樣往上漲的原因。

還是上面的圖1的截圖,一張圖用兩次哈哈

按理說減少并發(fā),增大每次調(diào)用時的圖片數(shù)量,就可以解決這個問題。

這就是推薦batch call的原因。

但問題又來了。

每次調(diào)用,上游服務(wù)輸入的是一個視頻以及它的幾張圖片,調(diào)用下游時,batch的數(shù)量按道理就只能是這幾張圖片的數(shù)量,怎么才能增大batch的數(shù)量呢?

這里的調(diào)用,就需要分為同步調(diào)用和異步調(diào)用了。

同步調(diào)用和異步調(diào)用的區(qū)別

同步調(diào)用,意思是上游發(fā)起請求后,阻塞等待,下游處理邏輯后返回結(jié)果給上游。常見的形式就像我們平時做的http調(diào)用一樣。

同步調(diào)用

異步調(diào)用,意思是上游發(fā)起請求后立馬返回,下游收到消息后慢慢處理,處理完之后再通過某個形式通知上游。常見的形式是使用消息隊列,也就是mq。將消息發(fā)給mq后,下游消費mq消息,觸發(fā)處理邏輯,然后再把處理結(jié)果發(fā)到mq,上游消費mq的結(jié)果。

異步調(diào)用

異步調(diào)用的形式接入

異步調(diào)用的實現(xiàn)方式

回到我們文章開頭提到的例子,當(dāng)上游服務(wù)收到一個請求(一個視頻和它對應(yīng)的圖片),這時候上游服務(wù)作為生產(chǎn)者將這個數(shù)據(jù)寫入到mq中,請求返回。然后新造一個C服務(wù),負(fù)責(zé)批量消費mq里的消息。這時候服務(wù)C就可以根據(jù)下游服務(wù)的性能控制自己的消費速度,比如一次性消費10條數(shù)據(jù)(視頻),每個數(shù)據(jù)下面掛了10個圖片,那我一次batch的圖片數(shù)量就是10*10=100張,原來的10次請求就變?yōu)榱?次請求。這對下游就相當(dāng)?shù)挠押昧恕?/p>

下游返回結(jié)果后,服務(wù)C將結(jié)果寫入到mq的另外一個topic下,由上游去做消費,這樣就結(jié)束了整個調(diào)用流程。

當(dāng)然上面的方案,如果你把mq換成數(shù)據(jù)庫,一樣是ok的,這時候服務(wù)C就可以不斷的定時輪詢數(shù)據(jù)庫表,看下哪些請求沒處理,把沒處理的請求批量撈出來再batch call下游。不管是mq還是數(shù)據(jù)庫,它們的作用無非就是作為中轉(zhuǎn),暫存數(shù)據(jù),讓服務(wù)C根據(jù)下游的消費能力,去消費這些數(shù)據(jù)。

這樣不管后續(xù)要加入多少個新服務(wù),它們都可以在原來的基礎(chǔ)上做擴展,如果是mq,加topic,如果是數(shù)據(jù)庫,則加數(shù)據(jù)表,每個新服務(wù)都可以根據(jù)自己的消費能力去調(diào)整消費速度。

mq串聯(lián)多個不同性能的服務(wù)

其實對于這種上下游服務(wù)處理性能不一致的場景,最適合用的就是異步調(diào)用。而且涉及到的服務(wù)性能差距越大,服務(wù)個數(shù)越多,這個方案的優(yōu)勢就越明顯。

同步調(diào)用的方式接入

雖然異步調(diào)用在這種場景下的優(yōu)勢很明顯,但也有個缺點,就是它需要最上游的調(diào)用方能接受用異步的方式去消費結(jié)果。其實涉及到算法的服務(wù)調(diào)用鏈,都是比較耗時的,用異步接口非常合理。但合理歸合理,有些最上游他不一定聽你的,就是不能接受異步調(diào)用。

這就需要采用同步調(diào)用的方案,但怎么才能把同步接口改造得更適合這種調(diào)用場景,這也是這篇文章的重點。

限流

如果直接將請求打到下游算法服務(wù),下游根本吃不消,因此首先需要做的就是給在上游調(diào)用下游的地方,加入一個速率限制(rate limit)。

這樣的組件一般也不需要你自己寫,幾乎任何一個語言里都會有現(xiàn)成的。

比如golang里可以用golang.org/x/time/rate庫,它其實是用令牌桶算法實現(xiàn)的限流器。如果不知道令牌桶是啥也沒關(guān)系,不影響理解。

限流器邏輯

當(dāng)然,這個限制的是當(dāng)前這個服務(wù)調(diào)用下游的qps,也就是所謂的單節(jié)點限流。如果是多個服務(wù)的話,網(wǎng)上也有不少現(xiàn)成的分布式限流框架。但是,還是那句話,夠用就好。

限流只能保證下游算法服務(wù)不被壓垮,并不能提升單次調(diào)用batch的圖片數(shù)量,有沒有什么辦法可以解決這個問題呢?

參考Nagle算法的做法

我們熟悉的TCP協(xié)議里,有個算法叫Nagle算法,設(shè)計它的目的,就是為了避免一次傳過少數(shù)據(jù),提高數(shù)據(jù)包的有效數(shù)據(jù)負(fù)載。

當(dāng)我們想要發(fā)送一些數(shù)據(jù)包時,數(shù)據(jù)包會被放入到一個緩沖區(qū)中,不立刻發(fā)送,那什么時候會發(fā)送呢?

數(shù)據(jù)包會在以下兩個情況被發(fā)送:

  • 緩沖區(qū)的數(shù)據(jù)包長度達(dá)到某個長度(MSS)時。
  • 或者等待超時(一般為200ms)。在超時之前,來的那么多個數(shù)據(jù)包,就是湊不齊MSS長度,現(xiàn)在超時了,不等了,立即發(fā)送。

這個思路就非常值得我們參考。我們完全可以自己在代碼層實現(xiàn)一波,實現(xiàn)也非常簡單。

1.我們定義一個帶鎖的全局隊列(鏈表)。

2.當(dāng)上游服務(wù)輸入一個視頻和它對應(yīng)的N張圖片時,就加鎖將這N張圖片數(shù)據(jù)和一個用來存放返回結(jié)果的結(jié)構(gòu)體放入到全局隊列中。然后死循環(huán)讀這個結(jié)構(gòu)體,直到它有結(jié)果。就有點像阻塞等待了。

3.同時在服務(wù)啟動時就起一個線程A專門用于收集這個全局隊列的圖片數(shù)據(jù)。線程A負(fù)責(zé)發(fā)起調(diào)用下游服務(wù)的請求,但只有在下面兩個情況下會發(fā)起請求

  • 當(dāng)收集的圖片數(shù)量達(dá)到xx張的時候
  • 距離上次發(fā)起請求過了xx毫秒(超時)

4.調(diào)用下游結(jié)束后,再根據(jù)一開始傳入的數(shù)據(jù),將調(diào)用結(jié)果拆開來,送回到剛剛提到的用于存放結(jié)果的結(jié)構(gòu)體中。

5.第2步里的死循環(huán)因為存放返回結(jié)果的結(jié)構(gòu)體,有值了,就可以跳出死循環(huán),繼續(xù)執(zhí)行后面的邏輯。

batch_call同步調(diào)用改造

這就像公交車站一樣,公交車站不可能每來一個顧客就發(fā)一輛公交車,當(dāng)然是希望車?yán)镱櫩驮蕉嘣胶?。上游每來一個請求,就把請求里的圖片,也就是乘客,塞到公交車?yán)?,公交車要么到點發(fā)車(向下游服務(wù)發(fā)起請求),要么車滿了,也沒必要等了,直接發(fā)車。這樣就保證了每次發(fā)車的時候公交車?yán)锏念櫩蛿?shù)量足夠多,發(fā)車的次數(shù)盡量少。

大體思路就跟上面一樣,如果是用go來實現(xiàn)的話,就會更加簡單。

比如第1步里的加鎖全局隊列可以改成有緩沖長度的channel。第2步里的"用來存放結(jié)果的結(jié)構(gòu)體",也可以改成另一個無緩沖channel。執(zhí)行 res := <-ch, 就可以做到阻塞等待的效果。

而核心的仿Nagle的代碼也大概長下面這樣。當(dāng)然不看也沒關(guān)系,反正你已經(jīng)知道思路了。

func CallAPI() error {
size := 100
// 這個數(shù)組用于收集視頻里的圖片,每個 IVideoInfo 下都有N張圖片
videoInfos := make([]IVideoInfo, 0, size)
// 設(shè)置一個200ms定時器
tick := time.NewTicker(200 * time.Microsecond)
defer tick.Stop()
// 死循環(huán)
for {
select {
// 由于定時器,每200ms,都會執(zhí)行到這一行
case <-tick.C:
if len(videoInfos) > 0 {
// 200ms超時,去請求下游
limitStartFunc(videoInfos, true)
// 請求結(jié)束后把之前收集的數(shù)據(jù)清空,重新開始收集。
videoInfos = make([]IVideoInfo, 0, size)
}
// AddChan就是所謂的全局隊列
case videoInfo, ok := <-AddChan:
if !ok {
// 通道關(guān)閉時,如果還有數(shù)據(jù)沒有去發(fā)起請求,就請求一波下游服務(wù)
limitStartFunc(videoInfos, false)
videoInfos = make([]IVideoInfo, 0, size)
return nil
} else {
videoInfos = append(videoInfos, videoInfo)
if videoInfos 內(nèi)的圖片滿足xx數(shù)量 {
limitStartFunc(videoInfos, false)
videoInfos = make([]IVideoInfo, 0, size)
// 重置定時器
tick.Reset(200 * time.Microsecond)
}
}
}
}
return nil
}

通過這一操作,上游每來一個請求,都會將視頻里的圖片收集起來,堆到一定張數(shù)的時候再統(tǒng)一請求,大大提升了每次batch call的圖片數(shù)量,同時也減少了調(diào)用下游服務(wù)的次數(shù)。真·一舉兩得。

優(yōu)化的效果也比較明顯,上游服務(wù)支持的qps從原來不穩(wěn)定的3q~15q變成穩(wěn)定的90q。下游的接口耗時也變得穩(wěn)定多了,從原來的過山車似的飆到15s變成穩(wěn)定的500ms左右。處理的圖片的速度也從原來20qps提升到350qps。

到這里就已經(jīng)大大超過業(yè)務(wù)需求的預(yù)期(40qps)了,夠用就好,多一個qps都是浪費。

可以了,下班吧。

總結(jié)

  • 為了充分利用GPU并行計算的能力,不少算法服務(wù)會希望上游通過加大batch的同時減少并發(fā)的方式進(jìn)行接口調(diào)用。
  • 對于上下游性能差距明顯的服務(wù),建議配合mq采用異步調(diào)用的方式將服務(wù)串聯(lián)起來。
  • 如果非得使用同步調(diào)用的方式進(jìn)行調(diào)用,建議模仿Nagle算法的形式,攢一批數(shù)據(jù)再發(fā)起請求,這樣既可以增大batch,同時減少并發(fā),真·一舉兩得,親測有效。

最后

講了那么多可以提升性能的方式,現(xiàn)在需求來了,如果你資源充足,但時間不充足,那還是直接同步調(diào)用一把梭吧。

性能不夠?下游加機器,gpu卡,買!

然后下個季度再提起一個技術(shù)優(yōu)化,性能提升xx%,cpu,gpu減少xx%。

有沒有聞到?

這是KPI的味道。


網(wǎng)站名稱:如何調(diào)用一個只支持batch_call的服務(wù)?
本文URL:http://m.5511xx.com/article/dpdesdp.html