アプリケーションのI / Oモデルを理解すると、作成された負荷で動作するアプリケーションと実際の適用方法に直面したアプリケーションとの違いを理解できます。 おそらく、アプリケーションが小さく、大きな負荷が発生しない場合、それはそれほど重要ではありません。 しかし、トラフィックが増加するにつれて、誤ったI / Oモデルを使用すると、痛みの世界に突入する可能性があります。
いくつかの可能な解決策を伴う他のほとんどの状況と同様に、どちらのオプションが優れているかではなく、妥協点を理解することです。 この記事では、Apacheの下からNode、Java、Go、PHPを比較し、異なる言語の入力/出力モデルについて説明し、各モデルの長所と短所を検討し、簡単なベンチマークに合格します。 次のWebアプリケーションのI / Oパフォーマンスに関心がある場合は、この記事が役立ちます。
I / Oの基本:知識を更新する
入力/出力に関連する要因を理解するには、まずOSレベルで使用されるいくつかの概念を思い出す必要があります。 それらの多くを直接処理する必要はほとんどありません。おそらく、アプリケーションのランタイム環境を通じて間接的に作業するでしょう。 そして詳細は重要な役割を果たします。
システムコール
まず、次のように説明できるシステムコールを使用します。
プログラム(いわゆるユーザースペース)は、オペレーティングシステムのカーネルにプログラムの代わりにI / Oを実行するように依頼する必要があります。
システムコールは、プログラムがカーネルに何かをするよう求める方法です。 実装の詳細はOSに依存しますが、基本的な原則はどこでも同じです。 カーネルを介してプログラムから制御を転送するための特定の命令が必要です(関数呼び出しとして、そのような状況で動作する特別な「アドオン」のみ)。 一般に、システムコールはブロックされています。つまり、プログラムはカーネルがコードに戻るまで待機します。
- カーネルは、目的のデバイス(ディスク、ネットワークカードなど)で基本的な入出力操作を実行し、システムコールに応答します。 実際には、カーネルは、デバイスの準備が整うのを待つ、内部状態を更新するなど、要求後に多くのアクションを実行できます。しかし、これについて心配する必要はありません。 これらは中核的な責任です。
ブロッキング呼び出しと非ブロッキング呼び出し
上記では、システムコールがブロックしていると言われましたが、一般的にはそうです。 ただし、いくつかの課題は非ブロッキングとして説明できます。 これは、カーネルがリクエストを受け入れ、それをキューまたはある種のバッファに入れてから、予期せずにすぐに現在の入力/出力に戻ることを意味します。 そのため、「ブロッキング」はごく短時間しか発生せず、リクエストをキューに入れるのに十分です。
より明確にするために、いくつかの例を示します(Linuxシステムコール):
read()
— : (handle), , ; , . .epoll_create()
,epoll_ctl()
epoll_wait()
— , , , ; / ; , . / . , , .
. 3 , - , 3 (3 ). , . , , : , 200 (1/5 ). 20 , — 200 . 10 .
(« »), (« , ») /. .
(Scheduling)
, , .
. , , . . , , . 300 , , : , . , / .
— - . , 100 , 1000 , , / , . .
( ), . , , .
: « , ». / .
? : , , … .
: ( , ). , (Memcache . .) , , , /, , . , / (PHP, Java), HTTP- : /, , .
. . , /, / , .
1990- Converse CGI- Perl. PHP, , -.
PHP . , PHP- .
HTTP- - Apache. , , ( , , ). Apache PHP .php
-, . PHP- /. PHP file_get_contents()
, read()
.
, , :
<?php
// blocking file I/O
$file_data = file_get_contents(‘/path/to/file.dat’);
// blocking network I/O
$curl = curl_init('http://example.com/example-microservice');
$result = curl_exec($curl);
// some more blocking network I/O
$result = $db->query('SELECT id, data FROM examples ORDER BY id DESC limit 100');
?>
:
: . / . ? , . ? 20 . , / (epoll .). , , , .
: Ruby , , .
: Java
Java , , « ». Java (multithreading) — ( ).
Java - , , , .
/ Java Servlet :
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
// blocking file I/O
InputStream fileIs = new FileInputStream("/path/to/file");
// blocking network I/O
URLConnection urlConnection = (new URL("http://example.com/example-microservice")).openConnection();
InputStream netIs = urlConnection.getInputStream();
// some more blocking network I/O
out.println("...");
}
doGet
, , , . , , . , PHP. , / , . (pooled), , , , .
Java 1.4 ( 1.7) /. , - , , . Java - - , Java- , .
Java /, , , / - .
/: Node
Node.js /. , Node, , , /. . , , .
, Node, : : « », : « ». , /, callback-, Node .
Node / :
http.createServer(function(request, response) {
fs.readFile('/path/to/file', 'utf8', function(err, data) {
response.end(data);
});
});
callback-. , . — .
, Node / callback-. : Node. , : Node callback-; /, , callback-. / callback- (event loop). .
. JS- V8 (JS- Chrome, Node). JS-, , . . , / , JS , . , : , , . :
var handler = function(request, response) {
connection.query('SELECT ...', function (err, rows) {
if (err) { throw err };
for (var i = 0; i < rows.length; i++) {
// do processing on each row
}
response.end(...); // write out the results
})
};
Node / , , , for
, . 10 , , , . .
, / — , , , . - , .
— , — , - , . Node- , .
. Node , /. , , HTTP-, , , .
: Go
Go, , . , , .
- , Go /. — . Go . , , — . , HTTP- Go, .
:
runtime- Go, /, // . ., , , .
runtime- Go , , Node. , / . Go , - , : Go , . :
func ServeHTTP(w http.ResponseWriter, r *http.Request) {
// the underlying network call here is non-blocking
rows, err := db.Query("SELECT ...")
for _, row := range rows {
// do something with the rows,
// each request in its own goroutine
}
w.Write(...) // write the response, also non-blocking
}
, , , , /.
« ». /; , . Go . , , /. , , .
Go , /.
,
. . HTTP- . , «HTTP-/» , .
, 64- , , N SHA-256 (N URL-, , .../test.php?n=100
) . / .
(low concurrency). 2000 300 (N = 1):
. ,
- . , , , /. , ( , ).
N 1000, 300 — , ( ):
. ,
Node, , , . , PHP ( ) Java. , SHA-256 PHP , (execution path) , 1000 .
5000 (N = 1) . , . .
. ,
. , , PHP + Apache , , PHP. Go , Java, Node, — PHP.
, , , , .
, , , /.
, , PHP Java /, -. , , . , , . «» PHP Java - .
, , , :
vs. | I/O | ||
---|---|---|---|
PHP | |||
Java | |||
Node.js | |||
Go | () |
. , /, / . , Go.
, , , . - Node Go. / — , . 15 .
, , , , . !