앞서 얘기한 것처럼 본 프로젝트의 배포 환경은 그야말로 ‘극한의 환경’이라고 할 수 있을 것이다. 다시 한번 배포 환경에 대해 정리하자면 다음과 같다.
환경 | 메모리 |
---|---|
EC2 (t2.micro) | 1024MiB |
API Gateway 컨테이너 | 128MiB |
Integrated Services 컨테이너 | 256MiB |
Direct Message Service 컨테이너 | 256MiB |
Drive Service 컨테이너 | 320MiB |
총합 | 960MiB |
단순히 각 서비스 컨테이너가 사용하는 메모리 뿐만 아니라 Host 예약 메모리까지 고려하면 실제로 가용한 메모리 용량은 64MiB(1024MiB - 960MiB) 이하이다. 실제로 EC2 인스턴스에 SSH 접속하여 예약 메모리 값을 확인해보자.
$ ps --sort=-rss -eo pid,comm,rss
PID COMMAND RSS
363963 java 239592
224454 java 118956
176970 java 93272
220656 java 77000
3758 dockerd 37028
1095 systemd-journal 35092
3747 containerd 17768
369342 systemd 12844
363903 containerd-shim 10132
2152 amazon-ssm-agen 9660
369324 sshd 9324
224392 containerd-shim 9140
220596 containerd-shim 8348
1 systemd 8108
369427 sudo 7660
176912 containerd-shim 7480
371540 systemd-userwor 6652
371662 systemd-userwor 6644
371661 systemd-userwor 6616
369397 sshd 5524
369431 bash 4924
369430 su 4284
369398 bash 4196
1966 systemd-logind 2840
1763 systemd-udevd 2728
369365 (sd-pam) 2632
371674 ps 2624
1862 systemd-resolve 2556
1971 systemd-network 2548
369429 sudo 2472
363881 docker-proxy 2100
363886 docker-proxy 2060
1965 systemd-homed 1716
2156 sshd 1208
3620 systemd-userdbd 1008
1866 auditd 648
1957 dbus-broker 640
224377 docker-proxy 584
224372 docker-proxy 496
1961 lsmd 392
1999 gssproxy 376
1963 rngd 348
1956 dbus-broker-lau 320
2185 chronyd 196
1958 systemd-inhibit 80
176880 docker-proxy 80
2163 atd 56
2167 agetty 24
2168 agetty 12
위의 결과를 보면 java 명령어가 실행되는 컨테이너 당 containerd-shim
프로세스가 실행되고 있고, 각 containerd-shim
프로세스는 약 7 ~ 10MiB의 메모리를 추가로 사용하고 있다.
그리고 아래 명령어를 통해 각 서비스 컨테이너가 현재 사용 중인 메모리 사용량을 보자.
$ docker stats zylo-integrated-services zylo-drive-service zylo-api-gateway zylo-chat-service --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
db0a13e292c5 zylo-integrated-services 0.10% 230.6MiB / 256MiB 90.09% 54.7kB / 58.6kB 86.7MB / 58.5MB 35
a5f47ed2050f zylo-drive-service 0.08% 116.8MiB / 320MiB 36.49% 205MB / 24.8MB 272MB / 510MB 50
87c72833c92d zylo-api-gateway 0.06% 69.36MiB / 128MiB 54.18% 10.7MB / 13.7MB 413MB / 1.15GB 24
b252c374c701 zylo-chat-service 0.06% 91.74MiB / 256MiB 35.84% 275MB / 53.8MB 590MB / 817MB 50
docker stats
명령어를 통해 확인된 각 서비스 컨테이너가 사용 중인 메모리가 ps
명령어 결과와는 사뭇 다르다. 이는 docker stats
명령어가 아래처럼 page cache 값을 제외하고 실제 점유 중인 메모리만 표시하기 때문이다. 여기서 memory_stats.usage_in_bytes
는 cgroup
이 보고하는 전체 메모리 사용량이며 memory_stats.stats.total_inactive_file
이란 reclaimable(돌려받을 수 있는) page cache를 말한다(Docker Docs > 첫번째 Note 및 cgroup Document 참고).
displayed_usage = memory_stats.usage_in_bytes − memory_stats.stats.total_inactive_file
<aside> 💡
Page cache란?
하드 드라이브에 저장된 파일의 캐시를 저장하는 RAM의 일부분. 주로 OS 커널이 사용한다.
cgroup?
Linux 커널이 제공하는 기능 중 하나. 컴퓨터의 자원(CPU, 메모리, 디스크 I/O 등)을 프로세스에 할당하는 역할을 담당한다.
</aside>
이 때문에 docker stats
의 결과와 ps
의 결과가 상이한 것이다. 여기서 우리가 알 수 있는 부분은, 각 서비스 컨테이너가 사용하는 메모리는 docker stats
명령어를 통해 표시되는 것보다 크다는 것이다. 뿐만 아니라 OOM 킬은 page cache를 포함한 메모리 사용량을 기준으로 트리거(trigger)된다.
결론적으로, 실제 사용 중인 메모리는 다음과 같다.
구성 | 메모리(MiB) |
---|---|
예약 메모리 | ≈ 187 |
컨테이너 4종 | |
API-Gateway | 128 |
Integrated-Svc | 256 |
Direct-Msg-Svc | 256 |
Drive-Svc | 320 |
컨테이너 오버헤드 (containerd-shim 등) |
≈ 34 |
컨테이너 페이지 캐시 | ≈ 40 |
컨테이너 합계 | ≈ 1034 |
총 예상 소비 | ≈ 1221 |
따라서 최종적으로 정리하면 다음과 같다
<aside> 💡
containerd-shim
등)를 포함하여 약 260 MiB결론
t2.micro EC2 인스턴스가 제공하는 1024 MiB 크기의 메모리보다 약 200 MiB가 더 필요하므로 메모리 최적화가 필요하다.
</aside>