18 - 高性能模式:PPC與TPC

高性能架構(gòu)設(shè)計

高性能架構(gòu)設(shè)計主要集中在兩方面:

  • 盡量提升單服務(wù)器的性能,將單服務(wù)器的性能發(fā)揮到極致
  • 如果單服務(wù)器無法支撐性能,設(shè)計服務(wù)器集群方案
  • 最終系統(tǒng)能否實現(xiàn)高性能,還和具體的實現(xiàn)及編碼相關(guān)
  • 架構(gòu)設(shè)計是高性能的基礎(chǔ),如果架構(gòu)設(shè)計沒有做到高性能,則后面的具體實現(xiàn)和編碼能提升的空間是有限的
  • 單服務(wù)器高性能的關(guān)鍵之一就是服務(wù)器采取的并發(fā)模型,并發(fā)模型有如下兩個關(guān)鍵設(shè)計點(diǎn):
    • 服務(wù)器如何管理連接
    • 服務(wù)器如何處理請求
  • I/O 模型:阻塞、非阻塞、同步、異步
  • 進(jìn)程模型:單進(jìn)程、多進(jìn)程、多線程

PPC

  • PPC 是 Process Per Connection 的縮寫,其含義是指每次有新的連接就新建一個進(jìn)程去專門處理這個連接的請求,這是傳統(tǒng)的 UNIX 網(wǎng)絡(luò)服務(wù)器所采用的模型


    PPC流程圖
    • 父進(jìn)程接受連接(圖中 accept)
    • 父進(jìn)程“fork”子進(jìn)程(圖中 fork)
    • 子進(jìn)程處理連接的讀寫請求(圖中子進(jìn)程 read、業(yè)務(wù)處理、write)
    • 子進(jìn)程關(guān)閉連接(圖中子進(jìn)程中的 close)
  • PPC 模式實現(xiàn)簡單,比較適合服務(wù)器的連接數(shù)沒那么多的情況,例如數(shù)據(jù)庫服務(wù)器
  • 這種模式的弊端,主要體現(xiàn)在這幾個方面:
    1. fork 代價高:站在操作系統(tǒng)的角度,創(chuàng)建一個進(jìn)程的代價是很高的,需要分配很多內(nèi)核資源,需要將內(nèi)存映像從父進(jìn)程復(fù)制到子進(jìn)程。即使現(xiàn)在的操作系統(tǒng)在復(fù)制內(nèi)存映像時用到了 Copy on Write(寫時復(fù)制)技術(shù),總體來說創(chuàng)建進(jìn)程的代價還是很大的
    2. 父子進(jìn)程通信復(fù)雜:父進(jìn)程“fork”子進(jìn)程時,文件描述符可以通過內(nèi)存映像復(fù)制從父進(jìn)程傳到子進(jìn)程,但“fork”完成后,父子進(jìn)程通信就比較麻煩了,需要采用 IPC(Interprocess Communication)之類的進(jìn)程通信方案。例如,子進(jìn)程需要在 close 之前告訴父進(jìn)程自己處理了多少個請求以支撐父進(jìn)程進(jìn)行全局的統(tǒng)計,那么子進(jìn)程和父進(jìn)程必須采用 IPC 方案來傳遞信息
    3. 支持的并發(fā)連接數(shù)量有限:如果每個連接存活時間比較長,而且新的連接又源源不斷的進(jìn)來,則進(jìn)程數(shù)量會越來越多,操作系統(tǒng)進(jìn)程調(diào)度和切換的頻率也越來越高,系統(tǒng)的壓力也會越來越大。因此,一般情況下,PPC 方案能處理的并發(fā)連接數(shù)量最大也就幾百

Prefork

PPC 模式中,當(dāng)連接進(jìn)來時才 fork 新進(jìn)程來處理連接請求,由于 fork 進(jìn)程代價高,用戶訪問時可能感覺比較慢,prefork 模式的出現(xiàn)就是為了解決這個問題

  • prefork 就是提前創(chuàng)建進(jìn)程(pre-fork)。系統(tǒng)在啟動的時候就預(yù)先創(chuàng)建好進(jìn)程,然后才開始接受用戶的請求,當(dāng)有新的連接進(jìn)來的時候,就可以省去 fork 進(jìn)程的操作,讓用戶訪問更快、體驗更好


    prefork示意圖
  • prefork 的實現(xiàn)關(guān)鍵就是多個子進(jìn)程都 accept 同一個 socket,當(dāng)有新的連接進(jìn)入時,操作系統(tǒng)保證只有一個進(jìn)程能最后 accept 成功
  • 存在一個小小的問題:“驚群”現(xiàn)象,就是指雖然只有一個子進(jìn)程能 accept 成功,但所有阻塞在 accept 上的子進(jìn)程都會被喚醒,這樣就導(dǎo)致了不必要的進(jìn)程調(diào)度和上下文切換了
    • 操作系統(tǒng)可以解決這個問題,例如 Linux 2.6 版本后內(nèi)核已經(jīng)解決了 accept 驚群問題
  • prefork 模式和 PPC 一樣,還是存在父子進(jìn)程通信復(fù)雜、支持的并發(fā)連接數(shù)量有限的問題,因此目前實際應(yīng)用也不多
  • Apache 服務(wù)器提供了 MPM prefork 模式,推薦在需要可靠性或者與舊軟件兼容的站點(diǎn)時采用這種模式,默認(rèn)情況下最大支持 256 個并發(fā)連接

TPC

TPC 是 Thread Per Connection 的縮寫,其含義是指每次有新的連接就新建一個線程去專門處理這個連接的請求

  • 與進(jìn)程相比,線程更輕量級,創(chuàng)建線程的消耗比進(jìn)程要少得多
  • 多線程是共享進(jìn)程內(nèi)存空間的,線程通信相比進(jìn)程通信更簡單
  • TPC 實際上是解決或者弱化了 PPC fork 代價高的問題和父子進(jìn)程通信復(fù)雜的問題


    TPC基本流程圖
    • 父進(jìn)程接受連接(圖中 accept)
    • 父進(jìn)程創(chuàng)建子線程(圖中 pthread)
    • 子線程處理連接的讀寫請求(圖中子線程 read、業(yè)務(wù)處理、write)
    • 子線程關(guān)閉連接(圖中子線程中的 close)
    • 和 PPC 相比,主進(jìn)程不用“close”連接了。原因是在于子線程是共享主進(jìn)程的進(jìn)程空間的,連接的文件描述符并沒有被復(fù)制,因此只需要一次 close 即可
  • TPC 雖然解決了 fork 代價高和進(jìn)程通信復(fù)雜的問題,但是也引入了新的問題,具體表現(xiàn)在:
    • 創(chuàng)建線程雖然比創(chuàng)建進(jìn)程代價低,但并不是沒有代價,高并發(fā)時(例如每秒上萬連接)還是有性能問題
    • 無須進(jìn)程間通信,但是線程間的互斥和共享又引入了復(fù)雜度,可能一不小心就導(dǎo)致了死鎖問題
    • 多線程會出現(xiàn)互相影響的情況,某個線程出現(xiàn)異常時,可能導(dǎo)致整個進(jìn)程退出(例如內(nèi)存越界)
  • 除了引入了新的問題,TPC 還是存在 CPU 線程調(diào)度和切換代價的問題
  • TPC 方案本質(zhì)上和 PPC 方案基本類似,在并發(fā)幾百連接的場景下,反而更多地是采用 PPC 的方案,因為 PPC 方案不會有死鎖的風(fēng)險,也不會多進(jìn)程互相影響,穩(wěn)定性更高

Prethread

TPC 模式中,當(dāng)連接進(jìn)來時才創(chuàng)建新的線程來處理連接請求,雖然創(chuàng)建線程比創(chuàng)建進(jìn)程要更加輕量級,但還是有一定的代價,而 prethread 模式就是為了解決這個問題

  • 和 prefork 類似,prethread 模式會預(yù)先創(chuàng)建線程,然后才開始接受用戶的請求,當(dāng)有新的連接進(jìn)來的時候,就可以省去創(chuàng)建線程的操作,讓用戶感覺更快、體驗更好
  • 由于多線程之間數(shù)據(jù)共享和通信比較方便,因此實際上 prethread 的實現(xiàn)方式相比 prefork 要靈活一些,常見的實現(xiàn)方式有下面幾種:


    prethread示意圖
  • Apache 服務(wù)器的 MPM worker 模式本質(zhì)上就是一種 prethread 方案,但稍微做了改進(jìn)
  • Apache 服務(wù)器會首先創(chuàng)建多個進(jìn)程,每個進(jìn)程里面再創(chuàng)建多個線程,這樣做主要是為了考慮穩(wěn)定性
    • 即使某個子進(jìn)程里面的某個線程異常導(dǎo)致整個子進(jìn)程退出,還會有其他子進(jìn)程繼續(xù)提供服務(wù),不會導(dǎo)致整個服務(wù)器全部掛掉
  • prethread 理論上可以比 prefork 支持更多的并發(fā)連接,Apache 服務(wù)器 MPM worker 模式默認(rèn)支持 16 × 25 = 400 個并發(fā)處理線程

小結(jié)

本文講了傳統(tǒng)的單服務(wù)器高性能模式 PPC 與 TPC,希望對你有所幫助

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容