카테고리 없음
[네트워킹과 웹성능 최적화기법] 13장 애플리케이션 전달 최적화
보리시스템
2025. 6. 5. 09:38
출처: https://hpbn.co/optimizing-application-delivery/
HTTP: Optimizing Application Delivery - High Performance Browser Networking (O'Reilly)
What every web developer must know about mobile networks, protocols, and APIs provided by browser to deliver the best user experience.
hpbn.co
[13장 애플리케이션 전달 최적화]
1. 물리적 및 전송 계층 최적화
2. Evergreen Performance 모범 사례
3. HTTP/1.x 최적화
4. HTTP/2 최적화
13장 애플리케이션 전달 최적화
- 고성능 브라우저 네트워킹을 위해...
=> 우리가 제어할 수 없는 부분: 클라이언트와 서버 간의 네트워크 환경이나 클라이언트 하드웨어, 장치 구성 등
=> 하지만 나머지는 관리를 통해 애플리케이션 최적화를 수행할 수 있음
1. 물리적 및 전송 계층 최적화
- 실제 대부분의 웹 애플리케이션의 성능은 대역폭이 아닌 지연 시간에 의해 결정됨
=> 비트의 이동 속도를 더 빠르게 할 수는 없지만
=> 전송 및 애플리케이션 계층에서 가능한 모든 최적화를 적용하여 성능을 향상할 수 있음
- 물리계층 (통신 채널의 물리적 특성은 모든 애플리케이션의 성능에 제한을 줌)
1) 광속과 클라이언트-서버 간 거리 => 전파 지연 시간에 영향
* 최적화 방법? 서버를 클라이언트에 더 가깝게 배치 (불필요한 왕복과 요청을 제거, 각 패킷이 이동한 거리를 최소화 등)
2) 유/무선 여부 => 각 데이터 패킷에 발생하는 처리, 전송, 큐잉 및 기타 지연에 영향
* 무선 네트워크는 지연 시간이 길고 대역폭이 항상 제한적임
- 응용-전송 계층
=> 기본 프로토콜을 최적화하기 위해서는 모든 서버가 최신 TCP(전송 계층) 및 TLS(응용-전송 계층 사이) 모범 사례를 사용하도록 구성되어야 함
- 애플리케이션 계층
=> HTTP는 불완전한 프로토콜이기 때문에 애플리케이션을 설계시 주의해야 함
- HTTP/1.x의 한계를 극복해야 함
- HTTP/2의 새로운 성능 역량을 활용해야 함
- 에버그린 성과 우수 사례를 적용하는 데 항상 주의를 기울여야 함
2. Evergreen Performance 모범 사례
- Evergreen Performance
Evergreen Performance?
=> 지속적이고 자동적으로 최신 성능 최적화 기술을 적용
- Evergreen Performance의 기반이 되는 규칙
=> 네트워크 유형이나 사용 중인 네트워킹 프로토콜의 유형 또는 버전에 관계없이 모든 애플리케이션은
1) 항상 불필요한 네트워크 지연 시간을 없애거나 줄이고
2) 전송되는 바이트 수를 최소화해야 함
1. DNS 조회 감소
=> 모든 호스트 이름 확인에는 네트워크 왕복이 필요하므로 요청에 지연이 발생하고 조회가 진행되는 동안 요청이 차단됨
2. TCP 연결 재사용
=> 가능한 한 연결 유지 기능을 활용하여 TCP 핸드셰이크와 Slow-start 지연 오버헤드를 제거 (Slow-start)
3. HTTP 리디렉션 수의 최소화
=> 최적의 리디렉션 횟수는 0회
=> HTTP 리디렉션은 높은 지연 오버헤드를 발생시키기 때문임
* 예를 들어, 다른 출처로의 단일 리디렉션은 DNS, TCP, TLS 및 요청-응답 왕복을 발생시켜 수백에서 수천 밀리초의 지연 시간
4. 왕복 시간 단축
=> 서버를 사용자와 더 가깝게 배치하여 왕복 시간 단축 (예: TCP 및 TLS 핸드셰이크가 더 빨라짐)
=> 프로토콜 성능이 향상되고 정적/동적 콘텐츠의 전송 처리량이 향상된 (캐시되지 않은 원본 가져오기)
5. 불필요한 리소스 제거
=> 불필요한 리소스를 모니터링하여 제거
- HTTP 버전별 성능향상 방법
1. 클라이언트의 캐시 리소스
- 애플리케이션 리소스를 캐시하면 리소스가 필요할 때마다 동일한 바이트를 다시 요청하지 않아도 됨
=> 이전에 다운로드한 데이터의 캐시를 유지
=> 클라이언트가 리소스의 로컬 복사본을 사용할 수 있으므로 요청이 실행되지 않음
- HTTP를 통해 전달되는 리소스의 경우, 적절한 캐시 헤더가 있는지 확인
1) Cache-Control 헤더: 리소스의 캐시 수명(max-age)을 지정할 수 있음
2) Last-Modified 헤더: ETag검증 메커니즘 제공
=> 가능하면 각 리소스에 대해 명시적인 캐시 수명을 지정한 뒤 만료된 리소스가 업데이트되었는지 확인하는 유효성 검사 메커니즘 지정
2. 전송 중 리소스 압축
- 새 리소스이거나, 캐시할 수 없는 경우 등 리소스를 가져와야 하는 경우
1) 애플리케이션 리소스는 최소한의 바이트로 전송해야 함
2) 전송되는 각 리소스에 항상 가장 적합한 압축 방법을 적용
=> HTML, CSS, JavaScript와 같은 텍스트 기반 에셋의 크기는 Gzip으로 압축하면 평균 60~80%까지 줄일 수 있음
=> 단, 이미지에는 메타데이터가 포함되어 있으므로 압축시 제거될 수 있음을 유의
* 전송되는 바이트를 최소화하려면 이미지 크기를 디스플레이 너비에 맞춰 조정 (손실형/무손실형 형식)
3. 불필요한 요청 바이트 제거
- 전송되는 HTTP 헤더 데이터(예: HTTP 쿠키)를 줄이면 네트워크 지연 시간의 전체 왕복을 줄일 수 있음
=> 많은 애플리케이션은 세션 관리, 개인화, 분석 등을 위해 상태 정보를 필요
- HTTP 상태 관리 메커니즘(RFC 2965) 확장
=> 모든 웹사이트가 해당 출처의 "쿠키" 메타데이터를 연결하고 업데이트
* 쿠키 크기에 대한 최대 제한을 명시하지 않지만, 실제로 대부분의 브라우저는 4KB 제한을 적용
=> 이 표준은 사이트가 출처별로 여러 개의 쿠키를 연결할 수 있도록 허용
* 결과적으로, 각 출처별로 수십에서 수백 킬로바이트에 달하는 임의의 메타데이터를 여러 쿠키에 나누어 연결할 수 있음
=> HTTP/1.x에서는 쿠키를 포함한 모든 HTTP 헤더가 각 요청 시 압축되지 않은 상태로 전송됨
=> HTTP/2에서는 헤더가 HPACK을 사용하여 압축되지만, 최소한 쿠키 값은 첫 번째 요청 시 전송되므로 초기 페이지 로드 성능에 영향을 미침
- 가장 좋은 방법은 가능한 쿠키를 완전히 제거하는 것임
=> 이미지, 스크립트, 스타일시트와 같은 정적 에셋을 요청할 때는 클라이언트별 메타데이터가 필요하지 않을 가능성이 높음
=> 보안 세션 토큰과 같은 필수 데이터는 최소한으로만 전송
=> 서버의 공유 세션 캐시를 활용하여 다른 메타데이터를 조회
4. 요청 및 응답 처리 병렬화
- 클라이언트/서버에서 요청 및 응답 대기열 지연은 종종 눈에 띄지 않지만, 상당하고 불필요한 지연을 발생
1) 연결 유지 시간 제한을 최적화하여 TCP 연결을 재사용
=> 연결 유지 기능이 없으면 각 HTTP 요청마다 새로운 TCP 연결이 필요하며, 이는 TCP 핸드셰이크와 느린 시작으로 인해 상당한 오버헤드를 발생
2) 다중화와 최상의 성능을 위해 HTTP/2로 업그레이드
=> HTTP/2를 사용하여 클라이언트와 서버가 모든 요청에 대해 동일한 연결을 재사용할 수 있도록 해야 함
* HTTP/2는 요청 및 응답 다중화, 헤더 압축, 우선순위 지정 등을 통해 네트워크 리소스를 더욱 효율적으로 사용하고 지연 시간을 단축
3) 병렬 다운로드가 필요한 경우 여러 개의 HTTP/1.1 연결을 사용
=> HTTP/2를 사용할 수 없는 경우, HTTP/1.x를 사용하여 여러 TCP 연결을 사용하여 요청 병렬 처리를 구현
- 클라이언트 리소스 워터폴( 리소스 워터폴 분석 참조 )과 서버 로그를 검토
5. 프로토콜별 최적화 적용
- HTTP/1.x
=> 제한된 병렬 처리를 제공하므로 리소스를 묶고, 여러 도메인에 걸쳐 전송을 분할하는 등의 작업
- HTTP/2
=> 단일 연결을 사용하고 HTTP/1.x 전용 최적화를 제거
3. HTTP/1.x 최적화
- 파이프라인은 지원이 제한적이며, 나머지 최적화 기법들은 각각 장단점을 가지고 있음
=> 아래의 방법들을 과도하게 적용하거나 잘못 적용하면 성능에 악영향
1. HTTP 파이프라이닝 활용
=> 애플리케이션이 클라이언트와 서버를 모두 제어하는 경우 파이프라인은 불필요한 네트워크 지연을 제거하는 데 도움됨
2. 도메인 샤딩 적용
=> 원본당 기본 6개 연결 제한으로 인해 애플리케이션 성능이 제한되는 경우 여러 원본에 리소스를 분할
3. 리소스 번들로 묶어 HTTP 요청을 줄이기
=> 연결 및 스프라이팅과 같은 기술은 프로토콜 오버헤드를 최소화하고 파이프라인과 같은 성능 이점을 제공
4. 인라인 소규모 리소스
=> 작은 리소스를 부모 문서에 직접 포함하여 요청 수를 최소화
4. HTTP/2 최적화
- HTTP/2에서 최상의 성능을 얻으려면 잘 조정된 서버 네트워크 스택이 필요
- 에버그린 애플리케이션 모범 사례를 적용
=> 전송 바이트 수 줄이기
=> 요청 제거
=> 무선 네트워크에 맞춰 리소스 스케줄링 조정
- 도메인 샤딩, 연결, 이미지 스프라이팅을 생략해 성능 향상
=> HTTP/2를 사용하면 더 이상 제한된 병렬 처리에 제약받지 않으므로 해당 방법들이 불필요(안티패턴이 됨)
- 도메인 샤딩 제거
- HTTP/2는 동일한 TCP 연결을 통해 요청을 다중화하여 최상의 성능을 달성
=> 최적의 연결 수는 하나임
=> 도메인 샤딩은 안티 패턴
- HTTP/2는 아래의 조건일때 클라이언트가 여러 출처에서 온 요청을 통합하고 동일한 연결을 통해 전송할 수 있도록 하는 TLS 연결 통합 메커니즘을 제공
1) 모든 하위 도메인에 유효한 동일한 TLS 인증서(와일드카드 인증서 또는 "주체 대체 이름"이 일치하는 인증서)를 제공하는 경우
2) 동일한 서버 IP 주소로 확인되는 자산을 참조하는 경우
- HTTP/1.x 클라이언트에는 샤딩된 자산 참조를, HTTP/2 클라이언트에는 동일 출처 자산 참조를 사용
=> 애플리케이션 아키텍처에 따라 연결 병합을 사용할 수도 있고, 대체 마크업을 제공해야 할 수도 있으며
=> HTTP/2 성능 최적화에만 집중할 수도 있음
=> 최적의 HTTP/1.x 및 HTTP/2 환경을 제공하기 위해 필요에 따라 두 가지 기술을 모두 사용할 수도 있음
* 단 두 프로토콜을 모두 최적화하는 데 따르는 추가적인 복잡성은 불필요할 수 있음
- 연결 및 이미지 스프라이팅 최소화
- HTTP/2에서는 멀티플렉싱이 더 이상 문제가 되지 않음
* HTTP/1.x는 각 리소스에 대한 세분화된 캐시 관리 메커니즘을 제공하지만, 병렬 처리의 한계로 인해 리소스를 묶어야 했음
=> 헤더 압축은 각 HTTP 요청의 메타데이터 오버헤드를 크게 줄여줌
=> 연결 및 스프라이팅의 새로운 장단점을 고려하여 사용을 재고해야 합니다.
* 리소스를 묶어 놓으면 불필요한 데이터 전송이 발생 (번들된 리소스로 인해 비용이 많이 드는 캐시 무효화가 발생)
- 하지만 HTTP/2가 연결과 스프라이팅의 유용성을 완전히 없애는 것은 아님
=> 추가 고려 사항: 비슷한 데이터를 담고 있는 파일은 묶으면 압축률이 더 좋아질 수 있음
* 적절한 균형점은 콘텐츠 유형, 업데이트 빈도, 액세스 패턴 및 기타 기준에 따라 달라짐
* 최상의 결과를 얻으려면 자체 애플리케이션의 측정 데이터를 수집하고 그에 따라 최적화
- 서버 푸시로 왕복 시간 제거
- 서버 푸시는 HTTP/2의 강력한 신기능
=> 서버가 단일 클라이언트 요청에 대해 여러 응답을 전송할 수 있도록 함
=> 서버 푸시는 지연 시간 최적화 기능을 통해 클라이언트와 서버 간의 전체 요청-응답 왕복을 제거
- 서버 푸시에 적합한 대상
=> 페이지 생성 및 렌더링을 차단하는 중요 리소스( DOM, CSSOM, JavaScript 참조 )
* 미리 지정되거나 알려진 경우가 많기 때문임
- 클라이언트는 서버 푸시 사용을 제한하거나 완전히 비활성화할 수 있름
=> 서버 푸시는 이름에서 알 수 있듯이 서버에서 시작되지만
=> 클라이언트는 서버에서 병렬로 시작할 수 있는 최대 푸시 스트림 수와 클라이언트가 확인 전까지 각 스트림에서 전송할 수 있는 데이터 양을 서버에 알려줌으로써
=> 서버 푸시의 사용 방식과 위치를 제어할 수 있음
* 예를 들어, 사용자가 고비용 네트워크를 사용하고 전송되는 바이트 수를 최소화하려는 경우, 페치되는 내용을 명시적으로 제어하기 위해 지연 시간 최적화를 비활성화할 수 있음
- 서버 푸시는 동일 출처 제한을 받음
=> 서버 푸시를 활용할 수 있는 기회를 늘리려면 리소스를 동일 출처에 통합하는 것이 좋음
=> 다시말해, 도메인 샤딩 없애기
- 서버 푸시 응답은 브라우저에서 시작된 요청에 대한 응답과 동일한 방식으로 처리됨
=> 캐시되어 여러 페이지와 탐색에서 재사용될 수 있움
* 이 기능을 활용해 여러 페이지와 탐색에서 동일한 콘텐츠를 중복해서 사용할 필요가 없어짐
- HTTP/2 서버 품질 테스트
- HTTP/2에서도 흐름 제어 및 요청 우선순위 지정과 같은 기능을 제대로 지원하지 않으면 최적의 성능을 얻기가 어려움
=> 서버 처리량과 초당 요청 수를 측정하는 품질 테스트 통한 실제 환경 반영 필요
* 예를 들어, 이미지와 같이 우선순위가 낮은 대용량 리소스를 전송하여 사용자 대역폭을 포화시키는 반면, 브라우저는 HTML, CSS 또는 JavaScript와 같이 우선순위가 높은 리소스를 수신할 때까지 페이지 렌더링이 차단
- 요청 우선순위 지정을 통한 응답전달 최적화
=> 요청 우선순위 지정의 목적은 제한된 용량이 있을 때 클라이언트가 서버가 응답을 전달하는 방식을 선택할 수 있도록 하는 것
* 서버가 모든 우선순위 정보를 무시하면 클라이언트에 불필요한 처리 지연이 발생할 위험이 있음
=> 하지만 엄격한 종속성 순서로 스트림을 전송하는 것은 다른 리소스의 전송을 불필요하게 차단하는 헤드 오브 라인(Head-of-Line) 블로킹 문제를 다시 발생시켜 최적의 성능을 발휘하지 못할 수도 있음
* 우선순위가 높은 스트림이 모두 차단된 경우에는 우선순위가 낮은 스트림을 인터리빙해야 함