Virtualization 101 - (3.1) 메모리 오버커밋과 메모리 여유공간 확보 방법

송주환·2023년 4월 21일
0

Virtualization 101

목록 보기
4/6
post-thumbnail

이번 포스팅에서는 직전의 메모리 가상화 파트에서 다루지 못했던 내용인 메모리 오버커밋과, 가상화 환경에서 메모리 압박(Memory pressure)을 핸들링 하는 방법을 알아본다.
예시로는 vSphere 환경을 사용할 것이나, 이론적인 내용은 다른 솔루션에서도 범용적으로 적용할 수 있다.

메모리 오버커밋 (Memory Overcommit)

직전 포스팅에서 페이징 기법을 소개하며 '온 디맨드 페이징'이라는 개념을 소개했다. 프로그램이 처음부터 전체 메모리 공간을 점유하는 것이 아니라, 자신이 그 순간에 사용하는 만큼의 메모리만 할당받으면 된다는 것이다.
가상화 환경에서는 이 개념이 가상머신까지 확장된다. 가상머신은 '자신이 사용하고 있는' 메모리 공간만을 점유하면 되는 것이다. 따라서 시스템이 가지고 있는 물리 메모리보다 더 큰 가상 메모리(vMem)를 프로비저닝 할 수 있고, 이것을 메모리 오버프로비저닝(Overprovisioning) 또는 오버커밋(Overcommit) 이라 부른다.

하지만 널리 사용되는 CPU 오버커밋과는 달리, 메모리 오버커밋은 자주 사용되지 않는다. 왜냐하면 CPU 오버커밋 대비 감수해야 하는 성능 저하 폭이 아주 크고, 특정 운영 환경에서는 서비스 중단을 일으킬 수도 있기 때문이다. 그래서 메모리 오버커밋이 가져올 수 있는 잠재적인 이점에도 불구하고 대부분의 사용자들은 1:1의 비율로 VM의 메모리를 할당한다.

메모리 압박 (Memory Pressure)

그런데, 만약 메모리가 오버 프로비저닝 된 환경에서 사용 가능한 물리 메모리 용량이 부족해진다면 어떻게 될까?
이러한 메모리 오버커밋 환경에서의 동작을 보증해주기 위해, VMware vSphere는 여러 종류의 메모리 관리 기법을 도입하였다.

TPS (Transparent Page Sharing)

TPS는 '동일한 OS를 실행중인 VM 간에는 동일한 내용을 가진 메모리 페이지가 많을 것이다' 라는 가정 하에 만들어진 기술로, 하이퍼바이저가 주기적으로 사용 중인 메모리 페이지들을 스캔하여 해시값이 서로 일치하는 페이지들을 중복 제거, 추가적인 메모리 공간을 확보한다.
TPS는 Guest OS에게 완전히 투명하며, 상시 동작하기 때문에 별도의 성능적 패널티가 거의 존재하지 않는다는 장점이 있다.

하지만, 값이 완전히 동일한 페이지만을 제거할 수 있기 때문에 메모리 용량 확보가 어렵고, 페이지 단위로 중복 제거를 수행하는 특성 상 페이지 크기가 커지면 hit rate가 낮아지고, 메모리의 용량이 커질수록 페이지를 스캔하고 비교하는 일에 필요한 리소스가 증가한다는 단점이 있다.

이러한 제약과, 캐시 사이드채널 어택이 대두되면서 드러난 취약점[1] 때문에 VMware는 vSphere 5.5 P04 부터 기본적으로 TPS 기능을 비활성화하였다.

TPS의 비활성화에 대한 보다 자세한 내용은 다음 KB에서 확인할 수 있다.
VMware KB - Security considerations and disallowing inter-Virtual Machine Transparent Page Sharing (2080735)

메모리 벌루닝 (Memory Ballooning)

하이퍼바이저가 메모리 압박을 받을 때 가장 먼저 동작하는 기술이 바로 메모리 벌루닝이다.
벌루닝은 가상 머신에 할당되었지만 실제로 사용되지는 않는 메모리 페이지를 회수하는 기법이다.
벌루닝 동작 시, 일반적으로 워크로드의 성능에 제한적인 영향을 미치며, 상대적으로 많은 메모리를 즉시 확보할 수 있을 가능성이 높다.

메모리 벌루닝의 기본 아이디어는 다음과 같다.

게스트 OS가 일단 메모리 페이지를 할당하고 나면, 실제로 그 페이지를 사용하지 않더라도 하이퍼바이저는 할당 상태를 유지해야 한다. 하이퍼바이저의 컨텍스트에서는 어느 페이지가 사용 중이고, 어느 페이지가 사용되지 않는지 알 수 없기 때문이다.
그러나, 하이퍼바이저가 벌룬 드라이버를 통해 메모리 페이지를 할당하면, 벌룬 드라이버가 할당한 페이지는 '회수 가능한' 페이지로 확정할 수 있다. 그 페이지들을 회수하여 하이퍼바이저의 메모리 압박을 해소할 수 있다.

그렇다면, 실제로 메모리 벌루닝은 어떻게 동작하는 것일까?

Balloon driver가 동작하는 방식은 다음과 같다

  • 하이퍼바이저가 Balloon driver에 백도어를 통해 target inflate size를 전송한다
  • Balloon driver는 주기적으로 하이퍼바이저의 리퀘스트를 모니터링 하다가 target inflate size 만큼의 페이지를 non-swappable page로 pinning 한다. 이 때, 할당받은 메모리의 PPN을 기록한다
  • Balloon driver가 pinning한 메모리가 증가하면, 하이퍼바이저의 메모리 압력이 게스트 OS 커널로 전가되면서, 게스트 OS 커널은 중요도가 낮은 것으로 평가되는 메모리 페이지를 해제하고, swap 공간으로 옮기는 것으로 메모리를 추가 확보한다
  • Balloon driver는 자신이 pinning 한 페이지를 해제하면서 PPN 값을 하이퍼바이저로 전달하고, 하이퍼바이저는 PPN -> MPN 변환을 통해 사용 가능한 페이지를 찾고, 다시 재할당한다

ESXi는 메모리 압력이 발생할 때, VM들을 대상으로 백도어를 통해 balloon driver의 동작 명령을 보낸다. 이 때, 고려해야 할 사항은 다음과 같을 것이다.

  1. 언제 balloon driver를 동작시킬 것인가?
  2. 어떤 VM의 balloon driver를 동작시킬 것인가?
  3. balloon을 얼마나 확장시킬 것인가?

1번에 대한 대답은 명확하다. VMKernel은 호스트의 사용 가능한 메모리의 양이 6% 미만으로 떨어질 때 벌룬 드라이버의 동작을 시작한다.

2번에 대한 명확한 답은 찾을 수 없었다. 하지만 하이퍼바이저가 유휴 메모리가 많은 VM을 Target으로 삼는다는 것을 확인할 수 있었다.
이 때, 유휴 메모리의 비율은 게스트에 할당된 페이지를 임의로 샘플링 한 뒤, 샘플 세트에 대한 페이지 폴트를 계측하는 식으로 간접적으로 유추한다.[2]

유휴 메모리 비율 계산을 위해 ESXi 하이퍼바이저는 기본적으로 VM별로 30초마다 100개의 샘플 페이지를 확인하며, 이 값은 변경할 수 없다.

또한 Ballooning이 동작하지 않는 조건을 추가로 확인할 수 있었다.[3]

  • vmmemctl이 존재하지 않는 경우 (=Balloon driver가 설치되지 않은 경우)
  • VMX에 sched.mem.maxmemctl = "0"을 추가한다
  • Host의 Mem.CtlMaxPercent가 0으로 설정된다

3번의 경우에도 하이퍼바이저의 동작은 명확하지 않으나, inflate 가능한 최대 메모리 크기는 기본적으로 VM에 할당된 메모리의 65%이다. 이 값은 Mem.CtlMaxPercent를 수정하는 것으로 변경할 수 있다.

Ballooning의 단점은 불필요한 swap-out과 그로 인한 성능 저하, 그리고 balloon driver로 인해 OOM Killer가 동작할 수 있다는 것이다.
Balloon driver의 메모리 할당 우선순위가 일반 응용 프로그램보다 더 높기 때문에, 현재 실행중인 응용의 페이지가 swap out될 가능성이 높고, 이것은 애플리케이션의 성능에 직접적인 영향을 준다.
더욱 치명적인 점은, OS 커널이 메모리 압박을 느끼고 OOM Killer를 동작시킬 수 있다는 것이다. 만약 서비스에 필요한 프로세스가 OOM Killer로 인해 종료된다면, 즉시 서비스 중단이 일어날 것이다.

이러한 단점 때문에 몇몇 사람들은 Ballooning을 비활성화 할 것을 권고하나, Ballooning이 동작하지 않는다 해서 Compression/Swapping이 동작하지 않는 것은 아니기 때문에, 가장 좋은 방법은 VM의 메모리를 미리 예약하여 모든 메모리 reclaim 기능이 동작하지 않게 하는 것이다.

메모리 압축 (Memory Compression)

Ballooning으로 충분한 메모리를 확보할 수 없었다면, 하이퍼바이저는 메모리 페이지를 압축하여 가용 메모리를 확보하려 시도한다.
압축은 메인 메모리 내부에서 일어나며, 디스크에 액세스하는 속도보다 압축된 메모리 페이지에 액세스하는 속도가 더 빠르기 때문에, 상대적으로 적은 오버헤드로 추가 메모리를 확보할 수 있다.
이 때, 메모리 압축 대상이 되는 페이지는 다음 조건을 만족해야 한다.

  • 디스크로 Swap-out 가능한 페이지
  • 50% 이상 압축할 수 있는 페이지

이 조건을 만족하지 않는 페이지는 하이퍼바이저 스와핑을 통해 디스크로 페이지 아웃된다.
메모리 압축 동작은 기본적으로 활성화되어 있으며, 호스트의 mem.memzipenable 옵션을 변경하여 비활성화 할 수 있다.
그리고 압축 가능한 메모리 크기의 기본값은 VM에 할당된 메모리의 10%로 설정되어 있으며, Mem.MemZipMaxPct 옵션으로 변경할 수 있다.

메모리 압축부터는 VM의 성능에 미치는 영향이 커지며, 더욱이 조건에 맞지 않는 페이지가 디스크로 페이지 아웃될 수 있다는 의미이기 때문에 실제 운영 환경에서는 압축이 일어나지 않도록 리소스 할당을 관리해야 한다.

하이퍼바이저 스와핑 (Hypervisior Swapping)

하이퍼바이저 스와핑은 말 그대로 VM에 할당된 페이지를 디스크로 swap-out 하는 것이다. 하이퍼바이저는 게스트 OS의 메모리 페이지 사용을 알 수 없기 때문에, 핫 페이지를 swap-out할 위험이 있으며, 게스트 OS가 페이지 아웃 한 페이지를 다시 페이지 아웃시키는 이중 페이징 문제가 일어날 수 있어 VM의 성능에 아주 큰 악영향을 미친다.

그렇기 때문에 하이퍼바이저 스와핑은 메모리 압력을 해소하기 위한 최후의 방법이며, 모든 VM들은 전원을 켜기 전, 데이터스토어에 이 동작을 위해 자신의 할당 메모리 크기 만큼의 스왑 공간을 예약해둔다.

번외로, 호스트에 SSD가 설치되어 있다면 Host cache를 설정할 수 있다.
Host cache는 swap 파일을 대신하지는 않지만, 하이퍼바이저 스와핑이 필요한 상황에서 지연시간이 더 낮은 SSD에 스왑 아웃된 페이지를 배치하는 것으로 성능 영향을 줄일 수 있다.

마치며

이상으로 vSphere ESXi에서 가용 메모리가 부족할 때 사용 가능한 메모리를 확보하는 방법을 알아보았다.
Memory reclaimation 기술들은 크건 작건 모두 오버헤드를 수반하며, 안정적인 운영 환경을 위해서는 애초에 메모리 압박을 느낄 정도로 메모리를 오버커밋 하지 않는 것이 좋다.

그리고 메모리 압박을 받아서는 안 되는 VM을 대상으로는, 처음부터 전체 할당 메모리를 예약하는 것이 Best Practice이다.

레퍼런스

[1] Wait a minute! A fast, Cross-VM attack on AES
[2] Memory Resource Management in VMware ESX Server
[3] Disabling the balloon driver (1002586)

profile
Virtualization / Network / Storage / Server Hardware and.. Linux

0개의 댓글