오늘 친구가 웹페이지에 2MB 파일이 업로드됐다고 문제를 신고했습니다. 웹페이지에서 다운로드했는데 64KB에 불과해 열리지 않았습니다. BUG가 존재하고 반드시 나타나야 한다는 것을 확인한 후, BUG를 디버깅하고 해결하는 길에 들어섰습니다.
1. 시스템은 nginx php mysql입니다. 경험상 mysql과는 관련이 없으므로 무시하셔도 됩니다.
2. PHP 웹페이지에서 2MB 파일을 업로드한 후 서버에서 직접 파일을 열어주시면 정상적으로 보실 수 있으며 원본 파일과 동일한 바이너리입니다.
3. 다른 브라우저와 다른 컴퓨터를 사용하여 PHP 웹 페이지에서 파일을 반복적으로 다운로드하고 다운로드한 파일이 64KB에 불과하다는 것을 확인합니다.
4. 90KB 크기의 파일로 변경하여 PHP 웹페이지에서 업로드 및 다운로드 하는데 이상이 없습니다.
위의 4가지 사항을 통해 기본적으로 nginx에 문제가 있음을 판단할 수 있습니다. 이때, nginx 로그 파일을 열어서 다음과 같은 에러 로그를 찾아보세요.
[crit] 21636#0: *843968 open() "/home/www/local/nginx/fastcgi_temp/0/11/0000000110" 업스트림을 읽는 동안 실패했습니다(13: 권한 거부됨),…..
fastcgi_temp 폴더를 운영할 수 있는 권한이 부족하여 일반 파일을 얻을 수 없다는 점을 과감히 짐작할 수 있다. 따라서 해당 폴더에 권한을 부여하면 문제가 해결된다.
돌이켜보면 그 이유가 무엇이었나요?
nginx 구성 파일을 보면 다음 단락을 찾을 수 있습니다.
fastcgi_connect_timeout 300
fastcgi_send_timeout 300
fastcgi_read_timeout 300
**fastcgi_buffer_size 64k
fastcgi_buffers 4 64k;**
fastcgi_busy_buffers_size 128k
fastcgi_temp_file_write_size 128k
다운로드가 실패할 때마다 파일 크기가 항상 64KB인 것도 이와 관련이 있습니다. nginx는 fastcgi_buffer_size에 지정된 크기의 버퍼를 사용하여 fastcgi 스트림의 콘텐츠를 캐시하는 것으로 나타났습니다. 크기가 이 크기를 초과하면 fastcgi_buffers에 지정된 수와 크기의 버퍼에 계속 적용됩니다. 이 크기가 여전히 초과되면 초과 콘텐츠가 임시 파일에 기록됩니다. 즉, 이 경우 nginx는 먼저 64K 버퍼를 사용하여 fastcgi 스트림의 첫 번째 부분을 버퍼링한 다음 버퍼링을 위해 최대 4*64K=256K 버퍼를 적용합니다. 초과하면 임시 파일이 기록됩니다. 따라서 256K보다 큰 파일을 다운로드할 경우 버퍼링을 위해 임시폴더를 사용해야 하는데 여기서는 작동할 수 있는 권한이 없어 이런 문제가 발생하게 됩니다.
이상에서는 nginx에서 대용량 파일을 다운로드할 때 파일 손상 및 파일 크기 불일치 문제를 해결하는 방법을 소개했으며, 문제의 측면도 포함하여 PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.