brpc初探


因為最近在看一個內部開源代碼,看到了braft。braft又依賴於brpc。於是就看了相關的文檔,打算接下來試一把。

這里引用下gejun大佬在知乎上的回答(https://www.zhihu.com/question/65370268/answer/231801580)。

RPC是個老概念,五花八門的實現非常多。在14年我剛轉到基礎架構部時,其實是不想做RPC框架的。我的想法可能和很多工程師一樣:之前做了那么多系統,現在就讓我來搞個編程框架?而且這能做出什么花頭?但事實很快證明我錯了,編程上的事真的需要實踐,否則看問題就很淺。像搞深度學習,vgg rcnn gan嘴上可以說得不停,但只要你沒在真正嚴肅的項目中調過參數,你就是門外漢。
RPC的深度在於現代的互聯網公司中幾乎所有服務都是使用RPC的,大部分工程師和它打交道。如果你能看到其中的痛點,提高了效率,那么整個公司的開發效率都會有明顯的提升。大家都是從學生時代過來的,心里清楚一個東西在正確的條件下正確運行很容易,但要在所有情況下能正確運行就非常困難。前兩天我修了個問題:brpc在fedora 26下一個weak function莫名其妙地沒有被tcmalloc中的對應版本覆蓋,導致heap profiler啟用不了,ubuntu,centos下都是好的。這種問題往往和系統或ld有關,要精確定位很麻煩,最后我找到了一個workaround。但這個事情耗了我幾個小時,因為需要在很多系統上驗證沒有regression。RPC里大量此類東西,雖然麻煩但能提高用戶體驗。那個問題其實和brpc對tcmalloc的支持方式有關,brpc默認不鏈接tcmalloc,但用戶在程序中鏈接tcmalloc后,我們希望cpu和heap profiler要自動開啟(這兩個功能依賴tcmalloc的API),同時用戶不用重編brpc。所以我們得在brpc中動態判定是否鏈接了tcmalloc,這就沒那么容易了。對我們很麻煩,但用戶的體驗更好了,甚至用戶會覺得理所當然。
知識是需要大量實踐的,你也許可以在正確的條件下用dlsym有效地覆蓋一個glibc中的函數,但你可能不知道dlsym在有多版本符號存在時可能無效,或dlsym和一些庫合用時(比如用於展開棧的libunwind)會死鎖,或dlsym對靜態鏈接是無效的除非編譯加了-rdynamic。你也許可以基於一些上下文切換庫三下五除二搞出個libcoroutine,但你可能不知道的是JNI會檢查stack layout而不能使用自定義棧,或程序運行在valgrind中需要注冊棧地址才不會報錯,或一個棧跑到另一個LWP上展開時會觸發gcc4以上版本的thread-local誤優化。這些知識,成千上萬條這種知識,通過實踐才會深深地刻畫在腦中,構成一個工程師真正的競爭力。
我一直堅信所有的用戶體驗都是端到端的,只有站在用戶的角度,把整個流程以既高效又不失擴展性的方式走通,才是最好的選擇。良好的文檔正是這種理念的體現:給新用戶鋪好路能快速上手,讓老用戶知其所以然更上一層樓。這種想法也體現在代碼中的方方面面:每個選項都有合理的默認值,用戶不設也能用;在注釋中提示best practice,避免用戶走彎路;用戶界面、日志內容不啰嗦,讓用戶一眼看清楚問題的全貌。不做並不意味着我們沒能力做,而是早已被事實證明可能出現非常subtle的bug而被淘汰掉的選擇。知道的越多,你就越會有一種責任感,需要幫助用戶修一條好路,避免陷到你已經踩過的成百上千個坑中。
說到性能,RPC的性能評估其實很像VC投資初創公司:每家都在說自己的東西好,並能拿出數據,可真的好不好天曉得。所以VC只能看團隊,查背景,憑感覺,這錢花出去了能不能拿回來心里都慌的很。RPC其實也這樣,每個實現都有大量獨特的設計和接口,用戶不太可能輕易地從一個RPC切換到另一個RPC,並在完全相同的環境下進行對比。每個RPC實現都在說自己高性能,輕量級。這是個自賣自誇的游戲,用戶只能看臉。但就像我們奇怪古人連那么簡單的東西都不知道一樣,人的認知就是這樣,內行的常識可能對外行非常困難,甚至這個常識非常簡單。在很多年以前,我們對“高性能”的認識還停留在“極限QPS”和“延時”兩個維度的時候,被一個復雜系統中的擁塞問題搞的焦頭爛額,大家就覺得莫名其妙啊,每個環節都很快,這延時怎么就嘩嘩嘩地漲上去了。最后在反反復復的思考和分析后才發現,QPS和延時的乘積與程序的最大服務能力緊密相連。我們搞了個概念叫volume,發現串行系統的volume可以相加,並行系統的volume可以求min,然后一層層地迭代上去從而計算出復雜系統同時能處理的最大請求數,並解決了擁塞問題。
不過就是個乘法。
今天我們知道這個原理是little’s law,tcp中的BDP也是類似的道理。我們在文檔中描述了相關的知識。但即使是這樣,根據我們在百度內的支持經驗(沒人會否認百度研發的整體素質吧),大部分RPC的用戶對這個乘法理解還是有困難的,更別提理解串行相加,並行求min,在系統設計中活學活用了。一個乘法尚且同此,更深入的可想而知。普通用戶是很難看明白性能測試的道道的。我們團隊里有個老梗:“處處是熱點,處處不是瓶頸”。這說的是如果整個程序寫的都很粗暴,不考慮性能,最后用profiler一跑,發現每個點都只有1%,2%,然后得出結論,“性能非常好,優化空間已經不大”。但實際上你去分析下hot path,會發現有太多可以大幅提高的點了。性能就是這樣,設計確保了流程是最優化的,但實現也非常重要,細節全靠摳。brpc上關鍵路徑上的代碼多一次new都需要討論,最熱的路徑上甚至不允許出現申明一個可能無用的空std::string,因為glibc中的空string是要加引用計數的,對cache有影響。
摳細節的背后需要工程師對性能的深入理解。一個函數的性能是可以估算出來的,測試只是驗證。如果不符合預期,你就要深入地去看,最終理解背后的原因。為什么一次激烈的cacheline同步大約是700ns?或是一次調度延時至少是3us,99%以內是20us?或是linux下的timed condition有60us的延時?或是一次上下文切換可以在200ns內做完?或是無競爭的mutex可以實現為兩條20ns左右wait-free的原子指令?掌握了這些知識,你才能抓大放小,把精力放在最關鍵的事情上,並把它做到世界上最好的水平。

 也推薦一下這個問題下面的其他回答。一看就知道是一直處在工程第一線的人寫出來的答案。

當一個框架得到較大規模的應用之后,沒有足夠的業務需求推動,往往自身缺乏前進的動力, 如果框架本身質量不是非常solid,開發者又換過一撥人之后,整體會更加保守。
但是brpc有一點在開始就做的非常好,能非常簡單的獲取系統的內部狀態,brpc提供了bvar和buiting service這類工具, 內部幾乎所有的環節都有相應的bvar, online profiling能非常輕松的分析熱點。 即使我們今天仍然沒法回答brpc理論極限在哪,也能非常方便的找出當前系統的瓶頸所在.

https://www.zhihu.com/question/65370268/answer/232090356

 因為前陣子剛好也在看我們內部的 某kit rpc框架,也仔細地研究了源碼以及內部相關的文檔,主要問題:
1. 基於protobuf2.3,所以比如像tensorflow這些用了新版本的庫就沒辦法整合進來;
2. 現網微服務之間都是通過rpc互聯,但是還有一些離線系統、docker環境里等等就不能直接訪問,需要自己再做一層http包裝;
3. 由於rpc服務都用的c++,沒有其他語言的client,再加上沒有http接口,因此基本上限制了線上的服務也只能用c++以及該rpc框架來寫;
4. 我們的rpc框架,很難做內存profile。沒有集成像tcmalloc、jemalloc這些,也沒有對應工具,之前試過用valgrind也是打印出太多信息,干擾性大;這些在定位內存泄漏時很麻煩;
5. rpc框架是個黑盒,內部狀態只能知道一些很粗的統計。比如我某次上線導致請求隊列滿,但是我無從得知,我知道總耗時上升了,不過也很難定位到是什么原因導致的,只能分析剛上線的代碼有沒問題;
雖然還沒試用過brpc,不過看了下文檔,以上的問題可能可以得到解決,這個后續再來對比一下。
總的來講,rpc框架說簡單也簡單,功能就是接受請求,處理完塞回去,性能雖然重要,但也不是最為重要的一點。說復雜也很復雜,這里作為業務應用的基礎,需要有相應的基礎監控、熔斷、負載均衡等支持;還要有方便定位問題的基礎能力。雖然現在一直在吐槽內部的框架,但是現在大部分bug也能根據經驗快速地定位出來,不過想起剛來那會的阻力,深感工具是否便利,是它能夠推動的非常重要原因之一。哪怕現在能比較快定位bug了,更多的是因為一些防御性編程的技巧,和框架倒是關系不大。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM