プロセス間通信(IPC)とは?「REST APIでよくない?」と思ったので調べてみた
プロセス間通信(IPC)とは?「REST APIでよくない?」と思ったので調べてみた
はじめに
Dockerについて調べている中で、マイクロサービスに関する話題を見ていたところ、「プロセス間通信(IPC)」という言葉が出てきた。
また、以前システム開発をしていたときにも、
プロセス間通信の方がセキュリティ面や速度面で有効
という話を聞いたことがある。
ただ、当時は「プロセス間通信」という言葉自体を深く理解していなかった。
特に気になったのが、
HTTP通信と何が違うの?
という部分だった。
REST APIならHTTPを使ってデータをやり取りできる。
実装方法も分かりやすく、利用しているシステムも多い。
それなら、
分かりづらいプロセス間通信をわざわざ使うメリットがそこまで多くないなら、REST APIでよくない?
と思った。
さらに調べていくと、
- そもそもプロセスとは何なのか
- プログラムとプロセスは何が違うのか
- プロセス間通信では何を使っているのか
- HTTP通信もプロセス間通信と言えるのではないか
- ソケットとプロセス間通信は何が違うのか
- パイプとは何なのか
- 共有メモリとは何なのか
- なぜIPCは速度面やセキュリティ面で有効と言われるのか
など、いろいろな疑問が出てきた。
そこで今回はDockerの検証はいったん切り離し、まずはプロセス間通信(IPC)そのものについて調べてみる。
実際の検証では、Windows環境にNode.jsをインストールし、HTTP通信とWindowsのNamed Pipeを使った通信を比較する。
まず結論
今回の調査では、プロセス間通信(IPC)について、次のように整理できました。
HTTPは、127.0.0.1:3000のようなIPアドレスとTCPポートを使用し、HTTPプロトコルによって別プロセス間で通信する。
WindowsのNamed Pipeは、\\.\pipe\ipc-test のようなPipe名を使用し、TCP/IPやTCPポートを介さずに別プロセス間で通信できる。
今回の環境で10,000回の通信を実測したところ、Named PipeはHTTPより大幅に短い時間で処理できた。
HTTPは合計189,208.053ms(平均18.921ms)、Named Pipeは合計4,964.665ms(平均0.496ms)だった。
今回の測定では、Named Pipeの合計処理時間はHTTPの約2.63%、つまりHTTPより約97.4%短い時間で処理された。
ただし、これはあくまでWindows + Node.js v24.14.1 + 今回作成した実装・実行環境における測定結果。
通信方式の違いによる傾向を確認するための検証であり、すべての環境で同じ速度差になることを示すものではない。
そのため、この結果だけから「Named Pipeは常にHTTPより約38倍速い」と一般化することはできない。
また、最初に疑問に思っていた、
「REST APIでよくない?」
については、「同じPC上のプロセス間で高速な通信を行うこと」が目的なら、必ずしもREST APIを選ぶ必要はないという結論になった。
HTTP/REST APIは、ネットワーク越しの通信や、異なるシステム・言語・サービス間で通信する場合には扱いやすく、汎用性が高いというメリットがある。
一方、通信相手が同じWindowsマシン上のプロセスに限定されているのであれば、Named PipeのようなOSが提供するIPCを利用することで、HTTP/TCPを使わずにプロセス間通信を行える。今回の実測でも、HTTPより短い時間で通信を処理できた。
また、セキュリティ面では、Named Pipeへの接続にWindowsのユーザー権限が影響することも確認できた。
今回の検証では、Serverと同じ mainaccount からは接続できた一方、別ユーザーの ipc-test-user からは EPERM となり接続できなかった。
Node.js側で独自の認証処理を実装していなくても、Windows側のアクセス制御によって接続可否が判断されることを確認できた。
そのため、Named Pipeは単に「ローカル通信だから安全」と考えるのではなく、Windowsのユーザー権限やNamed Pipeのアクセス制御を考慮して利用する必要がある。
つまり、
「REST APIでよいか」は通信相手と目的次第であり、同一マシン内のプロセス間通信だけが目的なら、Named PipeなどのIPCも有力な選択肢になる。
というのが、今回の検証から得られた結論。
プロセスとは?
プロセス間通信について調べる前に、そもそも「プロセス」とは何なのかを整理する。
自分の場合、調べる前は、
exeファイルなどのプログラムを実行したものがプロセス?
くらいの理解だった。
大きく間違ってはいないものの、「プログラム」と「プロセス」を同じものとして考えていた部分がある。
プログラムとプロセスの違い
プログラムは、コンピューター上で実行される命令やコードそのものを指す。
一方、プロセスは、プログラムが実行されている状態をOSが管理しているもの。
イメージとしては、
プログラム
│
│ 実行
▼
プロセスとなる。
同じプログラムであっても、複数回起動すれば複数のプロセスとして動作する場合がある。
例えば、
example.exe
│
├─ 実行 → プロセスA
│
└─ 実行 → プロセスBのような状態になる。
つまり、「プログラム」と「プロセス」は同じものではない。
プロセスとスレッドの違い
スレッドについては、
スレッドはプロセスの中で動くもの
という程度の理解だった。
基本的にはこの理解でよく、1つのプロセスの中で複数のスレッドが動作することがある。
プロセス
├─ スレッドA
├─ スレッドB
└─ スレッドCプロセスとスレッドの大きな違いとして、プロセスは独立した実行単位として扱われ、プロセスごとに独立した仮想アドレス空間を持つ。
一方、同じプロセス内のスレッドは、プロセスが持つメモリ空間などを共有する。
この違いが、後述するプロセス間通信を理解するうえで重要になる。
なぜプロセス間通信が必要なのか?
プロセスごとにメモリ空間が分かれているのであれば、別のプロセスが持っているデータをどうやって利用するのでしょうか。
例えば、
プロセスA プロセスB
┌──────────────┐ ┌──────────────┐
│ メモリ空間A │ │ メモリ空間B │
│ │ │ │
│ "Hello" │ │ │
└──────────────┘ └──────────────┘プロセスAが持っている "Hello" というデータを、プロセスBに渡したいとする。
プロセスAのメモリを、プロセスBが通常の変数のように直接読み取れるわけではない。
そこで、プロセス同士がデータをやり取りするための仕組みが必要になる。
それが**プロセス間通信(IPC)**です。
プロセス間通信(IPC)とは?
IPCは「Inter-Process Communication」の略で、日本語では「プロセス間通信」と呼ばれる。
ここで最初に誤解していたのが、
IPCという名前の通信プロトコルが存在する
というイメージだった。
実際には、IPCは特定の1つのプロトコルを指す言葉ではない。
複数のプロセスがデータをやり取りするための仕組みを総称してIPCと呼ぶ。
Windowsの公式ドキュメントでも、IPCの方式としてパイプ、共有メモリ、RPCなど複数の方式が紹介されている。
代表的なものには、次のような方式がある。
| 方式 | 概要 |
|---|---|
| パイプ | プロセス間でデータをストリームとして受け渡す |
| Named Pipe | 名前を付けたパイプを使ってプロセス間で通信する |
| Unix Domain Socket | Unix系OSで同一マシン上のプロセス間通信などに利用される |
| 共有メモリ | 複数プロセスからアクセス可能なメモリ領域を利用する |
| メッセージキュー | メッセージをキューに入れてプロセス間で受け渡す |
| RPC | 別プロセスの処理を呼び出すような形で通信する |
つまり、
IPC
├─ パイプ
├─ Named Pipe
├─ Unix Domain Socket
├─ 共有メモリ
├─ メッセージキュー
└─ RPCという関係になる。
パイプとは?
パイプは、プロセス間でデータを受け渡すための仕組み。
基本的には、一方のプロセスがデータを書き込み、もう一方のプロセスがデータを読み取る。
プロセスA
│
│ 書き込み
▼
┌──────────┐
│ パイプ │
└──────────┘
│
│ 読み取り
▼
プロセスBWindowsでは、匿名パイプとNamed Pipeが用意されている。
匿名パイプは、主に親プロセスと子プロセスなど、関連するプロセス間のデータ受け渡しに利用される。
一方、Named Pipeは名前を持つため、関連のないプロセス同士でも通信できる。Windowsでは同一コンピューター上だけでなく、ネットワーク越しの通信にも利用できる。
今回はWindows環境でのIPCを実際に試すため、Named Pipeを使用する。
ソケットとは?
ソケットは、プロセス同士がデータを送受信するための通信エンドポイントとして利用される。
ここで、
ソケット通信とプロセス間通信は何が違うの?
という疑問が出てきた。
調べてみると、ソケット自体はIPCだけに使われるものではない。
例えばTCPソケットでは、
Client
│
│ TCP/IP
▼
Serverのようにネットワークを介した通信ができる。
一方、Unix Domain Socketのように、同一OS上のプロセス間通信に利用されるソケットもある。
Node.jsの node:net でも、TCP用のソケットとIPC用のエンドポイントを扱うことができ、WindowsではIPCエンドポイントとしてNamed Pipeが使用される。
そのため、
ソケット = IPC
ではない。
また、
IPC = 特定の通信方式
でもない。
このあたりは、今回調べていて特に混乱しやすかった部分だった。
共有メモリとは?
共有メモリは、複数のプロセスからアクセスできるメモリ領域を利用するIPCの方式。
通常、プロセスごとに独立した仮想アドレス空間を持つ。
プロセスA プロセスB
┌──────────────┐ ┌──────────────┐
│ メモリ空間A │ │ メモリ空間B │
└──────────────┘ └──────────────┘共有メモリでは、OSなどの仕組みによって複数のプロセスからアクセスできる共有領域を用意する。
プロセスA プロセスB
│ │
│ │
└─────────┐ ┌───────────┘
▼ ▼
┌──────────────┐
│ 共有メモリ │
└──────────────┘そのため、プロセス間で大量のデータをやり取りする場合などに利用される。
Windowsの現行ドキュメントでも、IPC方式の選択肢として共有メモリが挙げられており、大量データや高性能が必要なケースに適した方式として整理されている。
ただし、複数プロセスが同じ領域へアクセスするため、データの整合性を保つための同期処理なども考える必要がある。
今回はNode.jsでの共有メモリの詳細な検証は行わず、まずIPCの代表的な方式として理解するところまでにする。
REST APIでよくない?
ここが今回、一番気になったところだった。
自分は、
HTTPを使ったREST APIの方が分かりやすいし、わざわざIPCを使わなくてもいいのでは?
と思っていた。
例えばREST APIなら、
Node.js Client
│
│ HTTP Request
▼
Node.js Server
│
│ HTTP Response
▼
Node.js Clientという構成を簡単にイメージできる。
一方、IPCにはパイプや共有メモリなど複数の方式があり、それぞれ仕組みが異なる。
そこで、実際にHTTPとWindows Named PipeをNode.jsで作って比較してみることにした。
実際にHTTP通信を試してみる
検証環境
今回の検証では、以下の環境を使用します。
| 項目 | 環境 |
|---|---|
| OS | Windows 11 |
| 実行環境 | Node.js |
| Client | Node.js |
| Server | Node.js |
| 通信方式 | HTTP |
| プロセス | Client / Serverで別プロセス |
今回はWSLやDockerは使用しない。
検証内容
Node.jsでHTTP Serverを作成し、別プロセスからClientを起動してリクエストを送信する。
Node.js Client
│
│ HTTP
│ TCP/IP
▼
Node.js ServerClientから、
GET /pingを送信し、Serverからレスポンスを返す。
実装
onst server = http.createServer((req, res) => {
console.log(`[HTTP Server] PID=${process.pid}`);
console.log(`[HTTP Server] ${req.method} ${req.url}`);
if (req.method === 'GET' && req.url === '/ping') {
res.writeHead(200, {
'Content-Type': 'application/json',
});
res.end(JSON.stringify({
message: 'pong',
}));
return;
}
res.writeHead(404);
res.end();
});http/server.js (GitHub)
確認すること
ClientとServerが別プロセスであること
- ServerのPID
- ClientのPID
- PIDが異なること
$ node client.js
=== HTTP Client ===
PID: 23304
$ node server.js
=== HTTP Server ===
PID: 28700HTTP通信の接続先
- IPアドレス
- ポート番号
- HTTPメソッド
- URL
$ node client.js
=== HTTP Client ===
Target: http://127.0.0.1:3000/ping
Status: 200
Response: {"message":"pong"}
$ node server.js
=== HTTP Server ===
Address: http://127.0.0.1:3000
[HTTP Server] PID=28700
[HTTP Server] GET /pingTCPを使用していること
- ServerがTCPポートで待ち受けていること
- Clientがそのポートへ接続していること
PS C:\Users\XXXXX> Get-NetTCPConnection -LocalPort 3000
LocalAddress LocalPort RemoteAddress RemotePort State AppliedSetting
------------ --------- ------------- ---------- ----- --------------
127.0.0.1 3000 0.0.0.0 0 Listen検証結果
- 【Server PID】: OK
- 【Client PID】: OK
- 【接続先】: OK
- 【HTTPレスポンス】
- 【TCPポートの確認結果】
Windows Named Pipeを試してみる
今回はUnix Domain Socketではなく、WindowsのNamed Pipeを使用する。
Node.jsの node:net は、WindowsではIPCエンドポイントとしてNamed Pipeを使用できる。Node.jsでは server.listen() や net.createConnection() にIPCのパスを指定できる。
検証内容
HTTPの検証とできるだけ同じ処理を、Named Pipeで実装する。
Node.js Client
│
│ Windows Named Pipe
│ \\.\pipe\example
▼
Node.js ServerClientからメッセージを送信し、Serverがレスポンスを返す。
実装
Server
const server = net.createServer((socket) => {
console.log(`[Named Pipe Server] PID=${process.pid}`);
console.log('[Named Pipe Server] Client connected');
socket.on('data', (data) => {
const message = data.toString();
console.log(`[Named Pipe Server] Received: ${message}`);
socket.write('OK');
});
socket.on('end', () => {
console.log('[Named Pipe Server] Client disconnected');
});
socket.on('error', (error) => {
console.error(
'[Named Pipe Server] Socket error:',
error.message
);
});
});Client
const client = net.createConnection({
path: PIPE_NAME,
});
client.on('connect', () => {
console.log('[Named Pipe Client] Connected');
client.write('Hello IPC');
});
client.on('data', (data) => {
console.log(
`[Named Pipe Client] Response: ${data.toString()}`
);
client.end();
});
client.on('end', () => {
console.log('[Named Pipe Client] Disconnected');
});named-pipe/server.js (GitHub)
確認すること
ClientとServerが別プロセスであること
- Server PID
- Client PID
$ node server.js
=== Windows Named Pipe Server ===
PID: 5264
$ node client.js
=== Windows Named Pipe Client ===
PID: 5612通信先
HTTPでは、
127.0.0.1:3000のようにIPアドレスとポート番号を指定した。
Named Pipeでは、
\\.\pipe\exampleのようなPipe名を指定します。
$ node server.js
=== Windows Named Pipe Server ===
PID: 5264
Pipe: \\.\pipe\ipc-test
[Named Pipe Server] PID=5264
[Named Pipe Server] Client connected
[Named Pipe Server] Received: Hello IPC
[Named Pipe Server] Client disconnected
$ node client.js
=== Windows Named Pipe Client ===
PID: 5612
Pipe: \\.\pipe\ipc-test
[Named Pipe Client] Connected
[Named Pipe Client] Response: OK
[Named Pipe Client] DisconnectedTCPポートを使用していないこと
HTTPと比較して、
- TCPポートを使用するか
- IPアドレスを使用するか
- Named Pipeをどのように指定するか
PS C:\Users\fiibu> Get-NetTCPConnection -LocalPort 3000
Get-NetTCPConnection : プロパティ 'LocalPort' が '3000' の MSFT_NetTCPConnection オブジェクトが見つかりません。プロパテ
ィの値を確認してから再試行してください。
発生場所 行:1 文字:1
+ Get-NetTCPConnection -LocalPort 3000
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (3000:UInt16) [Get-NetTCPConnection], CimJobException
+ FullyQualifiedErrorId : CmdletizationQuery_NotFound_LocalPort,Get-NetTCPConnection
PS C:\Users\fiibu> Get-ChildItem \\.\pipe\ | Where-Object {
>> $_.Name -like "*ipc-test*"
>> }
ディレクトリ: \\.\pipe
Mode LastWriteTime Length Name
---- ------------- ------ ----
------ 1601/01/01 9:00 4 ipc-test検証結果
- 【Server PID】
- 【Client PID】
- 【Named Pipeの名前】
- 【通信結果】
- 【TCPポート使用有無】
HTTPとNamed Pipeを比較してみる
ここまでの検証結果を整理する。
| 観点 | HTTP | Windows Named Pipe |
|---|---|---|
| プロセス | 別プロセス | 別プロセス |
| 通信方式 | HTTP | Named Pipe |
| IPアドレス | 127.0.0.1 を使用 | 使用しない |
| TCPポート | 3000 を使用 | 使用しない |
| TCP/IP | TCP/IPを使用 | TCP/IPを使用しない |
| 接続先 | http://127.0.0.1:3000/ping | \\.\pipe\ipc-test |
| Node.jsでの実装 | node:http | node:net |
| 通信結果 | HTTP GETを送信し、{"message":"pong"} を正常に受信 | Hello IPC を送信し、OK を正常に受信 |
ここで、
HTTPとNamed Pipeは、どちらも別プロセス間でデータをやり取りしている
ことを確認する。
つまり、HTTPとIPCは必ずしも対立する概念ではない。
HTTPを使って別プロセスと通信すること自体も、広い意味ではプロセス間の通信に該当する。
今回比較しているのは、
HTTPというアプリケーション層の通信方式を利用する場合と、OSが提供するIPC機構であるNamed Pipeを利用する場合の違い
と考えた方が分かりやすそう。
セキュリティ面では何が違う?
最初に聞いた、
「プロセス間通信の方がセキュリティ面で有効」
という話についても確認する。
ここは単純に、
IPCだから安全
とは言えない。
Named PipeではWindowsのセキュリティ機構によってアクセスを制御できる。
Named Pipeにはセキュリティ記述子やACLを設定でき、Clientが接続する際にもアクセスチェックが行われる。
そのため、今回は以下を確認する。
確認すること
- Named Pipeにアクセス制御を設定できるか
- Windowsのユーザー権限と関係するか
- 権限によって接続できるかどうかが変わるか
- 認証なしでも接続できる状態があるか
- ローカル専用として扱う場合に注意点があるか
検証結果
確認すること
- Named Pipeにアクセス制御が設定されているか
- Windowsのユーザー権限がNamed Pipeへの接続に影響するか
- 同じユーザーと別ユーザーで接続結果が変わるか
- Node.js側で認証処理を実装していなくても接続できるか
- Named Pipeをローカルプロセス間通信に利用する場合、どのようなセキュリティ上の注意が必要か
検証結果
① 同じユーザーからの接続
Named Pipe Serverを mainaccount で起動し、同じ mainaccount からClientを実行した。
Server User : mainaccount
Client User : mainaccount
Connection : SUCCESS
Response : OKServer側でもClientからの接続とデータ受信を確認できた。
=== Client Connected ===
Server PID : 20392
Received : Hello Security Test
Client disconnectedこの結果から、同一Windowsユーザーで起動したClientからNamed Pipeへ正常に接続できることを確認した。
② 別ユーザーからの接続
検証用にWindowsローカルユーザー ipc-test-user を作成し、runas を使用して別ユーザーのPowerShellを起動した。
whoami
→ owner\ipc-test-userその状態で同じNamed PipeへClientから接続した。
結果は以下のとおりだった。
Connection : FAILED
Error : EPERM
Message : connect EPERM \\.\pipe\ipc-security-testServer側では、別ユーザーからの接続時にClientの接続・データ受信は確認できなかった。
この結果から、今回の環境ではNamed Pipeへの接続時にWindowsユーザーの権限が影響し、mainaccount では接続できた一方、ipc-test-user では接続が拒否されたことを確認できた。
③ Windowsユーザー権限との関係
mainaccount と ipc-test-user のグループ情報を確認した。
mainaccount には、
BUILTIN\Administrators
BUILTIN\Usersなどのグループが含まれていた。
一方、ipc-test-user は、
BUILTIN\Usersに所属しており、Administratorsグループには所属していなかった。
今回の検証では、
mainaccount
↓
Named Pipeへ接続
↓
成功
ipc-test-user
↓
Named Pipeへ接続
↓
EPERM
↓
失敗という結果になった。
したがって、Named Pipeは単純に「Pipe名を知っていれば誰でも接続できる」という仕組みではなく、Windowsのアクセス制御の影響を受けることを確認できた。
ただし、今回の検証だけでは「Administratorsだから接続できた」とまでは断定できない。Named Pipe作成時にWindowsが設定する既定のセキュリティ記述子や、各ユーザー・グループに設定されたアクセス権など、複数の要因が関係しそう。
④ Node.js側の認証処理
今回のClientでは、
const client = net.createConnection({
path: '\\\\.\\pipe\\ipc-security-test',
});としており、ユーザー名やパスワードをNode.js側で送信する処理は実装していない。
それでも同一ユーザーでは接続でき、別ユーザーでは接続が拒否された。
このことから、今回の通信ではアプリケーション側で独自のユーザー認証を実装しなくても、Windows側のアクセス制御によってNamed Pipeへの接続可否が判断されていることを確認できた。
ただし、
「認証処理がない = セキュリティがない」
という意味ではない。
今回確認できたのは、アプリケーション独自の認証処理を実装していなくても、Windowsのユーザー・アクセス権を利用したアクセス制御が働いているということである。
⑤ セキュリティ上の注意点
今回の検証では、同一ユーザーからは接続でき、別ユーザーからは接続できなかった。
そのため、Windows上でNamed PipeをローカルIPCとして利用する場合でも、
- Pipe名を知っているだけで接続できるとは限らない
- Windowsユーザーやグループの権限が接続可否に影響する
- アプリケーション側の認証処理とWindows側のアクセス制御は別の仕組み
- 「ローカル通信だから安全」と決めつけず、Named Pipeのアクセス権を確認する必要がある
という点に注意する必要がある。
特に、機密情報を扱うNamed Pipeや、特定のユーザー・サービスからだけ接続させたいNamed Pipeでは、Windowsのセキュリティ記述子やDACLを適切に設定する必要がある。
今回の検証結果まとめ
| 確認項目 | 結果 |
|---|---|
| Named Pipeへの接続 | 成功 |
| 同一ユーザーからの接続 | 成功 |
| 別ユーザーからの接続 | 失敗(EPERM) |
| Windowsユーザー権限との関係 | あり |
| Node.js側のユーザー認証 | 実装していない |
| Windows側のアクセス制御 | 接続結果に影響したことを確認 |
| TCP/IP | 使用していない |
| セキュリティ上の注意 | Named Pipeのアクセス権を確認・適切に設定する必要がある |
なお、Named Pipeはネットワーク越しにも利用できるため、「Named Pipeだから必ずローカル通信」というわけではない。
速度面では本当に速いのか?
もう一つ気になっていたのが、
「プロセス間通信の方が速度面で速い」
という話だった。
これについても、実際にHTTPとNamed Pipeで簡単な性能比較を行う。
検証条件
できるだけ条件を揃えて、
Client
│
│ "Hello IPC"
▼
Server
│
│ "OK"
▼
Clientという処理を繰り返す。
例えば、
- 1,000回
- 10,000回
などの回数で測定する。
記録する値
| 項目 | HTTP | Named Pipe |
|---|---|---|
| リクエスト数 | 10,000 | 10,000 |
| 送信データ | GET /ping | Hello IPC |
| 合計時間 | 189,208.053 ms | 4,964.665 ms |
| 平均時間 | 18.921 ms | 0.496 ms |
| 成功件数 | 10,000 | 10,000 |
| 失敗件数 | 0 | 0 |
測定結果
今回の測定では、HTTPの合計時間が 189,208.053 ms、Named Pipeが 4,964.665 ms となった。
平均時間では、
- HTTP:18.921 ms
- Named Pipe:0.496 ms
となり、今回の測定条件ではNamed Pipeの方が短い時間で処理された。
合計時間を比較すると、Named PipeはHTTPの約 2.63% の時間で処理されており、HTTPと比較して約 97.4%短い時間 だった。
また、両方とも10,000件すべての通信に成功しており、失敗件数は0件だった。
注意点
今回の結果は、
Windows + Node.js v24.14.1 + 今回の実装条件
で測定した結果。
この結果だけをもって、
「Named PipeはHTTPより必ず○倍速い」
と一般化することはしない。
OS、Node.jsのバージョン、送受信するデータサイズ、接続方法、同時実行数などによって結果が変わる可能性があるため。
また、今回のベンチマークでは、1回の通信ごとに接続して通信した後、切断する方式を採用している。そのため、通信そのものだけではなく、接続・切断にかかる処理時間も測定結果に含まれている。
したがって、今回の結果は、
「今回のWindows + Node.js v24.14.1環境で、同じマシン上のプロセス間通信を1回ごとの接続・切断方式で10,000回実行した場合、Named Pipeの方がHTTPより短時間で処理された」
という結果とする。
結局、REST APIでよくない?
今回の記事を書くきっかけになった疑問に戻る。
最初は、
「分かりづらいIPCを使うくらいならREST APIでよくない?」
と思っていた。
しかし、調べていくと、そもそもIPCとREST APIを単純に二択で比較すること自体が適切ではないことが分かってきた。
IPCは、
プロセス同士が通信するための仕組み
を表す広い概念。
一方、REST APIは、
HTTPなどを利用してリソースを操作するためのAPI設計の考え方
そのため、
IPC
│
├─ Named Pipe
├─ Shared Memory
├─ Unix Domain Socket
└─ その他と、
HTTP
│
└─ REST APIは、そもそも同じ分類ではない。
今回の検証から分かったこと
- 【IPCについて分かったこと】
- 【HTTPとNamed Pipeの違い】
- 【速度について分かったこと】
- 【セキュリティについて分かったこと】
REST APIを使えばよいケース
HTTP/REST APIは、通信相手や利用環境を限定せず、ネットワーク越しにサービスを利用させたい場合に向いている。
例えば、
- ネットワーク越しに通信したい
- 他のシステムやサービスから利用したい
- HTTPを利用できるクライアントからアクセスしたい
- APIとして外部に公開したい
- 言語や実行環境が異なるシステムと連携したい
といったケースでは、HTTP/REST APIが扱いやすい選択肢になる。
特にHTTPは、多くのクライアントや開発ツールから利用でき、APIとして設計・公開しやすいことがメリット。
IPCを検討するケース
IPCは、同じコンピューター上で動作するプロセス同士を通信させたい場合に検討できる。
例えば、
- 同じPC上のアプリケーション間で通信したい
- 外部ネットワークからアクセスさせる必要がない
- HTTP/TCPを使う必要がない
- OSが提供するIPC機構を利用したい
- プロセス間で高速なデータ交換を行いたい
- Windows環境であればNamed Pipeを利用したい
といったケース。
今回の検証では、Windows Named Pipeを使用することでTCP/IPを介さずにプロセス間通信ができ、
今回の測定条件ではHTTPより短い時間で処理できることを確認した。
Windowsの公式ドキュメントでも、Named Pipeはストリーム型の双方向通信、共有メモリは大量データ・高性能用途など、IPC方式ごとに適した用途が整理されている。
今回はDockerの検証をしない理由
今回、IPCについて調べるきっかけになったのはDockerやマイクロサービスだった。
ただし、Dockerまで含めると、
- コンテナ
- IPC namespace
- ネットワーク
- コンテナ間通信
- Unix Domain Socket
- DockerのIPC設定
など、別の話題が増えるのでまた後日。
とりあえず
IPCとは何なのか?
を理解することを目的とする。
今回の記事で新たに出てきた、
Dockerコンテナ同士ではIPCをどうやって行うのか?
という疑問は、次の記事のテーマにでもする。
次に調べたいこと
今回の調査から、さらに次の疑問が出てきた。
- Dockerコンテナ間でもIPCは利用できるのか?
- コンテナごとにIPCは分離されるのか?
- DockerでNamed PipeやUnix Domain Socketは利用できるのか?
- IPC namespaceとは何を分離しているのか?
- コンテナ間で共有メモリを利用できるのか?
このあたりは、実際にDockerコンテナを作って検証してみたいと思う。
まとめ
今回は、Dockerやマイクロサービスを調べている中で気になった「プロセス間通信(IPC)」について調べた。
最初は、
「REST APIでよくない?」
と思っていた。
しかし、調べてみるとIPCは特定の通信プロトコルを指す言葉ではなく、プロセス同士がデータをやり取りするための仕組みをまとめた言葉だと分かった。
また、WindowsではNamed Pipeを利用したIPCをNode.jsから実装できる。
今回の検証では、HTTPとNamed Pipeを実際に動かして、通信方法や接続先、TCP/IPの利用などの違いを確認した。
今回分かったこと
- 【IPCとは何か】
- 【プロセスとプログラムの違い】
- 【HTTPとIPCの関係】
- 【Named Pipeの仕組み】
- 【セキュリティ面の違い】
- 【速度面の検証結果】
最初の疑問だった「REST APIでよくない?」についても、【最終結論を記載】となった。
次回は今回の調査で残った疑問をもとに、DockerコンテナにおけるIPCについて実際に検証してみる。
参考資料
今回使用したGithubコード群