😎
Node.js+Express+nginx環境下においてSSE(Server‑Sent Events)のバッファリングする問題の解決策
背景
Node.js+Express+nginx 環境下でSSE(Server‑Sent Events)を実装する際、サーバー側やミドルウェアのバッファリングにより応答が遅延してしまう問題があった。
本記事では アプリケーションコードだけで遅延を解消する方法を紹介する。
SSE(Server-Sent Events)とは?
クライアントとサーバー間で一度だけHTTP接続を確立し、その接続を維持しながらサーバーからクライアントへ一方向にイベントを送信できる技術。
クライアントからサーバーへの通信はできない(一方向通信)。
結論
先に結論。
- レスポンスヘッダーで
X-Accel-Buffering: no
を送信してnginx のバッファリングを無効化する -
compression
ミドルウェア使用時は送信タイミングでres.flush()
を呼ぶ
全体のコード例としては以下のようになる。
router.get('/events', function (req, res, next) {
res.status(200).set({
'Content-Type': 'text/event-stream;',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'X-Accel-Buffering': 'no'
});
res.flushHeaders();
const text = 'これはテスト用テキストです。';
let index = 0;
const intervalId = setInterval(() => {
if (index < text.length) {
res.write(`data: ${text[index]}\n\n`);
index++;
} else {
clearInterval(intervalId);
res.end();
}
if (res.flush) {
res.flush();
}
}, 500);
req.on('close', () => {
clearInterval(intervalId);
res.end();
});
});
原因
nginxのバッファリング
nginxはデフォルトでレスポンスを一定サイズまでバッファリングしてからクライアントへ転送するため遅延が発生する。
対策は次のいずれかとなる。
- nginxの設定ファイルでバッファリングをオフにする
- アプリケーション側で
X-Accel-Buffering: no
ヘッダーを付与する
nginxの設定ファイルを変更すると、全ての箇所に影響が出るため、X-Accel-Buffering: no
ヘッダーを付与する方法が望ましい。
参考: https://take-engineer.com/nginx_server-sent-events/
compressionのバッファリング
compressionは圧縮のためにレスポンスをバッファリングする。
そのため、SSEでは遅延の原因になる。
対策方法としては、送信したいタイミングでres.flush()
実行することでチャンクを即時送信する。
まとめ
バッファリングが疑われる場合は、まずX-Accel-Buffering: no
を試す。
改善しない場合はcompression
を利用しているか確認し、利用している場合は送信したいタイミングでres.flush()
を実行する。
それでもバッファリングされる場合は、ほかの箇所に原因がある可能性が高い。
Discussion