일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- aws
- 정보처리기사실기 기출문제
- 티스토리챌린지
- AI
- kotlin
- golang
- tucker의 go 언어 프로그래밍
- kotlin coroutine
- 정보처리기사 실기 기출문제
- Java
- minikube
- 코틀린 코루틴의 정석
- APM
- 공부
- kotlin querydsl
- 오블완
- CKA
- Spring
- AWS EKS
- docker
- Pinpoint
- PETERICA
- Kubernetes
- Elasticsearch
- 기록으로 실력을 쌓자
- CloudWatch
- mysql 튜닝
- go
- CKA 기출문제
- Linux
- Today
- Total
피터의 개발이야기
[GO] Too many open files 에러 트러블슈팅 본문
ㅁ 들어가며
Go에서 Too many open files
에러가 발생하여 이 문제를 공부한 내용을 정리해보았다.
ㅁ Too many open files 에러?
Too many open files 에러는 일반적으로 파일 디스크립터(File Descriptor, FD) 제한 초과로 발생하며, 주로 네트워크 연결이나 파일 핸들이 제대로 닫히지 않아 누적될 때 나타난다.
ㅁ 증상
go를 이용하여 hls 서비스를 운영 중이다. ffmpeg을 cmd.execute하여 맵으로 관리하는데, 해당 프로세스가 구동되면서 Too many open files가 발생하고 있었다. 프린트스택처럼 구체적인 에러 라인을 찾을 수 없어서 구체적인 원인을 분석 중이다.
ㅁ 에러 발생 주요 원인
ㅇ 파일 디스크립터(FD) 누수: HTTP 연결, 파일 핸들, DB 커넥션 등이 명시적으로 닫히지 않아 누적됨.
ㅇ 시스템 FD 제한 초과: 기본값(ulimit -n)인 1024를 초과하는 동시 연결 발생.
ㅇ 병렬 처리 과부하: 고루틴 무분별한 생성으로 FD가 급증.
ㅁ FD 누수 확인 방법
ㅇ 실시간 모니터링
# 프로세스별 FD 사용량 추적
watch -n 1 "ls /proc/<PID>/fd | wc -l"
# FD 유형 분석
lsof -p <PID> | awk '{print $5}' | sort | uniq -c
ㅁ prlimit 결과 분석
$ sudo prlimit -n --pid 4033763
RESOURCE DESCRIPTION SOFT HARD UNITS
NOFILE max open files 1073741816 1073741816 files
ㅇ SOFT/HARD 제한 무제한: RLIM_INFINITY로 설정되어 FD 누수가 즉각적 오류로 이어지지 않을 수 있음.
구체적으로 영향도 있을 만한 부분을 점검해 보았다.
ㅁ os.Stat(path)의 영향도
ㅇ 직접적 FD 소모 없음
ㅇ 간접적 영향 가능성?
// Bad: 루프 내에서 os.Open 후 Close 누락
for _, path := range paths {
os.Stat(path) // 문제 없음
f, _ := os.Open(path) // FD 누수 발생
}
ㅇ os.Stat은 파일 메타데이터만 접근하며, 실제 파일을 열지 않는다.
ㅁ FFmpeg 실패와 FD 연관성
ㅇ OSError: [Errno 24] Too many open files When calling get_data in reverse order #212
ㄴ ffmpeg의 실패와 연관성을 의심하게 했던 자료이다.
ㄴ Python library for reading and writing image data
ㅇ 직접적 영향: FFmpeg 비정상 종료 시 열린 소켓/파일 미해제 → FD 누적 가능.
ㅇ 추적 방법
# FFmpeg 프로세스 FD 추적
lsof -p $(pgrep ffmpeg) | grep "TYPE"
ㅁ fsnotify를 이용한 반복적 감시설정 영향도
ㅇ 단일 Watcher 사용 시: 동일 경로 반복 추가가 FD에 미치는 영향은 없다.
- inotify 인스턴스당 1개의 FD를 사용한다.
- Watcher 인스턴스 생성 시 이 FD가 할당되며, 감시 대상 경로 추가(Add())는 내부적으로 **watch descriptor(wd)**를 관리한다.
watcher, _ := fsnotify.NewWatcher()
watcher.Add("/tmp") // wd1 생성
watcher.Add("/tmp") // 기존 wd1 재사용
ㅇ 동일 경로 & 동일 이벤트 마스크로 추가하면 새 wd가 생성되지 않는다.
ㅇ여러 Watcher 인스턴스 생성 경우
- 인스턴스 수가 FD 제한을 초과하지 않도록 주의해야 한다.
for i := 0; i < 1000; i++ {
watcher, _ := fsnotify.NewWatcher() // 매번 새로운 FD 생성
watcher.Add("/tmp")
}
ㅇ 각 Watcher 인스턴스는 별도 FD를 소모하므로, FD 제한(ulimit -n)을 초과할 수 있다.
for i := 0; i < 1000; i++ {
watcher, _ := fsnotify.NewWatcher() // 매번 새로운 FD 생성
defer watcher.Close() // 반드시 호출
watcher.Add("/tmp")
}
ㅇ Watcher 인스턴스에 대한 Close를 적용해야한다.
ㅇ 간의로 코드를 작성해서 테스트를 수행해 보았다.
ㅇ failed to create new OS thread 에러만 확인할 뿐이었다.
ㅁ 마무리
해결점을 찾지 못하였다. ㅜㅜ 다만, 특정 클라이언트가 이미 몇분 지나 만료된 ts파일을 초당 8~9건씩 몇시간씩 요청하는 로그를 발견하였다. 해당 api(get)를 호출하면서 ffmpeg이 불안정해지고, 종료되어 다시 시작하지만 FD의 영향으로 기동되지 못하였다. 그래도 배운 것이 있다.
ㅇ 자원 관리 철칙: Open
후 반드시 Close
를 명시적으로 호출 해야함.
ㅇ 모니터링 문화 정착: lsof
, prlimit
을 이용한 주기적 점검도 필요하다.(어디서 누수가 되는지 모르니...)
ㅁ 함께 보면 좋은 사이트
ㅇ Linux에서 "열려 있는 파일이 너무 많음" 오류를 해결하는 방법
ㅇ defer f.Close() and "too many open files"
ㅇ OSError: [Errno 24] Too many open files When calling get_data in reverse order #212
ㄴ ffmpeg processes fail to close properly, causing an OSError: [Errno 24] Too many open files error.
ㅇ [Golang] too many open files 에러 해결
ㄴ defer resp.Body.Close()
'Programming > GO' 카테고리의 다른 글
[GO] Tucker의 GO 언어 프로그래밍 - 목차 (0) | 2025.03.31 |
---|---|
[GO] Tucker의 GO 언어 프로그래밍 - 18장 인터페이스 (0) | 2025.03.30 |
[GO] 인터페이스와 제네릭의 차이점은? (0) | 2025.03.28 |
[GO] Tucker의 GO 언어 프로그래밍 - 24장 제네릭 프로그래밍 (0) | 2025.03.27 |
[GO] Tucker의 GO 언어 프로그래밍 - 23장 채널과 컨텍스트 (1) | 2025.03.26 |