Webサーバアーキテクチャの基礎知識
Webサーバーアーキテクチャ進化論2023 | blog.ojisan.io
Node.js の章に入ると急に饒舌になると思うが、それ以前の章はあくまで教科書的な話しかできないだろう
下の記事を元に
...コードレベルにより踏み込んだ、かつ、green threadベースの新しいWebサーバアーキテクチャも含めて整理された記事...
目次拾い読み
system programming
プロセスとスレッド
File Descriptor
stream
ソケット間通信をするためのシステムコール
socket, bind, getaddrinfo, listen, accept
multi processで並行処理する世代
軽さを求めてmulti threadを使う世代
multi processだと親子でのメモリ空間が分離されるが、multi threadだとしないのでパフォーマンスが良い
コスト:各スレッドで同一リソースにアクセスできてしまう。このracingを避けつつコードを書く必要がある
デッドロックなどの問題が発生したりする
Rustは言語レベルでロックの利用をサポート
C10Kの解決のためにsingle threadと非同期 I/Oで性能を出す世代
クライアントに対してそれぞれmulti process、multi threadを作る時の問題
process IDの枯渇、File Descriptorの枯渇
ここは拡張可能
CPU割り当て時のコンテキストスイッチ
nginxやNode.jsはsingle threadで非同期処理とEvent loopを使って解決した
single threadでの非同期処理は時間分割
I/O実行中に待たずに別のタスクを進める
コンテキストスイッチを考える必要なし
この仕組みでのプログラミングの際には、「Aが終わったらBする」仕組みが必要
callbackとかPromise (JavaScript)
これらは内部ではOSがFile Descriptorをepollやqueueで監視して非同期 I/Oを実現している
ready通知が来たfile discriptorのみaccept()しているので、IOが終わるまでの時間を自由に使える
Receiving an event from epoll_wait(2) should suggest to you
that such file descriptor is ready for the requested I/O
operation. You must consider it ready until the next
(nonblocking) read/write yields EAGAIN
https://man7.org/linux/man-pages/man7/epoll.7.html
CPUコア数上限でのmulti threadで非同期処理する世代
非同期処理はmulti threadでも可能でも可能(1つ1つのスレッドをsingle threadとしてみる)
簡単に説明すると非同期計算をするためにはタスクのキューイングと、そのタスクをコンピュータリソースに割り当てるスケジューラの実装が必要となる。スケジューラやランタイムを提供しているのが Rust だと tokio だ...
実際にはより複雑な次の世代が利用されるらしい
green threadでコンテキストスイッチを減らす世代
モチベーション:シングルスレッドにしてコンテキストスイッチ自体を無くすのではなく、マルチスレッドでもコンテキストスイッチ自体が小さければいい。OSのスレッドではなく自作する
例:goroutine、tokio、cats-effect
Work stealing
タスクの消化に村があるのでキューが詰まったりするので空いてるキューにタスクを移す仕組み
M:Nモデル
理論上green threadにFDの上限はないが、物理上限があるのでnative threadとgreen threadをマッピングする
スタックの動的確保とガードページの排除
スレッドを自作する場合に配慮が必要な項目
メモリ中領域にはヒープとスタックがある
スタックを積み上げすぎるとガードページに達してスタックオーバーフローになるようにする
ただしgreen threadを大量に作ることを想定するとガードページ自体がチリツモで無駄になるので、Goはガードページを無くしているらしい
独自ABI
別CPUサポートをしやすくする
参考文献として挙げられている
並行プログラミング入門
2015年Webサーバアーキテクチャ序論 - ゆううきブログ
webサーバー