Tag Archives: varnish

Varnish 2.0 (웹캐시, 리버스프록시)

Varnish Cache에 대해서 글을 올린지 얼마 안된 듯한데 찾아보니 3년정도가 지났네요. 아직까지 실제 서비스 환경에서는 Varnish를 도입하지 못했었는데… 다시 필요에 의해서 로드밸랜서(+서버단 캐시)를 고려하게 되었습니다.

원래 수동으로 서브도메인별로 나누어서 로드밸런싱을 하고 있었는데, 서브도메인간 자바스크립트 연동의 문제들이 여러곳에서 발생하기 시작해서, 로드밸런서를 도입하려고 합니다. 그외에도 여러가지 장점이 있을듯 하네요.

Varnish가 이제 버전 2.0이 나왔고(나온지 1년 됐네요 –), 여러가지 변화가 있었네요.
현재 버전은 2.0.4 입니다.

1. VCL 언어가 좀더 프로그래밍 언어 다워졌습니다.

VCL 언어가 약간 언어답지 않은 면이 있었는데.. return 등의 도입으로 좀더 설정파일(소스) 보기가 편해졌습니다. 그리고 C언어를 embedding 할수 있는 방법이 있네요.

2. grace 지원

개체(요청결과)를 캐싱할때 expire 시간과 함께 grace 시간을 설정할수 있습니다. expire 시간이 지나고 웹서버(backend)들이 요청 처리를 하지 못할때 grace 시간 동안 캐시에 있는 내용으로 서비스가 됩니다. 또한 expire 시간이 지나는 순간 하나의 웹서버에 하나의 요청만으로 캐시를 업데이트하며 그 동안은 캐시에서 서비스가 되도록 설정할수 있습니다. 예를 들면 메인 페이지가 1초에 100번 요청되고 메인 페이지 처리하는데 2초가 걸린다고 하면, 서버에 원래 200번 요청 들어갈것이 1번만 가면 되는거죠. 웹서버와 디비 입장에서 아주 고마운 일이죠.

3. ESI (Edge Side Script) 일부 지원

 페이지에서 특정 부분은 사용자 정보가 포함되기 때문에 전체 페이지 캐싱이 어려운 경우가 많습니다. 사용자 별로 캐시를 두면 캐시의 의미가 많이 떨어집니다. 이럴 경우 해당 부분만 별도의 페이지로 저장해두고

<esi:include src=”userinfo.php” />

형태로 원본 페이지에 넣어주면 캐시에 그대로 저장되고, 요청을 처리할때 userinfo.php 부분만 웹서버에 요청하여 varnish에서 조합해서 보내줍니다.

ESI가 아주 유용한 기능이기는 하지만 아쉬운 점은 Varnish가 아직 압축을 지원하지 못한다는 점이네요. 웹서버 측에서 페이지를 압축하면 ESI를 쓸수 없고, Varnish 쪽에서 압축할수 있는 방법을 지원하지 않습니다. ESI와 압축을 조합해서 쓸수 있었으면 정말 좋았을텐데 정말 아쉬운 부분이네요.

현재 회사에서 varnish 도입을 위한  테스트중입니다. ESI는 압축 미지원으로 도입에서 제외되었으며, 로드밴런싱, 캐싱 기능, 서버 죽을때 처리 등만 활용하려고 합니다.

grace의 개념을 이해하면서, memcached를 웹에서 사용하는 방법을 비슷한 방법으로 변경을 고려하고 있습니다.

PHP 모든 페이지를 캐싱하기는 로직상으로 문제가 발생할 확률이 커서 정해진 HTTP 헤더가 포함된 PHP 페이지만 캐싱 되도록 설정했습니다. 캐싱해도 안전하다고 생각하는 페이지에 특정 헤더를 포함하면 캐싱이 됩니다.

url.purge 명령으로 정규식에 해당하는 캐싱된 페이지를 날릴수 있는 기능도 활용할 생각입니다. 캐싱이 유용한 페이지이지만 사용자가 글을 등록하고 바로 글이 안보인다던지 하는 문제는 url.purge를 써서 해결하려고 합니다.

Varnish Cache 소스로부터 배우기

요즘 Varnish Cache를 본격적으로 도입하기 위해서 노력중입니다. 설계 문서를 보면 많이 사용하는 Squid는 70/80년대 하드웨어에 적합하게 설계되었기 때문에 요즘 하드웨어에서는 퍼포먼스가 아주 많이 떨어진다는 흥미로운 얘기가 있습니다.

Squid에서는 소프트웨어적으로 캐시를 따로 구현해서, 커널에서 메모리 관리하는 것과 같이 잘 동작하지 않는다고 합니다. 소프트웨어적으로 캐시를 따로 구현하면 필요하지 않은 메모리 영역을 swap out할때, 똑똑한 커널에서 이미 swap out됐던 데이터를 메모리 영역으로 불러왔다가 다시 swap out 하는 과정이 일어난다고 합니다. 옛날 OS에서는 메모리 관리가 최적화가 안되어있었지만 요즘은 메모리 관리를 커널에서 알아서 하게 하면 퍼포먼스가 많이 빨라진다고 하네요.

Varnish Cache 최적화는 크게 3가지 정도로 요약할수 있을거 같습니다.

1. 메모리 관리를 커널에 위임
2. 메모리 할당/해제 부분을 최소화 (workspace 단위 할당, 한번에 해제)
3. 설정 파일 컴파일러로 컴파일

메모리 관리는 mmap을 통해서 관리합니다. 파일 시스템 영역과 메모리 영역을 연결하여 사용하고, storage_file.c에서 직접 메모리 쪼개서 관리합니다. 메모리 영역을 쪼개서 free list(VTAILQ)에 넣고, 할당할때 free list에서 꺼내서 쓰는 방식입니다. 프로그램에서는 무엇이 메모리에 있고, 파일로 swap 할지 결정하지 않고 커널이 하도록 내버려둡니다.

메모리 할당은 workspace 단위로 하고 그 안에서 쪼개서 쓰는 거 같습니다. 이 부분은 좀더 분석이 필요할거 같습니다.

설정 파일은 c로 변경한 다음 저장하고, 직접 cc를 호출해서 오브젝트 파일을 생성하며, dlopen으로 로드하게 되어있습니다.  mgt_vcc.c의 mgt_CallCc 함수를 참고하세요. dlopen을 사용하기 위해서 컴파일러에 -fpic -shared 등의 옵션을 넘기게 되어있습니다.

Varnish의 개발자가 FreeBSD 커널 개발자 출신입니다. 지금도 개발하는지는 모르겠네요..Varnish는 정말 BSD커널 소스처럼 짜놨네요. BSD 커널 소스보면 데이타 구조가 대부분 queue.h로 되어있는데, 여기서도 VTAILQ 등으로 이름만 조금 바꿔서 사용하고 있습니다. queue.h는 여러가지 데이타 구조를 C 매크로만으로 구현한 헤더파일 라이브러리입니다. 구현할때 struct 안에 포인터가 내장되서 여러가지 방법으로 메모리 사용을 최적화할수 있습니다. 커널에서는 대부분 블럭단위로 메모리 할당하여, 그걸 쪼개서 free 리스트에 넣어놓고 그걸 꺼내써서 사용하는 방식으로 메모리를 관리합니다. 메모리 할당과 해제가 간단한 포인터 연산으로 끝나기 때문에 매우 효율적이고, 메모리 fragmentation도 많이 줄여줍니다. 메모리 할당과 해제가 자주 일어나는 경우 아주 큰 도움이 되죠.

2000년에 FreeBSD에서 방화벽 커널 모듈을 개발한 적이 있었는데, 메모리 관리를 queue.h와 “Redesigning the BSD Callout and Timer Facilities (1995)”를 참고해서 구현했었습니다. 퍼포먼스 최적화에 아주 큰 도움이 됐었습니다. Redesigning the BSD Callout… 논문을 어떻게 알게 되었는지는 기억은 안나지만, 정말 많은 도움을 받았던 논문이네요. 지금 찾아보니 첫번째 저자는 구글에 있고, 두번째 저자는 벤처 만들었다가 시스코에 인수됐다고 하네요. 지금은 UCSD 교수로 있네요. 이 논문에 대해서는 블로그에 글을 한번 정리해서 올리도록 노력하겠습니다.

Varnish Cache Project & 웹서버 최적화

웹 프로그래밍을 전문적으로 하고 있지는 않으나, 서비스에 사용자가 많이 늘면서 여러가지 기술들을 찾고 있는데, 아직 본격적으로 적용은 못했으나 관심을 갖아볼 만한 프로젝트입니다. Varnish는 웹캐시로 웹속도를 줄이기위한 방법중 하나로 Reverse Proxy 역할을 위주로 설계됐습니다. 많이 쓰이는 Squid라는 프록시는 클라이언트 단에서 서버에서 오는 정보를 캐싱하여 클라이언트 단에서의 접속 속도를 향상시키는 역할이 주인 (Forward) Proxy로 주로 쓰입니다. 반면 Reverse Proxy는 서버단에 가까운곳에 위치하여 서버에서 나오는 데이타를 캐싱하여 서버의 부하를 줄이는 역할을 하며, 주로 동적으로 생성되는 페이지가 많을 경우 효과를 볼수 있습니다.

Varnish는 효율성을 위해서 C로 짜여져 있으며, VCL이라는 언어로 설정이 가능합니다. VCL은 간단한 언어로 오브젝트 파일로 컴파일되어 데몬에서 호출되는 등 빠르게 동작할수 있도록 최적화에 신경을 많이 썼습니다. 주 개발자는 FreeBSD 커널 여러부분에서 작업해서 OS에 대한 이해도가 높고, 기존에 있던 캐싱 시스템들이 옛날 하드웨어 맞게 최적화되어 개발되어 있기 때문에 오히려 요즘 처럼 여러단계로 메모리가 캐싱되는 하드웨어 상황에서는 적합하지 않다고 얘기합니다.

홈페이지는 http://varnish-cache.org/ 이며, FreeBSD에서는 /usr/ports/www/varnish 에서 설치할수 있습니다.

회사 서비스 중 웹서버에 많은 부하가 집중되어 있었는데 많은 부분 해결이 되었습니다. 해결을 위해 동원된 방법은…

  • SQL 쿼리 최적화
  • PHP에서 필요한 부분만 include (main include 파일이 커져서)
  • 랜더링 오래 걸리는 페이지 memcache에 캐싱
  • 잘 변하지 않는 페이지 html로 저장
  • 웹서버 Apache에서 lighttpd로 변경
  • xcache 적용 (코드 캐시만 사용)

동시 연결된 클라이언트가 급속히 늘다보니 아파치 1.3에서는 mod_php는 메모리가 너무 많이 차지하여 한계가 생겼었습니다. 당시 php 처리도 느렸었지만, lighttpd에 fastcgi로 바꾸고 나서는 메모리 사용량이 현저히 줄었습니다. xcache는 php 컴파일된 코드를 메모리에 캐싱하는 모듈로 적용후 php의 부하를 많이 줄일수 있었습니다. xcache에서 memcache와 동일한 기능도 제공합니다. 그외에 pen이나 plb등의 S/W load balancer 도입도 생각하고 있으며, lighttpd의 fastcgi load balancing도 고려하고 있습니다.