두 글을 정리요약했습니다.
발생 현상
- AUIGrid(자바스크립트 라이브러리)를 사용하는 엑셀 다운로드 시 깨진 파일을 다운받음
- 그러나 백엔드 서버에서 해당 파일을 저장해둔 위치에 가서 파일을 열어보면 정상적으로 열리는 상태
- 다운로드 받은 파일(깨진 파일)과 정상 파일을 메모장으로 열어서 데이터 비교했을 때 파일이 쓰이다 만 것처럼 데이터가 들어가 있음 (깨진 파일은 데이터가 중간에 끊김)
발생 원인
- 파일이 중간에 깨진 이유는 디스크 쓰기 작업이 완료(flush)되기 전에 파일을 반환했기 때문에 발생
- 백엔드 서버의 로직을 봤을 때 해당 코드는 동기적으로 처리되어야 정상인데 왜 문제가 발생했는가?
- AIP 서버에서 파일 데이터를 수신하면, 해당 데이터는 먼저 메모리 내 커널 페이지 캐시에 저장됨
- 이 시점에서 쉘 스크립트 또는 PHP는 파일 쓰기 작업이 완료된 것으로 간주하고, 바로 다음 단계로 넘어감
- 하지만 flush가 디스크에 완전히 반영되기 전 프론트엔드에서 해당 파일을 다운로드 받아 문제가 발생
- 즉, 쓰기 지연(write-back) 상태에서 read가 먼저 발생해 깨진 파일을 받게 됨
해결 방안
- 3초 딜레이 적용
- AUIGrid에서 사용하는 백엔드 호출 로직(DrmService.php)에 sleep(3)을 추가하여 디스크 flush가 완료되도록 유도
- 쉘 스크립트 내에서 파일 디스크 flush 유도
- 반환받은 파일 데이터를 .tmp 확장자로 저장한 후, mv file.xlsx.tmp file.xlsx 방식으로 최종 이름 변경
- mv는 atomic rename 동작이기 때문에 flush 유도에 효과적
- Python fsync() 시스템콜 직접 호출
- python3 -c "f = open('${ORIGINAL_PATH}', 'rb+'); import os; os.fsync(f.fileno()); f.close()"
- 명시적으로 flush 요청을 보냄 (단, NFS 환경에서는 보장되지 않을 수 있음)
고려 사항
- 해당 문제는 운영 환경에서만 발생하며, 개발 환경에서는 재현되지 않음
- 운영 서버에서 직접 코드를 수정하거나 임시 로직을 삽입해 테스트할 필요가 있음
- 백엔드에서 생성하는 다른 엑셀 암호화 파일들도 동일한 문제의 가능성이 있음
- 단, 해당 로직은 후처리 과정이 존재해 자연스러운 딜레이가 발생했기 때문에 flush가 완료되었음
- Content-Length 기반 .done + mv 전략은, 상대 서버가 전송하는 파일이 반드시 바이너리 형식이며 Content-Length를 정확하게 명시한다는 전제를 필요로 한다. 하지만 상대 서버가 우리가 직접 구현한 것이 아니라면, 전송 형식이 base64, gzip, chunked encoding 등으로 바뀌거나 Content-Length가 부정확할 수 있기 때문에, 이 전략은 실질적으로 적용이 불가능하다고 판단하여 제외함.
NFS(Network File System)를 곁들인 저장소
쉘 스크립트나 Python을 통해 flush를 직접 유도했음에도 불구하고, 운영 환경에서는 여전히 깨진 파일이 다운로드되었음.
이를 확인한 결과, 해당 파일이 저장된 위치는 NFS 마운트 스토리지였다.
NFS 환경 특성
- NFS export 옵션 중 sync, async가 있음
- 옵션이 명시되지 않으면 기본값은 async → flush 지연
NFS export 옵션 설명
- sync:
- 클라이언트의 write() 요청마다 NFS 서버가 디스크에 즉시 flush한 후 OK 응답 반환
- 안정성 높음, 성능 낮음
- async (기본값):
- write() → 클라이언트 커널 캐시에 저장 → 일정 시간 후 NFS 서버에 전송
- 서버에서도 메모리에 저장 후 나중에 flush (2단계 지연)
- fsync() 호출 → 클라이언트는 COMMIT 요청을 보내지만, 서버 flush 시점은 커널이 결정
- 이로 인해 flush 전에 장애 발생 시 데이터 손실 가능성 있음
NFS 환경에서 flush 요약
- 백엔드 서버는 NFS 마운트 스토리지에 파일을 저장하고 있음
- NFS의 async 설정 때문에 flush 요청이 디스크에 즉시 반영되지 않음
- flush()나 fsync(), mv 등을 해도 NFS 서버의 커널 스케줄러가 flush 시점을 결정하기 때문에 클라이언트 입장에서 flush가 즉시 완료되었는지는 보장되지 않음
최종 해결 방안
- NFS export 옵션을 sync로 바꾸는 건 성능 리스크가 커서 적용 어려움
- 엑셀 파일은 사용자가 다운로드 받기만 하면 되므로, 3초 대기 정도는 큰 무리가 없음
- 따라서 엑셀 path를 반환하기 전 sleep 3을 넣는 것이 현재 환경에선 가장 현실적인 대응
'LTF(learn through failure)' 카테고리의 다른 글
파일 flush 문제 공유 (NFS) (0) | 2025.04.13 |
---|---|
파일 flush 문제 공유 (0) | 2025.04.05 |