HTTP/2
HTTP/2
다중화, 헤더 압축, 서버 푸시 지원. HTTP/1.1 개선.
HTTP/2
다중화, 헤더 압축, 서버 푸시 지원. HTTP/1.1 개선.
HTTP/2는 2015년 IETF에서 표준화된 차세대 웹 프로토콜로, HTTP/1.1의 성능 한계를 극복하기 위해 설계되었습니다. Google의 SPDY 프로토콜을 기반으로 개발되었으며, 바이너리 프레이밍(Binary Framing)을 도입하여 텍스트 기반이던 HTTP/1.1보다 훨씬 효율적인 데이터 전송이 가능합니다. 현재 전 세계 웹사이트의 50% 이상이 HTTP/2를 사용하고 있습니다.
HTTP/2의 핵심 기능은 멀티플렉싱(Multiplexing)입니다. HTTP/1.1에서는 하나의 TCP 연결당 하나의 요청만 처리할 수 있어, 브라우저가 6개의 병렬 연결을 열어야 했습니다. 반면 HTTP/2는 단일 연결에서 수백 개의 요청을 동시에 처리할 수 있어, Head-of-Line Blocking 문제를 해결하고 페이지 로딩 속도를 30-50% 향상시킵니다.
HPACK 헤더 압축은 HTTP/2의 또 다른 중요한 특징입니다. HTTP/1.1에서는 매 요청마다 동일한 헤더(Cookie, User-Agent 등)를 반복 전송했지만, HTTP/2는 헤더 테이블을 유지하고 변경된 부분만 전송합니다. 이를 통해 헤더 크기를 85-90%까지 줄일 수 있으며, 특히 모바일 환경에서 큰 성능 향상을 보입니다.
서버 푸시(Server Push)는 클라이언트가 요청하기 전에 서버가 필요한 리소스를 미리 전송하는 기능입니다. HTML 파일을 요청하면 서버가 연관된 CSS, JavaScript 파일을 함께 푸시할 수 있습니다. 다만 실제 사용에서는 캐시 무효화 문제 등으로 Chrome 106부터 서버 푸시 지원이 제거되어, 현재는 103 Early Hints나 preload 태그를 권장합니다.
# Nginx HTTP/2 설정
# /etc/nginx/nginx.conf 또는 /etc/nginx/sites-available/default
server {
listen 443 ssl http2; # HTTP/2 활성화 (TLS 필수)
listen [::]:443 ssl http2;
server_name example.com;
# SSL 인증서 설정
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# HTTP/2 최적화 설정
http2_max_concurrent_streams 128; # 동시 스트림 수
http2_push_preload on; # preload 링크 자동 푸시
# HTTP/2 서버 푸시 예시 (Chrome 106 이후 미지원)
location / {
root /var/www/html;
http2_push /css/style.css;
http2_push /js/app.js;
}
# 103 Early Hints 설정 (서버 푸시 대안)
location / {
add_header Link "; rel=preload; as=style";
add_header Link "; rel=preload; as=script";
}
}
# HTTP → HTTPS 리다이렉트
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
# HTTP/2 지원 확인: curl -I --http2 https://example.com
# Apache HTTP/2 설정
# /etc/apache2/apache2.conf 또는 httpd.conf
# HTTP/2 모듈 활성화
# sudo a2enmod http2
LoadModule http2_module modules/mod_http2.so
# 전역 HTTP/2 설정
Protocols h2 h2c http/1.1
H2Direct on
H2MaxSessionStreams 100
H2WindowSize 65535
# 가상 호스트 설정
<VirtualHost *:443>
ServerName example.com
DocumentRoot /var/www/html
# SSL 설정
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# HTTP/2 활성화
Protocols h2 http/1.1
# HTTP/2 서버 푸시
<Location />
Header add Link "</css/style.css>; rel=preload; as=style"
Header add Link "</js/app.js>; rel=preload; as=script"
</Location>
# HTTP/2 우선순위 설정
H2Push on
H2PushPriority * after
H2PushPriority text/css before
H2PushPriority application/javascript interleaved
# 로그 설정
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %{SSL_PROTOCOL}x %{HTTP2}e" http2_log
</VirtualHost>
# 확인: apachectl -M | grep http2
const http2 = require('http2');
const fs = require('fs');
const path = require('path');
// HTTP/2 서버 생성 (TLS 필수)
const server = http2.createSecureServer({
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt'),
allowHTTP1: true // HTTP/1.1 폴백 허용
});
// 스트림 핸들러
server.on('stream', (stream, headers) => {
const reqPath = headers[':path'];
const method = headers[':method'];
console.log(`${method} ${reqPath}`);
if (reqPath === '/') {
// 메인 HTML 응답
stream.respond({
'content-type': 'text/html; charset=utf-8',
':status': 200
});
// 서버 푸시 (권장하지 않음 - 대안 사용)
// 103 Early Hints 방식으로 대체 권장
stream.pushStream({ ':path': '/style.css' }, (err, pushStream) => {
if (!err) {
pushStream.respond({ 'content-type': 'text/css', ':status': 200 });
pushStream.end('body { font-family: sans-serif; }');
}
});
stream.end(`
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>HTTP/2 Server with Node.js</h1>
<p>멀티플렉싱, 헤더 압축, 서버 푸시 지원</p>
</body>
</html>
`);
}
});
// HTTP/2 성능 비교 테스트
const http2Client = http2.connect('https://example.com');
// 멀티플렉싱: 여러 요청 동시 전송
const requests = ['/api/users', '/api/posts', '/api/comments'];
requests.forEach(path => {
const req = http2Client.request({ ':path': path });
req.on('response', headers => console.log(headers[':status']));
req.end();
});
server.listen(443, () => console.log('HTTP/2 server running on port 443'));
"HTTP/2로 전환하면 멀티플렉싱 덕분에 이미지 스프라이트나 CSS/JS 번들링을 덜 해도 됩니다. 오히려 파일을 분리하는 게 캐싱에 유리해요. 다만 서버 푸시는 Chrome에서 제거됐으니 103 Early Hints나 preload 태그를 사용하세요."
"HTTP/2의 핵심은 바이너리 프레이밍과 멀티플렉싱입니다. HTTP/1.1은 텍스트 기반이고 연결당 하나의 요청만 처리해서 HOL Blocking 문제가 있었는데, HTTP/2는 단일 연결에서 여러 스트림을 동시에 처리합니다. HPACK으로 헤더도 85% 이상 압축되고요. 실무에서 Nginx 설정 시 http2_max_concurrent_streams를 128로 설정해서 운영했습니다."
"HTTP/2는 TLS가 필수는 아니지만, 브라우저들이 h2c(cleartext)를 지원하지 않아서 사실상 HTTPS가 필요합니다. Let's Encrypt로 인증서 발급받고, Nginx에서 'listen 443 ssl http2'만 추가하면 되는데, 기존 HTTP/1.1 클라이언트와도 호환됩니다. ALPN으로 프로토콜 협상하거든요."
HTTP/2에서는 도메인 샤딩, 이미지 스프라이트, CSS/JS 번들링이 오히려 성능을 저하시킬 수 있습니다. 멀티플렉싱이 있으므로 파일을 분리하고 개별 캐싱이 가능하도록 하세요.
Chrome 106(2022년)부터 서버 푸시 지원이 제거됐습니다. 대신 103 Early Hints 응답이나 HTML의 <link rel="preload"> 태그를 사용하세요. 서버 푸시는 캐시된 리소스도 다시 보내는 문제가 있었습니다.
HTTP/2는 HTTP 레벨 HOL Blocking은 해결했지만, TCP 레벨에서는 여전히 발생합니다. 패킷 손실 시 모든 스트림이 영향받습니다. 이 문제는 QUIC 기반의 HTTP/3에서 해결됩니다.
TLS 1.2 이상 + HTTP/2 활성화, 파일 분리로 개별 캐싱 활용, preload 힌트로 중요 리소스 우선 로딩, CDN 사용 시 HTTP/2 지원 확인. curl -I --http2 명령으로 적용 여부를 확인하세요.