기타 Lobsters · 2일 전

465MB 저사양 서버 메모리 쥐어짜다 SQLite로 500배 느려진 썰

핵심 요약
  • 램 465MB 서버에서 IP 대역 조회 데이터가 117MB를 차지해 백업 스크립트가 강제 종료되자 메모리 다이어트에 돌입했습니다.
  • 디스크 기반 SQLite로 바꿨더니 메모리는 줄었지만 속도가 500배나 폭락하는 참사를 겪었습니다.
  • 결국 구조체 중복 제거와 가벼운 주소 타입 변경을 통해 기존 배열 구조를 유지하면서 70MB를 절감했습니다.
요약 'Mess With DNS' 서비스를 운영하는 개발자가 고작 465MB RAM에 불과한 저사양 가상머신(VM)에서 메모리 부족(OOM) 문제를 해결하기 위해 고군분투한 기술 최적화 삽질기입니다. 해당 서버는 평소 DNS 쿼리가 들어올 때 발신지 IP가 구글 등 어떤 ASN 소속인지 파악하기 위해 IP 데이터베이스 전체를 메모리에 올려두고 이진 탐색으로 조회하는 방식을 썼습니다. 원래 텍스트 파일(TSV) 크기는 IPv4와 IPv6를 합쳐 37MB 수준이었지만, Go 언어의 구조체 배열 형태로 인메모리에 로드되면서 약 117MB의 메모리를 차지하고 있었습니다. 전체 가용 램이 얼마 남지 않은 상황에서 최근 도입한 restic 백업 스크립트가 실행될 때마다 시스템 메모리가 고갈되어 OOM 킬러에 의해 백업이 강제 종료되고 수동으로 잠금을 풀어줘야 하는 번거로운 상황이 발생했습니다. 개발자는 디스크 기반의 SQLite 도입을 1차 시도로 검토했습니다. 데이터베이스를 디스크에 두고 쿼리하게 만들자 메모리 사용량은 즉각 줄어들었으나, 128비트 IPv6 주소를 문자열 형태로 저장해야 하는 스키마 문제와 더불어 조회 속도가 기존 초당 900만 건에서 초당 1만 7천 건 수준으로 무려 500배나 느려지는 한계에 부딪혔습니다. 이후 트라이(Trie) 구조 검토와 메모리 프로파일링을 거쳐, 결국 기존 배열 구조에서 국가명·이름 중복 제거와 더 가벼운 IP 주소 타입(netip.Addr) 교체 등을 통해 최종적으로 70MB의 메모리를 절감하는 데 성공했습니다.
Sponsored · 광고