偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

從SPserver到BRPC

開發(fā) 后端
本文是之家廣告引擎團隊結合工作中遇到的超時現(xiàn)象及問題分析過程,對服務框架升級背后的思考做出的一個總結與沉淀。

公眾號轉載自:汽車之家技術委員會

1.背景 

性能優(yōu)化是后端服務優(yōu)化的一個重要課題。尤其在廣告業(yè)務中,服務超時不但會引發(fā)廣告客戶的預算消耗顧慮,更會直接影響C端用戶的瀏覽體驗。而一個服務程序的性能往往是覆蓋了編程語言特性、業(yè)務需求邏輯,甚至是操作系統(tǒng)底層原理等多方面因素的綜合性外在表現(xiàn)。面對超時問題,不論是對其進行量化分解、問題復現(xiàn),還是異常監(jiān)控,以及后續(xù)的超時優(yōu)化,對后端開發(fā)同學而言都極富挑戰(zhàn)。如果變換思路,轉而升級后端服務框架或許會成為最為徹底的解決方案。

本文是之家廣告引擎團隊結合工作中遇到的超時現(xiàn)象及問題分析過程,對服務框架升級背后的思考做出的一個總結與沉淀。

2.問題回顧 

之家廣告檢索服務從建立之初采用的一直是SPserver服務框架。Spserver是一個C++實現(xiàn)的半同步異步的網(wǎng)絡框架,名氣雖然不大,但在當年并發(fā)編程尤其是協(xié)程概念尚不廣泛的年代,相比較代碼風格各異、封裝獨立性參差不齊的諸多自研網(wǎng)絡框架,它確實不失為一個比較好的選擇。特別是在之家廣告系統(tǒng)搭建之初,其以良好的性能、穩(wěn)定性和簡便的使用方式,在引擎內部曾得到廣泛應用,可以說在推進廣告業(yè)務發(fā)展上,SPserver立下了汗馬功勞。

隨著需求的不斷迭代和升級,廣告系統(tǒng)運行中碰到的問題也越來越凸顯,包括:內存消耗、并發(fā)、超時、生態(tài)融合等等,其中又以超時問題為重。

說起超時,恐怕會讓人抓狂,因為它來的太突然而且?guī)缀醪涣羧魏魏圹E。沒錯,監(jiān)控可以抓到它,但問題是通過分析全鏈路日志你可能不會有任何收獲,因為你所劃分的各個業(yè)務邏輯階段的耗時并沒有超過預先設定的超時閾值,而且進程的CPU利用率也不高(可以說很低),讓人詭異的是上游請求方的超時卻是實實在在發(fā)生了的。

3.問題分析 

應用服務不是孤立的,它所發(fā)生的問題也應該是有關聯(lián)的。

圖片

(圖1:來自網(wǎng)絡)

通過圖1知道,一個業(yè)務應用在處理網(wǎng)絡請求之前以及發(fā)送網(wǎng)絡應答之后,數(shù)據(jù)會流經網(wǎng)絡、系統(tǒng)內核。那么,超時會不會是由它們引起的呢?為此,我們通過壓測環(huán)境復現(xiàn)了超時發(fā)生的系統(tǒng)上下文場景:

圖片

(圖2)

可以發(fā)現(xiàn),業(yè)務應用與其上下游之間經由多個tcp連接通信,而部分tcp連接在對應socket的接收緩沖區(qū)和發(fā)送緩沖區(qū)卻存在著數(shù)據(jù)積壓的現(xiàn)象,且兩個隊列的積壓數(shù)據(jù)量分別固定在4xx和2xx。

不同于grpc倡導的單通道通信模式,spserver原生支持多tcp連接服務,這點無可厚非?;趖cp協(xié)議的擁塞控制機制,網(wǎng)絡數(shù)據(jù)進入應用層前,會在操作系統(tǒng)內核態(tài)的fd緩沖區(qū)稍作停留,因此短時間內存在一定量的數(shù)據(jù)積壓也是正常的;既然是緩沖區(qū),自然有大小之分。那么,會不會是緩沖區(qū)太小或者網(wǎng)絡擁堵導致的超時呢?又該如何判斷呢?

圖片

(圖3)

可見,系統(tǒng)對socket收發(fā)緩沖區(qū)的默認值都在80k以上,遠大于圖2中的431字節(jié)。而且spserver源代碼中也沒有通過setsockopt系統(tǒng)調用對socket的收發(fā)緩沖區(qū)重新設值。所以,圖2中緩沖區(qū)大小是合理的,而其中接收隊列中的數(shù)據(jù)量431則可能是有問題的(實際上,431是壓測場景中單次請求的數(shù)據(jù)長度;在生產環(huán)境中,這個隊列長度會隨著C端請求的不同而呈現(xiàn)不同的值,毫無規(guī)律可言)。

連續(xù)刷新netstat,對比目標tcp連接的發(fā)送緩沖隊列或接收隊列長度,發(fā)現(xiàn)此場景下收發(fā)隊列的長度并不能立即消失,也沒有減小,而是持續(xù)了1秒左右才有所變化。由此可以推測2種可能:1)網(wǎng)絡擁堵;2)服務端cpu繁忙,不能及時將數(shù)據(jù)從緩沖區(qū)讀走。第一種猜測通過網(wǎng)絡檢測工具很容易驗證,是否定的;第二種猜測,也通過查看系統(tǒng)以及進程cpu的利用率也很容易排除掉。分析排查到此,似乎走到了死胡同。真的是這樣嗎?

有一個細節(jié)似乎被忽略了:作為多線程服務,進程的cpu利用率≈線程cpu利用率之和,但進程cpu利用率低并不意味著某些或某個線程cpu利用率也低。換句話說,個別線程所在cpu的高利用率同樣會使上面第二種猜測成立。

圖片

(圖4)

如圖4,反復施加不同量級的請求壓力,會發(fā)現(xiàn)除了18194號線程的cpu使用率保持在99%以上,其他線程的cpu使用率最大都不過40%左右。面對高壓力,服務不能平攤cpu壓力,這就是問題!

4.根本原因 

上帝總是吝嗇造就一個十全十美的東西,對待SPserver自然也不例外。其實排查走到線程的cpu利用率時,已經接近真實原因,但還不是真相。為此,擼了一遍spserver的源碼,得出如下線程模型示意圖。

圖片

(圖5)

不出所料,SPserver采用的是單線程reactor網(wǎng)絡模型,即單線程負責事件監(jiān)聽、socket讀寫,多線程負責業(yè)務邏輯處理。單線程io的優(yōu)劣顯而易見,可以很好的利用thread local加速,也沒有cpu cache bounding的問題;但問題是一旦某個socket上待讀取或待發(fā)送的數(shù)據(jù)量較大時,就會阻塞其他socket上數(shù)據(jù)的收發(fā),這就比較致命。退一步講,即便每個socket fd上的數(shù)據(jù)量大小均勻,在上述單線程的cpu吃滿時,整個框架的數(shù)據(jù)收發(fā)效率同樣會成為所在服務的性能瓶頸。

真相大白了,原來SPserver框架的設計機制決定了它不適合高并發(fā)、高吞吐業(yè)務場景的事實。但如果是在業(yè)務初期又或是業(yè)務流量比較小,個人覺得它仍可視為一個不錯的選擇(SPserver框架的c++代碼風格還是很不錯的,很簡潔,封裝性也很好,值得借鑒)。

5.選擇BRPC 

如今rpc框架林立,我們的選擇是百度研發(fā)的brpc框架,主要是基于以下考慮:

1)高并發(fā)高性能

個人理解后面會著重介紹一下。這里我只貼一個brpc和其他rpc框架性能的對比圖:

圖片

(圖6:來自brpc官網(wǎng))

是的,你沒有看錯,在跨機多client請求單server的場景下,brpc框架的性能已經絕對領先國外知名的rpc框架,尤其是grpc,用碾壓一詞來形容也不為過。

2)文檔資料豐富

brpc有著豐富的中英文文檔,豐富程度讓人有點難以置信,曾一度有人認為是百度內部的技術資料無意中被公開了,呵呵。

3)apache 的頂級項目,目前有數(shù)千個企業(yè)級應用

說直白點,已經在生產中經歷過千錘百煉了,質量有保證。

當然,brpc還有諸多特性,這里不再贅述。詳見brpc官網(wǎng)或移步到github incubator-brpc項目。

6.性能初探 

經歷了spserver框架,免不了要有一番對比。在介紹brpc的線程模型前,先了解一個bprc中的概念:bthread。我們看一下官方的解釋:

“bthread是brpc使用的M:N線程庫,目的是在提高程序的并發(fā)度的同時,降低編碼難度,并在核數(shù)日益增多的CPU上提供更好的scalability和cache locality?!盡:N“是指M個bthread會映射至N個pthread,一般M遠大于N。由于linux當下的pthread實現(xiàn)[NPTL]是1:1的,M個bthread也相當于映射至N個[LWP]。bthread的前身是Distributed Process(DP)中的fiber,一個N:1的合作式線程庫,等價于event-loop庫,但寫的是同步代碼?!?/p>

個人理解bthread其實是一個運行在系統(tǒng)pthread之上的可以低成本、靈活調度的任務(隊列),而這個任務載有自身運行時的上下文信息(比如:棧、寄存器、signal等),使它能夠隨意切換在不同的pthread上運行。其低成本體現(xiàn)在幾個方面:1)bthread實現(xiàn)了多種同步原語,可以和系統(tǒng)線程實現(xiàn)相互等待,我們可以像使用pthread一樣使用bthread;2)納秒級建立bthread,耗時遠低于pthread;3)幾乎沒有上下文切換,且將cpu cache locality和thread local發(fā)揮到了極致,這部分后面會有實踐說明。

下面再來看看它的線程模型示意圖:

圖片

(圖7)

由圖7可見:1)在brpc框中系統(tǒng)級線程池pthread是高效運行的基礎設施,不再與具體的業(yè)務邏輯直接綁定,取而代之的是bthread;2)bthread按不同責任分成不同類型,且不同類型的bthread有著不同的數(shù)量。比如:網(wǎng)絡事件的監(jiān)聽和驅動由一個bthread專職處理,當然也可以通過命令行啟動服務時配置,或者服務啟動后通過web入口更新;而處理具體請求的bthread數(shù)量則是動態(tài)計算的;3)brpc支持不忙的線程“偷”繁忙線程的bthread任務來提升系統(tǒng)整體效能。

那么問題來了,某一個socket fd上大量數(shù)據(jù)的接收或發(fā)送,會發(fā)生類似spserver那樣的阻塞嗎?答案是不會。首先,每個fd有兩個bthread,分別負責接收和發(fā)送,這就能保證收發(fā)互不影響;其次,bthread作為被調度的任務,會被分派給不同系統(tǒng)線程(也就是pthread),而一個系統(tǒng)線程同一時刻只能執(zhí)行一個bthread任務,加上bthread 支持的stealing機制,就保證了進程中所有線程都是有事可做的,不會存在空閑的pthread(除非請求量非常小,不足以給pthread平分)。因此,基本上是不可能發(fā)生“一處阻塞處處阻塞”的情況的。

使用更大量的壓測請求對brpc服務發(fā)壓,得到各pthread的cpu消耗如下:

圖片

(圖8)

由圖8可見,系統(tǒng)的多核cpu得到充分的調動,且隨著壓力的增大cpu的擴展性表現(xiàn)良好;再來看一下網(wǎng)絡隊列:

圖片

(圖9)

可見,(同機grpc單通道壓測,僅有一個tcp連接)tcp fd的收發(fā)緩沖區(qū)得到了充分的利用,且隊列長度很快能減少至0。

Socket緩沖區(qū)不再是擺設,整個系統(tǒng)活了起來!

另外,值得一提的是線程間的上下文切換。因為過多的上下文切換,會把cpu時間消耗在寄存器、線程棧的保存和恢復上,從而降低服務的整體性能。brpc框架的m:n線程庫,在這方面做的比較好,它使用固定的系統(tǒng)線程調度運行大量用戶態(tài)的bthread,將所有的切換基本上都限制在了用戶態(tài),這就避免了內核態(tài)和用戶態(tài)的數(shù)據(jù)交換(用戶態(tài)之間切換耗時在100~200ns,而內核態(tài)和用戶態(tài)切換則在微秒級)。通過命令也可以證明這一點:

圖片

(圖10)

如圖10,我們的服務在使用brpc后上下文切換頻次基本保持在每秒1次。再回頭來看看spserver框架,由于沒有用戶態(tài)任務的概念,只是單純依賴系統(tǒng)級的線程池,就不可避免的使cpu不斷地游離于多線程調度和任務執(zhí)行上,內核態(tài)和用戶態(tài)間的上下文切換開銷肯定少不了:

圖片

(圖11)

用戶態(tài)線程切換的另一個好處是,可以將內核態(tài)線程與cpu核心很好的綁定到了一起,這就能夠盡量避免cpu不同核心間cacheline的數(shù)據(jù)同步,從而提升性能,這也是brpc框架高性能的一個原因。

7.應用實踐 

brpc的編譯安裝及基本使用,在官方文檔都有較為詳細的說明,比較簡單。這里再分享一下我們在brpc應用過程中遇到過的幾個值得注意的地方:

1)thread local.

它是多線程程序常用的加速手段。比如tcmalloc就充分利用了這個技術,通過在線程內部設置局部緩存來加速小額空間的申請效率。之家廣告引擎服務毫無例外的也使用了這項技術。但需要注意的是,在引入brpc框架后,原有的pthread id可能將不再有效,如果你執(zhí)意為之,就可能會在程序運行期間遇到莫名其妙的段錯誤。這是因為我們的業(yè)務代碼是托管在bthread中的,而bthread是在系統(tǒng)pthread之間隨機游走的,使用pthread1的標識信息到pthreadN的線程棧中讀取緩存數(shù)據(jù)自然是讀不到的。我們的臨時解決辦法是,暫時剝離掉thread local緩存,在控制鎖粒度的前提下改為全局cache,暴力、簡單、有效。

2)cpu profiler

顧名思義,你的程序可能會因此得以優(yōu)化并加速運行。但事實并非完全如此。如果你們業(yè)務程序的CMakeList來自某個demo或網(wǎng)絡程序,則最好要注意這個編譯選項。它的原理是通過調用對應的庫函數(shù)采集活躍線程中的線程函數(shù)信息,并根據(jù)棧體現(xiàn)的函數(shù)調用關系生成調用圖,進而進行調用優(yōu)化。所以,它會加速但不是立即,因為它要先采集數(shù)據(jù)、再分析,最后才能優(yōu)化運行。我們實踐初期,肉眼可見其性能相比較不加此編譯選項要低10%以上,所以,對待cpu profiler要慎用。

3)關于grpc

前面提到過,gprc默認是基于單通道的通信方式,這是既是google官方的建議也是微軟的實踐建議。下面截圖來自微軟的” Performance best practices with gRPC”一文:

圖片

(圖12:截自微軟官網(wǎng))

不能總是人云亦云。結合具體業(yè)務場景,我們的實踐結論是:多通道數(shù)據(jù)傳輸效率要優(yōu)于單通道。受限于tcp速率限制,單通道(連接)情況下,一旦遇到高吞吐的數(shù)據(jù)傳輸業(yè)務場景,會明顯阻塞此網(wǎng)絡連接。特別對于廣告業(yè)務來說,我們允許有大數(shù)據(jù)塊傳輸,但不允許大數(shù)據(jù)塊的傳輸影響其他正常的廣告數(shù)據(jù)響應。

因此,我們的建議是:要么使用多通道grpc或者其他協(xié)議方式,要么就放棄grpc吧(事實上,grpc在生產中還有其他問題)。

4)并發(fā)

早在spserver時期,我們曾在其中實現(xiàn)了并發(fā)線程庫(確切說是一個并發(fā)線程類),但效果并未達到預期,因為它一定程度上加重了多線程調度成本。而如今的brpc則直接提供了較為簡單的并發(fā)線程 api,我們可以直接使用,無需造輪。

然而,會面臨新的選擇:用bthread_start_background,還是用bthread_start_urgent。使用后者啟動bthread后會在當前pthread立即執(zhí)行任務,而前者則會讓新生成的bthread任務排隊等待調度。在我們的廣告檢索過濾場景中,適合使用后者;而在執(zhí)行http請求時,則更適合使用前者。建議brpc開發(fā)者,一定要根據(jù)自己業(yè)務的實際情況再做決定。

8.最后 

通過從SPserver框架升級到BRPC框架,在相同的業(yè)務場景下,之家廣告服務qps從5w+提升到了10w左右,服務實例數(shù)也因此下降了一半以上,收益明顯。

另外,Brpc提供了相對豐富的內置服務,這里貼兩個具有代表性功能的web界面,都比較實用,推薦大家嘗試。

圖13:我們可以看到服務的qps、latency分布等數(shù)據(jù),方便把握服務的運行時信息。

圖片

(圖13)

而從下圖,可以看到服務運行期間在等待鎖上所消耗的時間及發(fā)生等待的函數(shù),從而支持我們有針對性的開展性能優(yōu)化。

圖片

(圖14)

note

限于作者水平,難免會有理解和描述上的疏漏或者錯誤,歡迎共同交流、指正。文章供于學習交流,轉載注明出處,謝謝!

作者簡介

圖片

汽車之家

主機廠事業(yè)部-技術部

楊明哲

2018年加入汽車之家,目前任職于主機廠事業(yè)部-技術部-廣告技術及系統(tǒng)團隊,負責之家廣告引擎架構的設計與研發(fā)等相關工作。

圖片

責任編輯:武曉燕 來源: 汽車之家技術委員會
相關推薦

2025-04-30 10:55:46

2023-11-16 21:20:13

ListWatchkube

2021-03-03 08:18:54

Service組件

2022-05-09 08:35:43

面試產品互聯(lián)網(wǎng)

2015-09-17 13:09:48

預裝軟件毒瘤國產手機

2023-10-12 15:38:50

FreeDOS命令

2013-06-06 13:42:48

OSPF入門配置

2017-06-26 09:15:39

SQL數(shù)據(jù)庫基礎

2022-09-04 21:46:12

數(shù)據(jù)信息風險

2013-04-07 10:10:23

2023-12-27 06:48:49

KubernetesDevOpsHTTP

2019-07-02 14:17:18

API網(wǎng)關網(wǎng)關流量

2018-01-18 04:52:07

2016-11-28 16:23:23

戴爾

2010-12-22 12:00:48

軟件保護軟件授權

2010-02-06 15:31:18

ibmdwAndroid

2009-07-22 14:55:16

ibmdwAndroid

2012-04-26 10:48:01

iOS開發(fā)互動廣告

2021-09-01 22:58:22

Canvas標簽
點贊
收藏

51CTO技術棧公眾號