[譯]多線程網絡服務模型

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

多線程網絡服務模型

/*** 謹獻給Yoyo** 原文出處:https://www.toptal.com/software/guide-to-multi-processing-network-server-models* @author dogstar.huang <chanzonghuang@gmail.com> 2016-04-02*/

作為多年來一直在編寫高性能網絡代碼的人(我的博士論文主題是適配多核系統分布式應用的高速緩存服務),現在我看到了很多完全不知道或忽略討論網絡服務模型基本原理的教程。因此,本文旨在希望能為大家提供有用的概覽以及網絡服務模型的比較,以揭開編寫高性能網絡代碼的神秘面紗。

本文主要針對“系統程序員”,即與他們的應用程序的底層細節工作、實現網絡服務代碼的后端開發。這通常是在C++或C來完成,雖然時下大部分現代語言和框架通過各種級別的效率提供了體面的底層功能。

既然通過增加內核更容易擴展CPU,我會把這作為常識,而本質卻是調整軟件以便最大化使用這些內核。因此,問題就變成如何在能在多個CPU上并行執行的線程(或進程)中分區軟件。

我也將理所當然地認為讀者意識到,“并發”基本上意味著“多任務處理”,即一些代碼實例(無論是相同或不同的代碼,這并不重要),在同一時間是活躍的。并發可以在單個CPU上實現,并且通常前現代時期是這樣的。具體地,并發可以通過在單個CPU上的多個進程或線程之間快速切換來實現。這是老式的、單CPU系統如何管理在同一時間運行眾多應用程序的方式,在某種程度上,用戶會覺得應用程序是在同時執行,盡管實際上并沒有。另一方面,平行度,從字面上看具體意味著代碼通過多個CPU或CPU內核在同一時間執行。

分區應用程序(到多個進程或線程)

出于這個討論的目的,假如我們談論線程或全過程,它基本上是不相關的。現代操作系統(而Windows顯然是個例外)把進程看待像線程一樣輕量級(或在某些情況下,反之亦然,線程都獲得了功能,這使得它們像進程一樣重量級)。如今,進程和線程之間的主要區別是在跨進程或跨線程通信和數據共享的功能。其中,進程和線程之間的區別是很重要的,我會進行適當的備注,否則,在這些部分可以安全地考慮“線程”和“過程”是可以互換的。

通用網絡應用任務與網絡服務模型

這篇文章具體處理網絡服務代碼,這部分需要實現以下三個任務:

  • 任務#1:建立(和拆除)的網絡連接
  • 任務#2:網絡通信(IO)
  • 任務#3:有用的工作;例如負載或者應用程序為什么存在的原因

關于跨進程分區分區這三個任務,這里有幾個普遍的網絡服務模型,即:

  • MP:多進程
  • SPED:單進程,事件驅動
  • SEDA:分階段的事件驅動架構
  • AMPED:非對稱多進程事件驅動
  • SYMPED:對稱多處理事件驅動

這些都是在學術界使用的網絡服務模型的名字,我記得“在野外”的同義詞發現至少其中的一些。(名字本身,當然,并不是那么重要的 -- 真正的價值是如何洞悉代碼是怎么回事。)

這些網絡服務模型,每一個都會在下面的部分中進一步說明。

多進程(MP)模型

MP的網絡服務模型是每個人都會首選用來學習的一個,特別是學習多線程的時候。在MP模型中,有一個“master”進程,接收連接(任務#1)。一旦建立了連接,主進程創建一個新的進程,并把連接的socket傳給它,所以一個進程一個連接。這個新的進程然后通常和此連接以簡單、連續、鎖步的方式工作:進程從連接中讀取一些東西(任務#2),然后做一些計算(任務#3),然后寫一些東西給它(再次 任務#2)。

模型MP是很容易實現的,而且實際工作極為出色只要進程總數維持很低很低。有多低?答案取決于任務#2和任務#3蘊含了什么。經驗法則,可以說進程數或線程數不應超過CPU內核的兩倍。一旦有在同一時間激活太多進程,操作系統則趨于花費了太多在于時間抖動(即,圍繞可用的CPU內核上平衡進程或線程)和這樣的應用通常最終花費幾乎所有的CPU的一次在“SYS”(或內核)代碼,實際上卻做了一點點真正有用的工作。

優點:實現很簡單,只要連接數很少可以工作得非常好。

缺點:如果進程數增長太大則趨于使得操作系統過載過重,并且可能會有延遲抖動網絡IO等待,直到有效載荷(計算)階段結束。

單進程事件驅動(SPED)模型

該SPED網絡服務器模型,因最近一些高調的網絡服務應用程序,如Nginx而出名。基本上,它在同一個進程做了這三項任務,在它們之間之間復用。為了提高效率,它需要像epoll和kqueue的一些相當先進的核心功能。在這種模型下,代碼是由傳入的連接和數據“事件”驅動,并且實現了一個看起來像這樣的“事件循環”:

  • 問操作系統是否有任何新的網絡“事件”(如新的連接或輸入數據)
  • 如果有新的可用連接,建立他們(任務#1)
  • 如果有可用的數據,讀取它(任務#2)并對它采取行動(任務3#)
  • 重復,直到服務器退出

所有這一切都在一個單一的進程中完成,并且可以非常有效地完成,因為它完全避免了進程之間的上下文切換,這通常會造成MP模型嚴重的性能問題。這里唯一的上下文切換來自系統調用,而這些又通過僅作用于有某些事件綁定的具體連接而使得切換最小化。該模型可以同時處理數萬的連接,只要有效載荷工作(任務#3)不是太復雜或是資源密集型的。

盡管這種方式有兩大缺點:

  • 1、由于三個任務都在一個單一的循環迭代中順序進行,有效載荷工作(任務#3)和所有東西都是同步完成的,也就是說,如果它需要很長的時間來計算到由客戶端接收的數據的響應,當正在做這點時其他東西都會停止,而這會在延遲中引入潛在的巨大波動。

  • 2、只使用一個CPU內核。這樣再次是有好處,絕對限制了來自操作系統要求的上下文切換數量,從而提高了整體性能,但有明顯的不足就是其他任何可用的CPU內核都無事可做。

這是對于需要更先進的模型的理由。

優點:可以是具有高性能,在操作系統易于實現(即,需要最少量的OS干預)。只需要一個CPU內核。

缺點:僅利用單個CPU(不管可用的數量)。如果有效載荷工作不統一,會導致非均勻的響應延遲。

分階段的事件驅動架構(SEDA)模型

該SEDA網絡服務模型有點復雜。它把復雜的,事件驅動的應用程序分解到一組由隊列連接的階段。盡管如果不仔細實現,它的性能會跟MP情況中同一問題而受到影響。它的工作原理是這樣的:

  • 有效載荷工作(任務#3)會盡可能地分成多個階段,或模塊。每個模塊實現了駐留在其自己單獨的進程中單個特定功能(可認為是“微服務”或“微內核”),并且這些模塊經由消息隊列相互通信。此架構可以表示為節點圖,其中節點是進程,邊是消息隊列。

  • 一個單一進程執行任務#1(通常遵循SPED模型),它將新連接交付于特定的條目點節點。這些節點可以是傳遞數據給其他節點進行計算,或者也可以是實現有效載荷處理(任務3#)的純網絡節點(任務#2)。通常沒有“master”進程(例如,一個收集并聚集響應,并將其通過連接發送返回),因為每一個節點都可以通過自身進行響應。

理論上,這種模式可以是任意復雜的,因為節點圖可能具有循環,連接到其他類似的應用程序,或是連接到實際上是在遠程系統上執行的節點。但在實踐中,即使有定義良好的消息和高效的隊列,它會變得笨拙難以思考,并且把系統的行為作為一個整體來推理。相比于SPED的模式,來往傳遞的消息可能會破壞該模型的性能,如果每個節點的工作都是很簡短的話。該模型的效率顯然比SPED模型的要低,所以它通常采用在有效載荷的工作復雜且耗時的情況。

優點:軟件架構師最終的夢想:一切都分割成整齊而又獨立的模塊。

缺點:復雜度隨模塊數量而爆炸,并且消息隊列仍然比直接內存共享慢得多。

非對稱多進程事件驅動(AMPED)模型

該AMPED網絡服務是SEDA馴服的,更易于模型的一個版本。沒有過多不同的模塊和進程,也沒有多過的消息隊列。下面是它如何工作的:

  • 以SPED風格在一個單一的“master”進程中實現任務#1和任務#2。這是網絡IO的唯一進程。
  • 在一個單獨的“worker”進程中實現任務#3(可能在多個實例中啟動),通過一個隊列連接到主進程(每個進程一個隊列)。
  • 當“master”進程接收到數據,找到一個沒有被充分利用(或空閑)的工作進程,并把數據傳遞給它的消息隊列。當響應準備好時主進程由該進程發起消息通知,此時它通過連接傳遞響應。

這里最重要的是,有效負載工作是在一個固定的(通常配置的)數量的進程中進行,這獨立于連接的數量。這樣的好處是,有效負載可以是任意復雜,并且也不會影響網絡IO(這是很好的等待時間)。而且還可能帶來更高的安全性,因為只有一個進程在做網絡IO。

優點:網絡IO和有效載荷的工作分離非常清晰。

缺點:為在進程之間來回傳遞數據利用消息隊列,而這根據不同協議的性質,可能成為瓶頸。

對稱多處理事件驅動(SYMPED)模型

該SYMPED網絡服務模型在許多方面是網絡服務模型的“圣杯”,因為它就像有獨立SPED“worker”進程的多個實例。它是通過由單一進程循環接收連接,然后將它們傳遞到工作進程得以實現,每一個都有一個像SPED的事件循環。這有一些非常有利的后果:

  • CPU都為生成的進程的準確數量而加載,這在每個時間點要么做網絡IO或有效載荷處理。沒有辦法進一步提升CPU利用率。
  • 如果連接是獨立的(例如使用HTTP),在工作進程之間則沒有間通信。

事實上,這一點,也是最新版Nginx在做的;它們生產出少量工作進程,每個運行一個事件循環。為了使事情變得更好,大多數操作系統都提供了一個可由多個進程在一個獨立的TCP端口偵聽傳入連接的功能,省去了為某個特定進程決定與網絡連接工作的需要。如果你正在使用的應用程序可以通過這種方式來實現,我建議這樣做。

優點:通過像SPED那樣循環可控制的數量,嚴格提高CPU使用率天花板。

缺點:由于每個過程有一個像SPED那樣的循環,如果有效載荷工作是不均勻的,等待時間可以再次變化,就像與正常SPED模型那樣。

一些低級技巧

除了為您的應用選擇最佳的構架模型外,這里還有可用于進一步提高網絡代碼性能的一些低級招數。下面簡短列出了一些更有效的技巧:

  • 1、避免動態內存分配。作為一個解釋,簡單地看流行的內存分配代碼 - 他們使用復雜的數據結構,互斥,并其中只是簡單地這么多的代碼(例如,jemalloc大概是450KiB左右的C代碼!)。上面大部分的模型可用完全靜態的(或預先分配)網絡和/或僅在需要的地方改變線程之間所有權緩沖器來實現。

  • 2、使用操作系統可以提供最大值。大多數操作系統允許多個進程監聽一個單一socket,并在套接字直到接收到第一個字節(或甚至是第一個完整的請求!)時連接將不被接受時那里實現功能收到。如果可以請使用sendfile()。

  • 3、了解您正在使用的網絡協議!例如,禁用Nagle算法通常是有意義的,并且如果(再)連接率高禁止持續是有意義的。學習TCP擁塞控制算法,看看它是否有意義去嘗試較一個新的。

在未來的博客文章,我可以更多地談論這些,以及其他技術和實用的技巧。但現在,這里希望能為編寫高性能網絡代碼提供關于的架構選擇一個有用的信息基礎,和它們的相對優勢和劣勢。


------------------------

  • 知識共享許可協議本作品采用知識共享署名-非商業性使用-相同方式共享 3.0 未本地化版本許可協議進行許可。
  • 本文翻譯作者為:dogstar,發表于艾翻譯(itran.cc);歡迎轉載,但請注明出處,謝謝!

轉載于:https://my.oschina.net/dogstar/blog/759120

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/260313.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/260313.shtml
英文地址,請注明出處:http://en.pswp.cn/news/260313.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

likely(x)與unlikely(x)函數,即__builtin_expect的使用

轉載自&#xff1a;http://velep.com/archives/795.html 本文講的likely()和unlikely()兩個宏&#xff0c;在linux內核代碼和一些應用中可常見到它們的身影。實質上&#xff0c;這兩個宏是關于GCC編譯器內置宏__builtin_expect的使用。顧名思義&#xff0c;likely()指“很有可能…

java mvc引擎_SpringMvc+JavaConfig+Idea 搭建項目

1.介紹之前搭建SpringMvc項目要配置一系列的配置文件&#xff0c;比如web.xml,applicationContext.xml,dispatcher.xml。Spring 3.X之后推出了基于JavaConfig方式以及注解的形式的配置。在一定程度上簡化了Spring項目的配置。近幾年特別火的SpringBoot&#xff0c;大大的簡化了…

window.parent和window.opener區別

下面一段代碼是關于window.parent和window.opener區別 來講的&#xff0c;我們如果要用到iframe的值傳到另一框架就要用到window.opener.document.getElementById(name).value uvalue;這種形式哦。 window.parent能獲取一個框架的父窗口或父框架。頂層窗口的parent引用的是它本…

極域電子書包課堂管理系統_【君蓮微訊】君蓮學校(小學部)開展電子書包第13共同體數學研討活動...

借 助 媒 體 技 術豐 富 圖 形 認 識君蓮學校(小學部)開展電子書包共同體 數學研討活動 2020年12月2日下午&#xff0c;君蓮學校(小學部)開展了以“借助媒體技術 豐富圖形認識”為主題的閔行區電子書包第13共同體的數學研討活動。共同體學校教師代表、學校電子書包項目組主管朱…

python批量改動指定文件夾文件名稱

這小樣例僅僅要是說明用python怎么批量改動指定文件夾的文件名稱&#xff1a; 記得要把腳本跟改動的文件放在同一個文件夾下 #encoding:utf-8 import os import sys files os.listdir(D:\\1) #路徑能夠自己for name in files:a os.path.splitext(name)if a[1] .txt: #txt能夠…

Linux vmstat命令實戰詳解

vmstat命令是最常見的Linux/Unix監控工具&#xff0c;可以展現給定時間間隔的服務器的狀態值,包括服務器的CPU使用率&#xff0c;內存使用&#xff0c;虛擬內存交換情況,IO讀寫情況。這個命令是我查看Linux/Unix最喜愛的命令&#xff0c;一個是Linux/Unix都支持&#xff0c;二是…

python的基礎網絡編程是下列_Python入門基礎之網絡編程、socket編程、TCP、UDP編程...

忙了兩天&#xff0c;繼續更文&#xff01;希望多多支持。套接字套接字是一種具有之前所說的"通訊端點"概念的計算機網絡數據結構。網絡化的應用程序在開始任何通訊之前都必需要創建套接字。套接字有三種&#xff1a;1、 AF_UNIX(在 POSIX1.g 標準中也叫 AF_LOCAL)&a…

java 入門 博客園_javaweb入門

復習&#xff1a;css的常用樣式&#xff1a;borderbackgroundpaddingmarginfloatposition 定位top left確定div在頁面中的位置&#xff0c;這兩個值可以為負數。cssdiv 布局方式cssdivtable 先由div劃分大塊兒&#xff0c;再由table進行整齊布局。下拉列表&#xff1a;層疊的布…

以ThreadStart方式實現多線程

3.1 使用ThreadStart委托 這里先以一個例子體現一下多線程帶來的好處&#xff0c;首先在Message類中建立一個方法ShowMessage()&#xff0c;里面顯示了當前運行線程的Id&#xff0c;并使用Thread.Sleep&#xff08;int ) 方法模擬部分工作。在main()中通過ThreadStart委托綁定M…

管理思考

管理基礎 分活 分錢 分責任 分權 安人(安排 配置) 流程 標準 考核 治人(協調 指揮 控制) 社會越來越復雜 分工越來越復雜 合作越來越重要 目標一定要一致共同的意愿共識 需要大家參與管理 業務劃分 責任劃分 流程梳理 如何合作做好安全工作 安全服務因為不承擔責任 責任主體是管…

我的atom插件

atom插件實在是太多了&#xff0c;下面就說說我的插件 1.minimap 右邊的小地圖&#xff0c;和sublime里面的差不多&#xff1b; 2.open-in-browser 右擊默認瀏覽器打開&#xff1b; 3.emmet 這個不用多說吧&#xff0c;html快速編譯 4.git-plus 直接在atom提交代碼&#xff0…

python統計英文句子每個單詞字數_Python小書3-文本英文單詞統計

之前寫Python Web小書第三小節本來用的垃圾郵件的案例三郎&#xff1a;Python貝葉斯推理垃圾郵件分類?zhuanlan.zhihu.com后來發現里面的東西&#xff0c;涉及到概率&#xff0c;程序太復雜了。。。哈哈哈所以就想著&#xff0c;哪天重寫一下&#xff0c;選來選去&#xff0c;…

java9特性_96.java基礎10(java9/10/11新特性)

126.java 9 新特性1(模塊化功能):1.java模塊化2.java 交互式環境jshell3.泛型package com.atguigu.java;import org.junit.Test;import java.io.IOException;import java.io.InputStreamReader;import java.net.MalformedURLException;import java.net.URL;import java.util.Ar…

MonoRail - 簡介 [基礎知識篇]

MonoRail - 簡介 起源 MonoRail是一個.NET的MVC web開發框架, 原名Castle On Rails, 是CastleProject的一個子項目. 作者hammett在使用過Ruby On Rails后, 覺得非常棒, 他希望在享受ror的開發模式的同時能使用大量現有的資源, 于是就用.NET寫出了一個Castle On Rails. 后來ror那…

結對編程(黃金點游戲)

我扮演的角色是駕駛員 一、結對伙伴 領航員&#xff1a;趙峻 作業地址見我的博客。 二、代碼地址 https://coding.net/u/k2048/p/huangjindian/git/blob/master/main.c 三、總結 1、個人總結 本次作業我扮演駕駛員&#xff0c;趙峻扮演領航員&#xff0c;我負責算法實現以及代碼…

qtgl 鼠標平移 c++_羅技真愛粉的MX Master 3無線鼠標體驗

?這是一篇關于羅技MX Master3的曬單&#xff0c;順帶也翻出我的庫存清潔整理一下吧。在決定購買一款新鼠標的時候&#xff0c;我的第一目標其實是MX Vertical垂直鼠標&#xff0c;不過MX Vertical目前優勢只在外形上&#xff0c;在MX系列中明顯屬于低配&#xff0c;自由滾輪、…

java實驗指導書(實驗四)答案_java程序設計實驗指導書答案

? 狗生活在陸地上(是一種陸生動物)&#xff0c;既是哺乳類的也是肉食性的。狗通常的時候和人打招呼會通過“搖搖尾巴”&#xff0c;在被撫摸感到舒服的時候&#xff0c;會“旺旺叫”&#xff0c;而在受到驚嚇情緒煩躁時&#xff0c;會發出“嗚嗚”聲&#xff1b;? 貓也生活在…

php代碼規范說明文檔

命名規則&#xff1a;采用駝峰標識&#xff0c;盡量做到見名知義 PHP編碼規范與原則&#xff1a; //命名&#xff1a;類&#xff0c;方法&#xff0c;函數&#xff0c;變量&#xff0c; 注釋&#xff1a;開發中難免留下一些臨時代碼和調試代碼&#xff0c;此類代碼必須添加注釋…

下載網頁中的圖片到本地

簡單的一個下載如下 &#xff1a; string url "http://avatar.csdn.net/A/2/6/2_yefengzhixia.jpg";string filepath "D:\\pic.jpg";WebClient mywebclient new WebClient();mywebclient.DownloadFile(url, filepath);MessageBox.Show("OK");…

nacos linux啟動_微服務系列之Nacos配置中心之一:Nacos介紹與安裝

一、Nacos 介紹Nacos 是 Alibaba 公司推出的開源工具&#xff0c;用于實現分布式系統的服務發現與配置管理。英文全稱 Dynamic Naming and Configuration Service&#xff0c;Na 為 Naming/NameServer 即注冊中心&#xff0c;co 為 Configuration 即配置中心&#xff0c;Servic…