日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

魅族C++协程框架(Kiev)技术内幕

發布時間:2025/3/21 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 魅族C++协程框架(Kiev)技术内幕 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Kiev框架簡介

kiev是魅族科技推送平臺目前使用的Linux-C++后臺開發框架。從2012年立項起,先后由多位魅族資深架構師、資深C++工程師傾力打造,到本文寫就的時間為止,已經在推送平臺這個千萬用戶級的大型分布式系統上經歷了近5年的考驗。如今Kiev在魅族推送平臺中,每天為上百個服務完成數百億次RPC調用。

kiev作為一套完整的開發框架,是專為大型分布式系統后臺打造的C++開發框架,由以下幾個組件組成:

  • RPC框架(TCP/UDP)
  • FastCGI框架
  • redis客戶端(基于hiredis封裝)
  • mysql客戶端(基于mysqlclient封裝)
  • mongodb客戶端
  • 配置中心客戶端(Http協議, 基于curl實現)
  • 基于zookeeper的分布式組件(服務發現、負載均衡)
  • 日志模塊
  • 狀態監控模塊
  • 核心模塊是一個開源的`CSP并發模型`協程庫(libgo)

并發模型

Kiev采用了很先進的CSP開發模型的一個變種(golang就是這種模型),這一模型是繼承自libgo的。 選擇這種模型的主要原因是這種模型的開發效率遠高于異步回調模型,同時不需要在性能上做出任何妥協,在文中會對常見的幾種模型做詳細的對比。

CSP模型

CSP(Communicating Sequential Process)模型是一種目前非常流行的并發模型,golang語言所采用的并發模型就是CSP模型。 在CSP模型中,協程與協程間不直接通信,也不像Actor模型那樣直接向目標協程投遞信息,而是通過一個Channel來交換數據。


這樣設計的好處是通過Channel這個中間層減少協程間交互的耦合性,同時又保證了靈活性,非常適合開發并發程序。

RPC框架

RPC(Remote Procedure Call)是一種遠程調用協議,簡單地說就是能使應用像調用本地方法一樣的調用遠程的過程或服務,可以應用在分布式服務、分布式計算、遠程服務調用等許多場景。說起 RPC 大家并不陌生,業界有很多開源的優秀 RPC 框架,例如 Dubbo、Thrift、gRPC、Hprose 等等。 RPC框架的出現是為了簡化后臺內部各服務間的網絡通訊,讓開發人員可以專注于業務邏輯,而不必與復雜的網絡通訊打交道。 在我們看來,RPC框架絕不僅僅是封裝一下網絡通訊就可以了的,要想應對數以百計的不同服務、數千萬用戶、百億級PV的業務量挑戰,RPC框架還必須在高可用、負載均衡、過載保護、通信協議向后兼容、優雅降級、超時處理、無序啟動幾個維度都做到足夠完善才行。

服務發現

Kiev使用zookeeper做服務發現,每個kiev服務開放時會在zookeeper上注冊一個節點,包含地址和協議信息。水平擴展時,同質化服務會注冊到同一個路徑下,產生多個節點。 依賴的服務調用時,從zookeeper上查詢當前有哪些節點可以使用,依照負載均衡的策略擇一連接并調用。

負載均衡

內置兩種負載均衡策略:robin和conhash,并且根據實際業務場景可以定制。

過載保護

Kiev內置了一個過載保護隊列,分為10個優先級。每個請求到達時先進入過載保護隊列,而后由工作協程(work-coroutine)取出請求進行處理。 如果工作協程的處理速度低于請求到達的速度,過載保護隊列就會堆積、甚至堆積滿。 當過載保護隊列堆滿時,新請求到達后會在隊列中刪除一個更低優先級的請求,騰出一個空位,塞入新請求。 同時,隊列中的請求也是有時效性的,過長時間未能被處理的請求會被丟棄掉,以此避免處理已超時的請求。 這種機制保證了當系統過載時盡量將有限的資源提供給關鍵業務使用。

通信協議向后兼容

由于微服務架構經常需要部分發布,所以選擇一個支持向后兼容的通信協議是很必要的一個特性。 Kiev選取protobuf作為通信協議。

與第三方庫協同工作

最早期的Kiev是基于異步回調模型的,但是很多第三方庫只提供了同步模型的版本,很難搭配使用。 當前的Kiev是CSP并發模型,配合libgo提供的Hook機制,可以將同步模型的第三方庫中阻塞等待的CPU時間充分利用起來執行其他邏輯,自動轉化成了CSP并發模型;異步回調模型的第三方庫也可以使用CSP模型中的Channel來等待回調觸發;從而完美地與第三方庫協同工作。

kiev功能組件結構圖


Kiev發展史與技術選型

2012年,魅族的推送業務剛剛有一點從傳統架構向微服務架構轉型的意識萌芽,為了在拆分系統的同時提高開發效率,我們決定做一個C++開發框架,這就是最早期Kiev的由來.

第一個版本的Kiev使用了多線程同步模型,業務邏輯順序編寫,非常簡單。 但是由于os對線程數的支持有限,隨著線程數量的增長,調度消耗的增長是非線性的,因此不能支持過高的請求并發。

隨著用戶量的增長,我們需要支持更高的并發請求,由于當年協程還不像現在這樣流行,所以我們決定使用異步回調模型編寫Kiev。早期的業務形態非常簡單,使用異步回調模型也勉強可以應付開發任務。

在其后幾年中,我們使用異步回調模型的Kiev開發了大量的服務,在使用中我們慢慢發現邏輯碎片化的問題越來越多,更可怕的是,有些時候長長的回調鏈還要和有限狀態機糾纏在一起,代碼越來越難以維護。常常出現類似于下面這樣的代碼片段:


針對這樣的問題,我們引入了騰訊開源的協程庫libco,在協程中執行同步的代碼邏輯;同時使用Hook技術,將阻塞式IO請求中等待的時間片利用起來,切換cpu執行其他協程,等到IO事件觸發再切換回來繼續執行邏輯。類似于上述的碎片化代碼就變成了連續性的業務邏輯,也不再需要手動維護上下文數據,臨時數據直接置于棧上即可,代碼變成如下的樣子:



然而,libco僅僅提供了協程和HOOK兩個功能,協程切換需要我們自己做,為了實現簡單,RPC框架進化成了連接池的模式,每次發起RPC調用時從連接池中取一條連接來發送請求,等待回復,然后釋放回連接池。 每條連接同一時刻只能跑一個請求,rpc協議退化成了半雙工模式。此時為保證性能,不得不在每兩個有依賴關系的服務之間建立數以百計的TCP連接,這樣在依賴了水平擴展為很多進程的服務上,就會與這些進程分別建立數百連接,TCP連接高達數千,甚至上萬,對服務器造成了很大的壓力。連接請求如下圖所示,其中每條連接線都代表數以百計的TCP連接。


相應地,我們也更新了kiev中的redis、mysql、fastcgi模塊,都改為了協程模型的。

在最初的幾個月中,這種方式很好地幫我們提升了開發效率,同時也有著還算不錯的性能(Rpc請求差不多有20K左右的QPS)。隨著時間的流逝,我們的用戶越來越多,請求量也越來越大,終于在某次新品發布后,我們的一個非關鍵性業務出現了故障。

出現故障的這個業務是一個接受手機端訂閱請求的業務,手機端在訂閱請求超時后(大概30s),會重新嘗試發起請求。由于當時系統過載,處理速度慢于請求速度,大量請求積壓在隊列中,隨著時間的推移,服務處理請求的響應速度越來越慢,最終導致很多請求還沒處理完手機端就認為超時了,重新發起了第二次請求,形成雪崩效應。當時緊急增加了一些服務器,恢復了故障,事后總結下來發現,事件的主因還是因為我們沒有做好過載保護機制。于是我們決定在Kiev中內置過載保護功能,增加一個分為10個優先級的過載保護隊列。每個請求到達時先進入過載保護隊列,而后由工作協程(work-coroutine)取出請求進行處理。當過載保護隊列堆滿時,隊列中刪除一個最低優先級的請求,騰出一個空位。同時,隊列中的請求也是有時效性的,過長時間未能被處理的請求會被丟棄掉,以此避免處理已超時的請求。如下圖所示:


隨著機器越來越多,以及后續出現了一些超長鏈路請求的業務形態(這里解釋一下長鏈路請求的問題,長鏈路請求是指一個請求要流經很多服務處理,在處理流程中,前面的服務一定要等到后面的服務全部處理完成或超時,才會釋放其占用的TCP連接,這樣的模式會極大地影響整個系統的請求并發數),TCP連接數方面的壓力越來越大,最終不得不考慮改為單連接上使用全雙工模式。然而當時使用的libco功能過于簡單,很難基于此開發全雙工模式的RPC框架,恰好當時有一位同事在github上做了一個叫libgo的開源項目,是一個和golang語言一樣的CSP并發模型的協程庫,于是我們做了一段時間的技術預研,看看能否替換掉現有的libco. 下面的表格是兩個項目在我們比較關心的一些維度上的對比:


通過調研,最終我們決定使用libgo替換掉libco。

基于CSP模型實現全雙工通信RPC非常容易,客戶端只需在每個request發出后保存id和channel并阻塞地等待相應的channel,收到response時根據id找到對應的channel并寫入數據即可。這樣只需一條TCP連接,就可以并發無數個request,分布式水平擴展帶來的TCP連接管理方面的壓力就不再是問題了。同時由于每次RPC所需的資源更少,性能也有了很大提升,Rpc請求的QPS輕松提升到了100K以上。這一性能指標目前已經超越了絕大多數開源的RPC框架。

與流行開源框架對比

總結

以上是生活随笔為你收集整理的魅族C++协程框架(Kiev)技术内幕的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。