HTTP 요청 최소화
HTTP 요청 최소화는 최적화에서 가장 기본이면서도 중요한 부분이다. 웹 사이트는 주로 마크업, 이미지, 스타일시트, 자바스크립트 등으로 구성된다. 각 구성 요소는 모두 웹 서버에 있다. 이 구성 요소를 사용자의 컴퓨터로 가져오는 데는 네트워크 비용이 든다. 네트워크 비용은 곧 응답 시간으로 이어진다. 그러므로 다운로드해야 하는 구성 요소의 개수를 줄이는 것은 가장 효과가 크고 중요한 최적화 방법이다. 웹 페이지에서 다운로드하는 구성 요소의 개수는 HttpWatch나 YSlow[^13]로 알아볼 수 있다.
다음은 YSlow로 네이버me(http://me.naver.com) 서비스 페이지를 분석한 결과다. 왼쪽 분석 결과는 캐시가 없는 상태일 때를 분석한 결과고, 오른쪽 분석 결과는 캐시가 있는 상태일 때를 분석한 결과다. YSlow를 이용하면 이처럼 웹 페이지의 구성 요소의 개수와 크기를 쉽게 알 수 있다.

캐시가 없는 상태에서는 총 63개의 구성 요소를 다운로드하고, 캐시가 있는 상태에서는 24개의 구성 요소를 다운로드한다. 네이버me 서비스는 화면 구성이 미려하면서도 많은 서비스를 이어 주기 때문에 기능도 많다. 그리고 대부분의 기능이 자바스크립트를 이용해 동적으로 반응하도록 구현돼 있다. 이런 서비스를 어떻게 해서 63개의 구성 요소만으로 구현해 HTTP 요청을 최소화할 수 있는지 살펴보겠다.
[^13]: 야후!에서 개발한 웹 페이지 성능 분석 도구다. YSlow는 야후!에서 정의한 규칙에 따라 등급을 나누어 최적화 결과와 최적화해야 하는 부분을 알려 준다. YSlow에 대한 더 자세한 내용은 http://yslow.org/를 참조한다.
CSS 스프라이트 기법 활용
좀 더 미려한 페이지를 만들려면 어쩔 수 없이 이미지를 사용해야 한다. 순수한 HTML 마크업만으로는 표현에 한계가 있기 때문이다. 대신 이미지를 많이 사용하면 HTTP 요청이 많아질 수밖에 없다. 이미지를 많이 사용하면서도 HTTP 요청을 최소화하는 방법 가운데 하나가 CSS 스프라이트 기법이다.
CSS 스프라이트 기법은 이미지 여러 개를 하나로 만들고 스타일시트에서 background-position 속성을 설정해 필요한 부분의 이미지만 보여 주는 기술이다. 여러 이미지를 하나의 이미지로 합치기 때문에 HTTP 요청 횟수를 줄일 수 있고, 이미지의 컬러 테이블과 같은 메타 데이터를 하나로 합칠 수 있어 파일 크기가 줄어든다.
하나로 합친 CSS 스프라이트 이미지를 사용할 때는 다음 예제와 같은 형식으로 스타일시트를 작성한다.
/* CSS 스프라이트용 이미지를 설정한다.*/
.menu_list li a{background:url(https://example.com/some.png) no-repeat}
/* background-position 속성의 왼쪽과 위쪽 기준을 설정해 보여 줄 이미지를 지정한다. */
.menu_list a.me{background-position:0 0} /* 첫 번째 아이콘 */
.menu_list a.mail{background-position:0 -52px} /* 52픽셀 아래에 있는 두 번째 아이콘 */
...
...
CSS 스프라이트 기법은 구글이나 야후! 등 많은 웹 서비스에서 활용하고 있다. 다음 이미지는 구글에 적용된 CSS 스프라이트 이미지다.

네이버me에서도 CSS 스프라이트 기법을 활용하고 있다. 다음은 네이버me에서 사용한 CSS 스프라이트 이미지다.

CSS 스프라이트 기법은 이미지를 관리하기 어렵고 웹 접근성을 나쁘게 하는 요소가 있다는 단점이 있지만 구성 요소를 다운로드하는 시간을 크게 줄여 준다. 만약, CSS 스프라이트 기법을 사용하지 않았다면 그림 2-3의 이미지를 기준으로 60여 개의 이미지를 다운로드해야 한다. 이미지 하나를 받는 데 0.05초가 걸린다고 가정하면 60개의 이미지를 받는 데 총 3초라는 시간이 걸린다.
인터넷 익스플로러 8 버전의 동시 커넥션 수를 활용해 6개의 병렬 호스트에서 동시에 이미지 6개를 다운로드한다고 해도 60개의 이미지를 다운로드하려면 0.5초라는 시간이 걸린다. 그렇지만 CSS 스프라이트 기법을 활용하면 이미지를 1개만 다운로드하면 되기 때문에 단 0.05초만에 필요한 이미지를 다운로드한다.
웹 사이트를 개발하고 최적화한 경험이 있는 개발자라면 알겠지만 클라이언트에서 단 0.1초를 줄이는 것도 매우 힘든 일이다. 그럼에도 0.2~1초 차이에 사용자의 체감 속도가 달라지기 때문에 0.1초라도 줄여야 한다. 실제로 2008년에 네이버 메일 3.0을 개발할 때는 디자인 및 마크업 부서와 협업해 CSS 스프라이트 기법으로 응답 속도를 2~3초 정도 빠르게 개선했다. 네이버 메일 3.0 개선에 관한 자세한 내용은 “9. 메일 3.0 성능 개선 사례(271페이지)”를 참조하기 바란다.
CSS 스프라이트 제작 도구 N-MET
CSS 스프라이트 기법을 활용하기 위해 여러 이미지를 하나의 이미지 파일로 합치고, 각 이미지에 해당하는 스타일시트를 작성하는 것이 쉬운 일은 아니다. NHN에서는 N-MET(NHN Markup Enhancement Tool)이라는 도구로 비효율적이고 반복적인 마크업 개발 업무를 빠르게 처리하는데, CSS 스프라이트 이미지도 이 도구로 처리한다. N-MET의 CSS Sprites Generator가 CSS 스프라이트 이미지를 처리하는 도구다.
CSS Sprites Generator를 활용하면 여러 개의 이미지를 하나의 CSS 스프라이트 이미지로 만들어 낼뿐더러 관련된 스타일시트 파일도 만들어 낸다. 또한 각 이미지의 좌푯값 정보를 저장하기 때문에 CSS 스프라이트 이미지를 쉽게 수정하고 새로운 이미지를 추가할 수 있다.
N-MET는 http://html.nhndesign.com/markup_tools/nmet에서 무료로 공개하고 있으므로 누구나 다운로드해서 사용할 수 있다. N-MET과 CSS Sprites Generator에 대한 자세한 내용과 사용 방법은 http://html.nhncorp.com/N-MET/guide_public/#csg 문서를 참조한다.
헤더에 만료 날짜 추가
헤더에 만료 날짜를 추가하는 이유는 웹 페이지를 구성하는 이미지, 스타일시트 파일, 자바스크립트 파일 등을 사용자 컴퓨터의 캐시에 저장해서 재사용하기 위해서다. 사용자가 처음 웹 페이지에 방문하면 만료 날짜가 설정된 요소를 사용자 컴퓨터에 저장한다. 이후 같은 웹 페이지에 다시 방문하면 유효한(파일의 내용이 바뀌지 않고 사용 가능한) 요소는 서버에 요청하지 않고 사용자 컴퓨터에서 바로 읽어 온다. 이로 인해 상당히 많은 HTTP 요청을 줄여 웹 페이지의 성능을 향상시킬 수 있다.
사용자 컴퓨터에 저장된 캐시 파일
만료 날짜 설정에 대해 좀 더 깊이 알기 위해서 사용자 컴퓨터에 저장된 파일을 살펴보겠다. 따로 설정하지 않았다면 C:\Documents and Settings{User}\Local\Settings\Temporary Internet Files 디렉터리에 캐시 데이터가 있다. 또는 인터넷 익스플로러 8을 기준으로 임시 인터넷 파일 및 열어본 페이지 목록 설정[^14] 메뉴에서 도구 > 인터넷 옵션을 선택한 다음 일반 탭의 검색 기록에서 설정 버튼을 클릭하면 대화 상자가 나타난다.

[^14]: 메뉴에서 도구 > 인터넷 옵션을 선택한 다음 일반 탭의 검색 기록에서 설정 버튼을 클릭하면 대화 상자가 나타난다.
대화 상자에서 파일 보기 버튼을 클릭하면 캐시에 저장된 요소를 살펴볼 수 있다.
다음 그림은 캐시에 저장된 요소의 예다.

캐시에 저장된 파일에는 만료 날짜가 없는 파일도 있고 만료 날짜가 있는 파일도 있다. 모든 구성 요소에 무조건 만료 날짜를 설정하는 것이 아니라 특정 기간까지 변경되지 않아도 서비스에 문제가 없는 요소에만 적용해야 한다. 주로 페이지 디자인을 위한 이미지나 스타일시트 파일, 자바스크립트 파일 등이 여기에 해당한다.
만약, 만료 날짜 전에 수정 사항이 있어 파일을 변경해야 한다면 파일 이름을 변경하거나 파일 이름 뒤에 쿼리스트링을 추가해 새로 추가된 파일임을 알려야 바로 반영된다. 예를 들어 some.js 파일에 수정 사항이 있고 바로 반영해야 한다면 다음과 같이 파일 이름이나 쿼리스트링을 변경한다.
//방법1: 파일 이름을 변경한다.
<script type="text/javascript" src="some_20120622.js"></script>
//방법2: 쿼리스트링을 추가한다.
<script type="text/javascript" src="some.js?20120622"></script>
브라우저에서 캐싱된 파일을 이용할지 서버에 요청할지 판단하는 기준은 그림 2-5의 칼럼 이름을 기준으로 이름과 인터넷 주소다. 그렇기 때문에 위와 같이 작업해서 파일 이름이나 파일의 주소를 바꾸지 않으면 계속 같은 파일로 인식하고 사용자 컴퓨터에 있 는 파일을 로딩한다.
만료 날짜 설정과 확인 방법
만료 날짜 설정은 웹 서버에서 처리하는 내용이기 때문에 간략하게 설명하겠다. 아파치 웹 서버에서 만료 날짜를 설정하려면 mod_expires 모듈[^15]이 필요하다. mod_expires 모듈을 설치한 다음 httpd.conf 파일을 수정해 만료 날짜를 설정한다. httpd.conf 파일의 ExpiresActive 키워드로 만료 날짜 설정을 활성화하거나 비활성화한다. 특정한 파일 형식에만 만료 날짜를 부여하려면 ExpiresByType 키워드를 활용한다.
만료 날짜가 올바르게 설정됐는지는 HttpWatch로 확인할 수 있다. HttpWatch를 사용하면 각 요소의 헤더 정보를 보여 준다. 다음 그림은 네이버 모바일(http://m.naver.com/) 페이지에 있는 이미지 파일의 헤더 정보를 HttpWatch로 확인한 내용이다.

만료 날짜가 1년 후(2013년 6월 25일)로 설정돼 있다. 즉 사용자가 캐시 파일을 지우기 전까지는 1년 동안 계속 캐시 파일을 읽는다.
만료 날짜를 설정하면 어떤 효과를 볼 수 있는지 YSlow로 확인해 보자. 다음 그림은 네이버 모바일 페이지를 YSlow로 검사한 결과다. 캐시가 없는 첫 방문에서는 24개의 HTTP 요청을 처리해야 하는데, 캐시가 있는 다음 방문에서는 HTTP 요청을 3개만 처리했다.
[^15]: mod_expires 모듈과 사용법에 대한 자세한 내용은 http://httpd.apache.org/docs/2.2/mod/mod_expires.html을 참조한다.

스타일시트 파일, 자바스크립트 파일, 심지어 일정 간격으로 변하는 콘텐츠에 포함된 이미지에도 만료 날짜를 설정해 얻은 성능 개선 결과다. 모바일 환경의 네트워크 상태는 PC 환경보다 불안하기 때문에 더 중요한 성능 개선 요소라고 할 수 있다.
자바스크립트 파일 통합
시간이 지남에 따라서 웹 서비스의 기능은 날로 향상되고 있다. 기능이 향상됨에 따라 자바스크립트 파일은 개수도 많아지고 크기도 커지고 있다. 특히 네이버에서 서비스하는 메일, 캘린더, N드라이브, 포토앨범과 같은 도구형 서비스는 모든 UI를 자바스크립트로 구현하기 때문에 성능 향상에 어려움이 많다. 이럴 때 성능을 높이는 방법은 여러 개의 자바스크립트 파일을 하나의 파일로 합쳐 파일 개수를 최소화하는 것이다.
2008년 네이버 메일 3.0을 개발할 때 자바스크립트 파일의 개수는 무려 60개 정도였고, 캐시를 비운 상태에서 자바스크립트 파일을 로딩하는 데만 3초 이상의 시간이 걸렸다. 이 파일을 모두 합치고 최소화해 단 0.15초 만에 로딩하도록 성능을 개선했다.
네이버 메일 3.0의 사례에서 보듯이 웹 사이트의 성능을 개선할 때에는 파일의 용량보다 파일의 개수가 더 중요하다. 아주 용량이 작은 파일라도 원격 서버에서 가져와야 한다면 네트워크 비용이 든다. 파일이 캐시에 있더라도 해당 파일이 유효한지 판단해야 한다. 또한 병렬로 다운로드하는 데 한계가 있기 때문에 파일의 개수가 늘어나는 것은 성능에는 치명적이다.
다시 강조하지만 웹 페이지의 성능을 높이는 제일 좋은 방법은 파일의 개수를 줄여 HTTP 요청을 최소화하는 것이다.