溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

libco是怎樣支撐巨大數(shù)據(jù)信息量的

發(fā)布時間:2021-01-27 09:26:38 來源:億速云 閱讀:181 作者:小新 欄目:移動開發(fā)

這篇文章給大家分享的是有關libco是怎樣支撐巨大數(shù)據(jù)信息量的的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

ibco是微信后臺大規(guī)模使用的c/c++協(xié)程庫,2013年至今穩(wěn)定運行在微信后臺的數(shù)萬臺機器上。libco在2013年的時候作為騰訊六大開源項目首次開源,我們最近做了一次較大的更新,同步更新在github.com/tencent/libco 上。libco支持后臺敏捷的同步風格編程模式,同時提供系統(tǒng)的高并發(fā)能力。

  libco支持的特性

  無需侵入業(yè)務邏輯,把多進程、多線程服務改造成協(xié)程服務,并發(fā)能力得到百倍提升;

  支持CGI框架,輕松構建web服務(New);

  支持gethostbyname、mysqlclient、ssl等常用第三庫(New);

  可選的共享棧模式,單機輕松接入千萬連接(New);

  完善簡潔的協(xié)程編程接口

  – 類pthread接口設計,通過co_create、co_resume等簡單清晰接口即可完成協(xié)程的創(chuàng)建與恢復; – 類thread的協(xié)程私有變量、協(xié)程間通信的協(xié)程信號量co_signal (New); – 非語言級別的lambda實現(xiàn),結合協(xié)程原地編寫并執(zhí)行后臺異步任務 (New); – 基于epoll/kqueue實現(xiàn)的小而輕的網(wǎng)絡框架,基于時間輪盤實現(xiàn)的高性能定時器;

  libco產(chǎn)生的背景

  早期微信后臺因為業(yè)務需求復雜多變、產(chǎn)品要求快速迭代等需求,大部分模塊都采用了半同步半異步模型。接入層為異步模型,業(yè)務邏輯層則是同步的多進程或多線程模型,業(yè)務邏輯的并發(fā)能力只有幾十到幾百。隨著微信業(yè)務的增長,系統(tǒng)規(guī)模變得越來越龐大,每個模塊很容易受到后端服務/網(wǎng)絡抖動的影響。

  異步化改造的選擇

  為了提升微信后臺的并發(fā)能力,一般的做法是把現(xiàn)網(wǎng)的所有服務改成異步模型。這種做法工程量巨大,從框架到業(yè)務邏輯代碼均需要做一次徹底的改造,耗時耗力而且風險巨大。于是我們開始考慮使用協(xié)程。

  但使用協(xié)程會面臨以下挑戰(zhàn):

  業(yè)界協(xié)程在c/c++環(huán)境下沒有大規(guī)模應用的經(jīng)驗;

  如何控制協(xié)程調(diào)度;

  如何處理同步風格的API調(diào)用,如Socket、mysqlclient等;

  如何處理已有全局變量、線程私有變量的使用;

  最終我們通過libco解決了上述的所有問題,實現(xiàn)了對業(yè)務邏輯非侵入的異步化改造。我們使用libco對微信后臺上百個模塊進行了協(xié)程異步化改造,改造過程中業(yè)務邏輯代碼基本無修改。至今,微信后臺絕大部分服務都已是多進程或多線程協(xié)程模型,并發(fā)能力相比之前有了質的提升,而libco也成為了微信后臺框架的基石。

  libco框架

  libco在框架分為三層,分別是接口層、系統(tǒng)函數(shù)Hook層以及事件驅動層。

libco是怎樣支撐巨大數(shù)據(jù)信息量的


  同步風格API的處理

  對于同步風格的API,主要是同步的網(wǎng)絡調(diào)用,libco的首要任務是消除這些等待對資源的占用,提高系統(tǒng)的并發(fā)性能。一個常規(guī)的網(wǎng)絡后臺服務,我們可能會經(jīng)歷connect、write、read等步驟,完成一次完整的網(wǎng)絡交互。當同步的調(diào)用這些API的時候,整個線程會因為等待網(wǎng)絡交互而掛起。

  雖然同步編程風格的并發(fā)性能并不好,但是它具有代碼邏輯清晰、易于編寫的優(yōu)點,并可支持業(yè)務快速迭代敏捷開發(fā)。為了繼續(xù)保持同步編程的優(yōu)點,并且不需修改線上已有的業(yè)務邏輯代碼,libco創(chuàng)新地接管了網(wǎng)絡調(diào)用接口(Hook),把協(xié)程的讓出與恢復作為異步網(wǎng)絡IO中的一次事件注冊與回調(diào)。當業(yè)務處理遇到同步網(wǎng)絡請求的時候,libco層會把本次網(wǎng)絡請求注冊為異步事件,本協(xié)程讓出CPU占用,CPU交給其它協(xié)程執(zhí)行。libco會在網(wǎng)絡事件發(fā)生或者超時的時候,自動的恢復協(xié)程執(zhí)行。

  大部分同步風格的API我們都通過Hook的方法來接管了,libco會在恰當?shù)臅r機調(diào)度協(xié)程恢復執(zhí)行。

  千萬級協(xié)程支持
  libco默認是每一個協(xié)程獨享一個運行棧,在協(xié)程創(chuàng)建的時候,從堆內(nèi)存分配一個固定大小的內(nèi)存作為該協(xié)程的運行棧。如果我們用一個協(xié)程處理前端的一個接入連接,那對于一個海量接入服務來說,我們的服務的并發(fā)上限就很容易受限于內(nèi)存。為此,libco也提供了stackless的協(xié)程共享棧模式,可以設置若干個協(xié)程共享同一個運行棧。同一個共享棧下的協(xié)程間切換的時候,需要把當前的運行棧內(nèi)容拷貝到協(xié)程的私有內(nèi)存中。為了減少這種內(nèi)存拷貝次數(shù),共享棧的內(nèi)存拷貝只發(fā)生在不同協(xié)程間的切換。當共享棧的占用者一直沒有改變的時候,則不需要拷貝運行棧。

  libco協(xié)程的共享協(xié)程棧模式使得單機很容易接入千萬連接,只需創(chuàng)建足夠多的協(xié)程即可。我們通過libco共享棧模式創(chuàng)建1千萬的協(xié)程(E5-2670 v3 @ 2.30GHz * 2, 128G內(nèi)存),每10萬個協(xié)程共享的使用128k內(nèi)存,整個穩(wěn)定echo服務的時候總內(nèi)存消耗大概為66G。
  協(xié)程私有變量
  多進程程序改造為多線程程序時候,我們可以用thread來對全局變量進行快速修改,而在協(xié)程環(huán)境下,我們創(chuàng)造了協(xié)程變量ROUTINE_VAR,極大簡化了協(xié)程的改造工作量。
  因為協(xié)程實質上是線程內(nèi)串行執(zhí)行的,所以當我們定義了一個線程私有變量的時候,可能會有重入的問題。比如我們定義了一個thread的線程私有變量,原本是希望每一個執(zhí)行邏輯獨享這個變量的。但當我們的執(zhí)行環(huán)境遷移到協(xié)程了之后,同一個線程私有變量,可能會有多個協(xié)程會操作它,這就導致了變量沖入的問題。為此,我們在做libco異步化改造的時候,把大部分的線程私有變量改成了協(xié)程級私有變量。協(xié)程私有變量具有這樣的特性:當代碼運行在多線程非協(xié)程環(huán)境下時,該變量是線程私有的;當代碼運行在協(xié)程環(huán)境的時候,此變量是協(xié)程私有的。底層的協(xié)程私有變量會自動完成運行環(huán)境的判斷并正確返回所需的值。
  協(xié)程私有變量對于現(xiàn)有環(huán)境同步到異步化改造起了舉足輕重的作用,同時我們定義了一個非常簡單方便的方法定義協(xié)程私有變量,簡單到只需一行聲明代碼即可。
  gethostbyname的Hook方法
  對于現(xiàn)網(wǎng)服務,有可能需要通過系統(tǒng)的gethostbyname API接口去查詢DNS獲取真實地址。我們在協(xié)程化改造的時候,發(fā)現(xiàn)我們hook的socket族函數(shù)對gethostbyname不適用,當一個協(xié)程調(diào)用了gethostbyname時會同步等待結果,這就導致了同線程內(nèi)的其它協(xié)程被延時執(zhí)行。我們對glibc的gethostbyname源碼進行了研究,發(fā)現(xiàn)hook不生效主要是由于glibc內(nèi)部是定義了poll方法來等待事件,而不是通用的poll方法;同時glibc還定義了一個線程私有變量,不同協(xié)程的切換可能會重入導致數(shù)據(jù)不準確。最終gethostbyname協(xié)程異步化是通過Hook poll方法以及定義協(xié)程私有變量解決的。
  gethostbyname是glibc提供的同步查詢dns接口,業(yè)界還有很多優(yōu)秀的gethostbyname的異步化解決方案,但是這些實現(xiàn)都需要引入一個第三方庫并且要求底層提供異步回調(diào)通知機制。libco通過hook方法,在不修改glibc源碼的前提下實現(xiàn)了的gethostbyname的異步化。
  協(xié)程信號量
  在多線程環(huán)境下,我們會有線程間同步的需求,比如一個線程的執(zhí)行需要等待另一個線程的信號,對于這種需求,我們通常是使用pthread_signal 來解決的。在libco中,我們定義了協(xié)程信號量co_signal用于處理協(xié)程間的并發(fā)需求,一個協(xié)程可以通過co_cond_signal與co_cond_broadcast來決定通知一個等待的協(xié)程或者喚醒所有等待協(xié)程。
  總結
  libco是一個高效的c/c++協(xié)程庫,提供了完善的協(xié)程編程接口、常用的Socket族函數(shù)Hook等,使得業(yè)務可用同步編程模型快速迭代開發(fā)。隨著幾年來的穩(wěn)定運行,libco作為微信后臺框架的基石發(fā)揮了舉足輕重的作用。

感謝各位的閱讀!關于“l(fā)ibco是怎樣支撐巨大數(shù)據(jù)信息量的”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI