もう䞀床ネットワヌクデヌモンのアヌキテクチャに぀いお

Habrを含む倚くの蚘事で、ネットワヌクサヌビスデヌモンのアヌキテクチャを構築するさたざたな方法が蚀及され、説明されおいたす。 ただし、数䞇の同時接続やギガビットトラフィックで動䜜するデヌモンを䜜成および最適化した経隓のある著者はほずんどいたせん。



ほずんどの著者はドキュメントに煩わされるこずさえないので、通垞、そのような蚘事では、すべおの情報は特定の噂ず噂の再語に基づいおいたす。 これらのうわさはWebをうろ぀き、Wikipedia、Habrahabrおよびその他の評刀のよいリ゜ヌスをヒットしたす。 結果は「 あなたはおそらく冗談だろう、Dahl、たたはNode.jsなのか」のような反察掟です 著者の句読点は保持されたすそれは基本的に本質的に真実ですが、䞍正確さでいっぱいで、いく぀かの事実䞊の誀りを含み、いく぀かのあいたいなオブゞェクトを描写したす短瞮。



「珟圚、有効なポヌリングの実装は* nix-systemsでのみ利甚可胜」などのフレヌズが豊富な蚘事をバむパスするこずは困難でしたpollは* nixを陀くどこかにあるように。 この投皿は、圌の蚘事で尊敬されおいるむニクリンの誀りを説明する解説ずしお始たりたした。 執筆の過皋で、最初から䞻題を説明する方が簡単であるこずがわかりたした。これは実際には別の投皿ずしお行いたす。

私の゚ッセむでは、カバヌの内蚳やいく぀かの未知のトリックはありたせん。異なるオペレヌティングシステムで実際にこれがどのように機胜するかをチェックした人による、異なるアプロヌチの長所ず短所を単に説明しおいたす。

啓発したい人のために、猫ぞようこそ。



ネットワヌクデヌモンのTK



たず、ネットワヌクサヌビスが正確に䜕をすべきか、そしお䞀般的には䜕が問題なのかを理解する必芁がありたす。



すべおのデヌモンは、ネットワヌク接続を受け入れお凊理する必芁がありたす。 TCP / IPプロトコルスタックはUNIXから発展し、このOSは「すべおはファむル」ずいう教矩を公蚀しおいるため、ネットワヌク接続は、ファむルを操䜜するための暙準OS機胜によっお開かれ、閉じられ、読み曞きされる特別なタむプのファむルです。 モヌダル動詞「can」に泚意しおください。「理論的に」ずいう蚀葉ず組み合わせお、珟実を非垞に正確に衚したす。



したがっお、たず、デヌモンはシステム関数socketを呌び出し、次にbind、listenを呌び出し、その結果、特殊なタむプの「listening socket」のファむルを受け取りたす。 これらの機胜のパラメヌタずデヌモンのさらなるアクションは、䜿甚されるトランスポヌトプロトコルTCP、UDP、ICMP、RPDなどに倧きく䟝存したすが、ほずんどのオペレヌティングシステムでは、最初の2぀のみをバむンドできたす。 この蚘事では、最も人気のあるTCPプロトコルを䟋ずしお芋おいきたす。



リスニング゜ケットはファむルですが、発生する可胜性があるのは、「着信接続芁求」などの定期的に発生するむベントです。 デヌモンはaccept関数を䜿甚しおこの接続を受け入れるこずができたす。この関数は新しいファむルを䜜成したすが、今回は「TCP / IPネットワヌク゜ケットを開く」タむプです。 おそらく、デヌモンはこの接続から芁求を読み取り、それを凊理しお結果を送り返す必芁がありたす。



同時に、ネットワヌク゜ケットは既にほが通垞のファむルです。最も暙準的な方法では䜜成されおいたせんが、少なくずもそこからデヌタの読み取りず曞き蟌みを詊みるこずができたす。 ただし、ファむルシステムにある通垞のファむルずは倧きく異なりたす。

*すべおのむベントは、実際には非同期に発生し、期間は䞍明です。 最悪の堎合の操䜜には数十分かかる堎合がありたす。 䞀般的には。

*ファむルずは異なり、接続は、最も予期せぬ瞬間に「自分で」閉じるこずができたす。

* OSは垞に閉じた接続を報告するわけではありたせん。「デッド」゜ケットは30分ハングするこずがありたす。

*クラむアントずサヌバヌの接続は異なる時間に閉じられたす。 クラむアントが新しい接続を䜜成しおデヌタを「送信」しようずするず、デヌタの耇補が可胜になり、クラむアントが誀っお曞き蟌たれた堎合、倱われる可胜性がありたす。 サヌバヌが1぀のクラむアントから耇数の接続を開いおいる可胜性もありたす。

*デヌタはバむトのストリヌムず芋なされ、文字通り1バむトの郚分で受信できたす。 したがっお、たずえばUTF-8文字列ず芋なすこずはできたせん。

*ネットワヌク䞊のデヌモンによっお提䟛されるもの以倖のバッファはありたせん。 したがっお、1バむトでも゜ケットに曞き蟌むず、デヌモンが数十分ブロックされる可胜性がありたす䞊蚘を参照。 さらに、サヌバヌ䞊のメモリは「非ゎム」であり、デヌモンは結果の生成速床を制限できる必芁がありたす。

*゚ラヌはどこでも発生する可胜性があり、デヌモンはそれらをすべお正しく凊理する必芁がありたす。



開いおいるすべおの接続「額」でルヌプを䜜成するず、最初の「ハング」接続は他のすべおの接続をブロックしたす。 はい、数十分です。 そしお、デヌモンのさたざたなモゞュヌルの盞互䜜甚を敎理するためのさたざたなオプションがありたす。 写真を参照しおください



免責事項 図は、珟実に察応しない擬䌌蚀語コヌドを瀺しおいたす。 倚くの重芁なシステムコヌルずすべおの゚ラヌ凊理コヌドは、明確にするために省略されおいたす。



2.マルチプロセスアヌキテクチャ



接続が盞互に圱響しないようにする最も簡単な方法は、接続ごずに個別のプロセス぀たり、プログラムの個別のコピヌを開始するこずです。 この方法の欠点は明らかです-別のプロセスを開始するず、非垞にリ゜ヌスを消費する操䜜になりたす。 しかし、ほずんどの蚘事では、このメ゜ッドが同じApacheで䜿甚されおいる理由を説明しおいたせん。



そしお、すべおのOSでのプロセスは、システムリ゜ヌスメモリ、オヌプンファむル、アクセス暩、クォヌタなどのアカりンティングの単䜍であるずいうこずです。 シェルやFTPなどのオペレヌティングシステム甚のリモヌトアクセスデヌモンを䜜成する堎合、ファむルのアクセス蚱可を正しく考慮するために、ログむンしおいる各ナヌザヌに代わっお個別のプロセスを開始するだけです。 同様に、異なるナヌザヌの数癟のサむトが1぀の「物理」ポヌトで同時に共有ホスティングサヌバヌ䞊でスピンしおいたす。たた、䞀郚のホスティングナヌザヌのサむトが他のナヌザヌのデヌタにアクセスできないように、プロセスにApacheが必芁です。 プロセスを䜿甚しおも、実際にはApacheのパフォヌマンスには圱響したせん。

画像

グラフ䞊-Linuxカヌネルのバヌゞョンに応じた、1秒あたりの静的ファむルぞの凊理枈みリク゚ストの数。 倚いほど良い。

テストベンチCore i7 970、3Gb DDR3、Nvidia GTX 460、64GB OCZ Vertex SSD。

出兞Phoronix。

あなたの悪魔が毎秒17000ファむルを䞎えるこずを望みたす。



デヌモンのナヌザヌがオペレヌティングシステムに登録されおいなくおも、サヌビスのセキュリティ芁件が高くなっおいる堎合でも、ナヌザヌごずに個別のプロセスを割り圓おるこずは非垞に合理的なアヌキテクチャ゜リュヌションです。 これにより、悪意のあるナヌザヌが他のナヌザヌのデヌタの読み取りやデヌモンプロセスの砎壊を蚱可するバグをデヌモンに芋぀けたずしおも、他のナヌザヌのデヌタぞのアクセスを取埗たたはブロックするこずはできたせん。



最埌に、各プロセスには独自のアドレス空間があり、異なるプロセスが盞互のメモリ䜿甚を劚げるこずはありたせん。 この利点が䞀郚説明されおいる理由



3.マルチスレッドアヌキテクチャ



ストリヌムは、共有メモリ、システムリ゜ヌス、アクセス暩を持ち、スタックが異なる最も簡単な「プロセス」です。 ぀たり、スレッドには共通の動的倉数、グロヌバル倉数、静的倉数がありたすが、ロヌカル倉数は異なりたす。 マルチプロセッサおよび/たたはマルチコアシステムでは、同じプロセスの異なるスレッドを物理的に同時に実行できたす。



マルチスレッドアヌキテクチャは、パフォヌマンスずメモリ消費のためにセキュリティず安定性が犠牲になるマルチプロセスアヌキテクチャに䌌おいたす。



パフォヌマンス埌のマルチスレッドアヌキテクチャの䞻な利点は、オヌプン接続凊理アルゎリズムのシヌケンスず同期です。 ぀たり、アルゎリズムは、最初の郚分の図に瀺されおいるずおりに衚瀺および実行されたす。 最初に、必芁な時間だけデヌタが゜ケットから読み取られ、次に凊理されたす。この堎合も、この凊理に必芁な時間だけ結果がクラむアントに送信されたす。 同時に、結果の送信を速すぎるず、ストリヌムはwrite関数によっお自動的にブロックされたす。 凊理アルゎリズムは単玔で、少なくずも最高レベルでは簡単です。 これは非垞に倧きなプラスです。



同時接続数が比范的少ない堎合、マルチスレッドアヌキテクチャが最適です。 しかし、実際に倚数の接続1䞇などがある堎合、スレッド間の切り替えには時間がかかりすぎたす。 しかし、これでもマルチスレッドアヌキテクチャの䞻な欠点ではありたせん。



そしお䞻なこずは、スレッドが独立しおおらず、お互いをブロックできるそしおブロックするこずです。 これがどのように発生するかを理解するには、䟋を考えおください。



匏の倀を蚈算する必芁があるずしたしょう

a = b + c;





、ここで、a、b、およびcはグロヌバル倉数です。



通垞のシングルスレッドの状況では、コンパむラは次のマシンコヌドのようなものを生成したす。

a = b; // MOV A, B

a += c; // ADD A, C









マルチスレッドバヌゞョンでは、このコヌドは䜿甚できたせん。 別のスレッドは、最初の呜什ず2番目の呜什の間でbの倀を倉曎できたす。その結果、誀ったaの倀を取埗したす。 aが垞にb + cに等しいず芋なされる堎合、「フロヌティング」゚ラヌを再珟するのは非垞に困難です。



したがっお、マルチスレッドバヌゞョンでは、コヌドは次のように䜿甚されたす。

lock a;

lock b;

lock c;

a = b;

a += c;

unlock c;

unlock b;

unlock a;







ここで、lockおよびunlockは、倉数ぞのアクセスをロックおよびロック解陀するアトミック操䜜です。 これらは、倉数が別のスレッドによっお既にロックされおいる堎合、lock操䜜がその倉数の解攟を埅機するように配眮されたす。



したがっお、2぀のスレッドが同時に操䜜a = b + cおよびb = c + aの実行を開始するず、それらは互いに氞遠にブロックされたす。 この状況はクリンチず呌ばれ、クリンチの怜玢ず解決は、䞊列プログラミングの別の「痛い䞻題」です。 しかし、クリンチがなくおも、スレッドは、ロックを迅速に解陀しないず、非垞に長い期間互いに停止する可胜性がありたす。



さらに、アトミック操䜜は、RAMバスずRAM自䜓の排他制埡によっお物理的に実装されたす。 キャッシュではなくメモリを盎接操䜜するこず自䜓が非垞に遅く、この堎合、他のすべおのサヌバヌプロセッサのすべおのコアの察応するキャッシュラむンが無効化リセットされたす。 ぀たり、最良の堎合でも、ロックがない堎合、各アトミック操䜜は十分に長い時間実行され、他のスレッドのパフォヌマンスが䜎䞋したす。



しかし、悪魔の぀ながりはほずんど独立しおいるため、どこから共通倉数を取埗できるのでしょうか

しかし、どこから

*新しい化合物の䞀般的なキュヌ。

*デヌタベヌスたたは同様のリ゜ヌスにアクセスするための䞀般的なキュヌ。

*メモリ割り圓おのリク゚ストの䞀般的なキュヌyes、mallocおよびnewはブロッキングを匕き起こす可胜性がありたす;

*䞀般ログログファむルおよび統蚈蚈算の䞀般オブゞェクト。

これらは最も明癜なものです。



堎合によっおは、共有倉数を省く方法がありたす。 たずえば、ストリヌムの1぀に「ディスパッチャヌ」の機胜を付䞎するず、新しい接続のキュヌのブロックを拒吊できたす。これにより、巧劙な方法でタスクが配られたす。 特別な「非ブロッキング」デヌタ構造を適甚できる堎合がありたす。 しかし、䞀般的に、マルチスレッドアヌキテクチャのデッドロックの問題は解決されおいたせん。



4.ノンブロッキングアヌキテクチャ



理想的には、アプリケヌション内のスレッドの数は、プロセッサコアの数ずほが同数である必芁がありたす。 これを実珟する1぀のメカニズムは、非ブロッキングI / Oです。



ノンブロッキングI / Oは、ほずんどの最新のオペレヌティングシステムにむンストヌルできる単なるファむルアクセスモヌドです。 通垞の「ブロッキング」モヌドで読み取り関数がプログラマヌが泚文した数だけファむルからバむトを読み取り、この読み取りが進行䞭にそれを匕き起こしたスレッドを「無効」にするず、非ブロッキングモヌドでは同じ読み取り関数はファむルから読み取りたせんが、キャッシュ、このキャッシュ内のバむト数ず同じ数になり、その埌、トラフィックをストリヌミングしたりブロックしたりするこずなく、すぐに戻りたす。 キャッシュが空の堎合、非ブロッキング読み取りは0バむトを読み取り、システム゚ラヌコヌドをEWOULDBLOCKに蚭定し、すぐに戻りたす。 それでも、これは通垞の同期関数ぞの通垞の同期呌び出しです。



特に英語版りィキペディアでは、非ブロッキング同期入出力が「非同期」ず呌ばれる混乱が、明らかに、Linux OSのあたり奜奇心のない謝眪者によっお匕き起こされおいたす。 このオペレヌティングシステムでは、カヌネル2.6.22-2.6.29たで長い間、非同期I / O関数がたったくありたせんでしたそしお、珟圚でも必芁なすべおのセットがなく、特に非同期fnctlはありたせん。このOSでのみ、圌らは誀っおノンブロッキング同期関数を「非同期」ず呌んでいたした。これは倚くの叀いLinuxマニュアルで远跡できたす。


非同期I / Oに぀いおは次のパヌトで詳しく説明したすが、ここでは非ブロッキング読み取りおよび曞き蟌み関数の䜿甚に焊点を圓おたす。



実際の条件では、ノンブロッキングreadコヌルの95がそれぞれ0バむトを読み取りたす。 OSカヌネルのこれらの「アむドル」呌び出しを回避するために、すでに読み取りおよび/たたは曞き蟌み可胜な接続のリストから遞択するようオペレヌティングシステムに芁求できるselect関数がありたす。 䞀郚の* nixオペレヌティングシステムには、pollず呌ばれるこの関数のバリアントがありたす。

pollの詳现この機胜は、POSIX暙準の次のバヌゞョンの芁件ずしお登堎したした。 Linuxの堎合、pollは最初に暙準C蚀語ラむブラリlibc> = 5.4.28の関数ずしお、通垞のselectのラッパヌずしお実装され、しばらくしおからカヌネルに「移動」されたした。 たずえば、Windowsでは、通垞のpoll関数はただありたせんが、Vistaからは、 アプリケヌションの移行を簡玠化するための特定の緩和策があり、Cのselectのラッパヌずしおも実装されおいたす。

これらすべおの革新がもたらすものを瀺すグラフを共有せざるを埗たせん。 グラフ䞊-カヌネルのバヌゞョンに応じお、ルヌプむンタヌフェむスを介しお10 GBのデヌタをポンピングする時間。 少ないほど良い。 ゜ヌスは同じで、テストベンチは同じです。

画像







いずれにせよ、selectには䞀定の制限がありたすが特に、1぀のリク゚ストのファむル数、この関数ずノンブロッキングI / Oモヌドを䜿甚するず、すべおの䜜業を30行のコヌドでオペレヌティングシステムに転送し、単玔に凊理するこずができたすあなたのデヌタ。 ほずんどの堎合、非ブロッキングI / Oを担圓するスレッドは、1぀のコアの凊理胜力の数パヌセントしか消費したせん。 すべおの蚈算を実行するず、オペレヌティングシステムのカヌネルの内郚スレッドは10倍以䞊「消費」されたす。



スレッド数の削枛に戻りたしょう。

そのため、デヌモンには「接続」クラスのオブゞェクトが倚数あり、各接続オブゞェクトに正しい順序で適甚する必芁がある䞀連の操䜜がありたす。



マルチスレッドアヌキテクチャでは、接続オブゞェクトごずに個別のスレッドが䜜成され、操䜜は目的の順序でブロックモヌドで自然に実行されたす。



ノンブロッキングI / Oアヌキテクチャでは、操䜜ごずにストリヌムが䜜成され、異なるオブゞェクトに順次適甚されたす。 これは、MMXやSSEなどのSIMD呜什に少し䌌おいたす。1぀の呜什が耇数のオブゞェクトに同時に適甚されたす。 必芁な䞀連の操䜜に耐えるため぀たり、最初に結果を蚈算しおから送信する、スレッド間のゞョブキュヌがプロセスの共有メモリに䜜成されたす。 通垞、キュヌはリングバッファに基づいお䜜成されたす。この堎合、「非ブロッキング」方匏で実装できたす。



実際のネットワヌクサヌビスでは、芁求の読み取りず結果の送信の間に、アプリケヌションサヌバヌ、DBMS、たたはその他の「重い」操䜜の呌び出しを含む、かなり耇雑な分岐凊理アルゎリズムず、すべおの分岐、ルヌプ、すべおのステップでの゚ラヌ凊理などがありたす。 同時に実行されおいるスレッドの以前の未知数に埓っおそれをすべお分解し、さらにプロセッサコアの負荷がほが同じになるように-これは、システムプログラミングのすべおの偎面をマスタヌする必芁がある最高レベルの開発者スキルです。 ほずんどの堎合、それははるかに単玔にしたす。readずwriteの間のすべおを別のストリヌムに囲み、開始N =このストリヌムのコピヌのコアの数です。 そしお、リ゜ヌスを奪い合ったり、DBMSを殺したりするクリンチメンバヌのために束葉杖が発明されたした。 䞊列スレッド。



5.非同期I / O



非同期関数ず同期関数の違いを理解しおいない堎合、簡単にするために、非同期関数は、たずえば隣接するカヌネルで呌び出したプログラムず䞊行しお同時に実行されるず想定できたす。 䞀方では、呌び出し偎プログラムは蚈算の終了を埅぀必芁がなく、䜕か圹に立぀こずができたす。 䞀方、非同期関数の結果の準備ができたら、䜕らかの方法でこれに぀いお顧客プログラムに通知する必芁がありたす。 このメッセヌゞが発生する方法は、さたざたなOSで非垞に異なる方法で実装されたす。



歎史的に、Windows 2000は非同期I / Oをサポヌトする最初のOSの1぀でした。

兞型的なナヌスケヌスは次のずおりです。たずえば、数十秒以内に倧きなファむルをロヌドするシングルスレッドアプリケヌションマルチコアプロセッサはありたせんでした。 readの同期呌び出しで芋られたむンタヌフェヌスず「クロック」をフリヌズする代わりに、非同期バヌゞョンではメむンプログラムフロヌが「ハング」せず、ロヌドプロセスず「キャンセル」ボタンを衚瀺する矎しいプログレスバヌを䜜成するこずができたす。

「プログレスバヌ」を実装するために、特別なOVERLAPPED構造が非同期Windows I / O関数に枡され、そこでOSは珟圚の転送バむト数を蚘録したす。 プログラマヌは、この構造䜓の内容を自分にずっお郜合の良いずきにい぀でも読むこずができたす-メむンのメッセヌゞ凊理サむクル、タむマヌなどで。 同じ構造で、操䜜の最埌に、その最終結果が蚘録されたす転送されたバむトの合蚈数、゚ラヌコヌドある堎合など。



この構造に加えお、独自のコヌルバック関数を、操䜜の終了時にオペレヌティングシステムによっお呌び出されるOVERLAPPEDぞのポむンタヌを取る非同期I / O関数に転送できたす。

どこにいおもプログラムを䞭断するこずによるコヌルバック関数の真の正盎な非同期起動は、同じカヌネル䞊でプログラム実行の2番目のスレッドを開始するこずず区別できたせん。 したがっお、コヌルバック関数を非垞に慎重に蚘述するか、アクセスロックに関するすべおの「マルチスレッド」ルヌルを共有デヌタに適甚する必芁がありたす。これは、シングルスレッドアプリケヌションでは非垞に奇劙です。 シングルスレッドアプリケヌションでの朜圚的な゚ラヌを回避するために、Windowsは生のコヌルバックをキュヌに入れたす。プログラマヌは、これらのコヌルバックを実行するために䞭断できるプログラム内の堎所を明瀺的に指定する必芁がありたすWaitFor *オブゞェクトファミリヌ関数。



䞊蚘の非同期I / Oスキヌムは、WindowsNTカヌネルの「ネむティブ」です。぀たり、他のすべおの操䜜は䜕らかの方法で実装されたす。 氏名-IOCP入力/出力完了ポヌト。 このスキヌムは、鉄から理論的に最倧の性胜を達成できるず考えられおいたす。 Windowsでの本栌的な䜜業甚に蚭蚈されたデヌモンは、IOCPに基づいお開発する必芁がありたす。 詳现に぀いおは、 MSDNのIOCPの抂芁を参照しおください。



Linuxでは、通垞のOVERLAPPED構造の代わりに、aiocbずの匱い類䌌性がありたす。これにより、操䜜の完了の事実のみを刀断でき、珟圚の進行状況は刀断できたせん。 カヌネルは、ナヌザヌ定矩のコヌルバックの代わりに、UNIXシグナルはい、殺すシグナルを䜿甚したす。 シグナルは完党に非同期で到着し、すべおの結果が生じたすが、リ゚ントラント関数の䜜成に慣れおいない堎合は、特殊なタむプのファむルsignalfdを䜜成し、非ブロッキングを含む通垞の同期I / O関数を䜿甚しお着信信号に関する情報を読み取るこずができたす。 詳现に぀いおは、 man aio.hを参照しおください。



非同期I / Oを䜿甚しおも、デヌモンのアヌキテクチャに制限は課せられたせん。理論的には任意です。 ただし、原則ずしお、いく぀かのワヌクフロヌがプロセッサコアの数に応じお䜿甚され、その間にサヌビス接続が均等に分散されたす。 接続ごずに、有限状態マシンFSMが構築およびプログラムされ、むベントコヌルバック関数および/たたぱラヌの呌び出しの出珟により、このマシンが1぀の状態から別の状態に移行したす。



たずめ



ご芧のずおり、それぞれの方法には長所、短所、甚途がありたす。 セキュリティが必芁な堎合-プロセスを䜿甚し、高負荷䞋で速床が重芁な堎合-ノンブロッキングI / Oで、開発の速床ずコヌドのわかりやすさが重芁な堎合は、マルチスレッドアヌキテクチャが適しおいたす。 非同期I / Oは、Windowsの䞻な方法です。 いずれにせよ、自分でI / Oを操䜜するコヌドを曞かないでください。 このネットワヌクには、すべおのアヌキテクチャずオペレヌティングシステム甚の無料の既補のラむブラリがあり、䜕十幎もの間、ほずんど茝きを攟っおいたす。 ほずんど-あなたの堎合、あなたはただあなたの条件にねじれ、ファむルし、調敎する必芁があるためです。 むンタヌネットは耇雑なものであり、䞇胜な解決策はありたせん。



デヌモンは1぀のI / Oで十分ではなく、芁求凊理䞭により耇雑な「ギャグ」が発生する可胜性がありたす。 しかし、誰かが興味を持っおいる堎合、これは別の蚘事のトピックです。



参照資料



1. C10Kの問題 、ヒントo_O_Tyncに感謝

2. libevラむブラリのヘルプ 。倧量の入出力engのさたざたなメカニズムの説明が付いたおいしい郚分です。tipsaterenkoに感謝したす。

3. よくある質問echo ru.unix.prog

4. UNIXラむブラリlibaioの抂芁

5. 2.6.12から2.6.37たでのコアパフォヌマンステスト 。



All Articles