HTML5의 FileReader API는 클라이언트 브라우저가 사용자의 로컬 파일을 읽을 수 있게 해주어, 업로드된 파일이 서버에서 더 이상 읽히지 않게 하여 서버의 부담을 크게 줄이고 업로드에 필요한 시간을 절약합니다. 하지만 실제로는 FileReader.readAsText()로 30만 개의 로그 파일을 쉽게 처리할 수 있지만, 로그 파일이 1G나 심지어 2G처럼 클 때는 브라우저가 다운됩니다. 이는 readAsText()가 대상 파일을 한꺼번에 메모리에 로드하여 메모리가 한계를 초과하게 만들기 때문입니다. 따라서 웹 애플리케이션이 큰 파일을 자주 처리해야 한다면, FileReader.readAsArrayBuffer()를 사용해 파일을 하나씩 읽어야 합니다.
테스트 시나리오
저희 시나리오는 간단합니다. JavaScript를 사용해 IIS 로그의 시간 범위를 얻는 것입니다
IIS 로그 샘플:
#Software: 마이크로소프트 인터넷 정보 서비스 10.0 #Version: 1.0 #Date: 2016-08-18 06:53:55 #Fields: 날짜, 시간, s-ip, cs-method, cs-uri-stem, cs-uri-query, s-port, cs-username, c-ip, cs(User-Agent), cs(Referer), sc-status, sc-substatus, sc-win32-status, time-taken. 2016-08-18 06:53:55 ::1 GET / - 80 - ::1 Mozilla/5.0+(Windows+NT+10.0; +WOW64; +트라이던트/7.0; +rv:11.0)+like+Gecko - 200 0 0 476 2016-08-18 06:53:55 ::1 GET /iisstart.png - 80 - ::1 Mozilla/5.0+(Windows+NT+10.0; +WOW64; +트라이던트/7.0; +rv:11.0)+like+게코 http://localhost/ 200 0 0 3 2016-08-18 08:45:34 10.172.19.198 GET /test/pac/wpad.dat - 80 - 10.157.21.235 Mozilla/5.0+(Windows+NT+6.1; +Win64; +x64; +트라이던트/7.0; +rv:11.0)+like+Gecko - 404 3 50 265 2016-08-18 08:46:44 10.172.19.198 GET /test/pac/wpad.dat - 80 - 10.157.21.235 Mozilla/5.0+(Windows+NT+6.1; +Win64; +x64; +트라이던트/7.0; +rv:11.0)+like+게코 - 200 0 0 6 우리의 목표는 그 로그의 시간대를 파악하는 것입니다:
시작 시간: 2016-08-18 06:53:55 종료 시간: 2016-08-18 08:46:44
readAsText() 구현 사용
readAsText() 사용은 비교적 간단합니다. 전체 파일의 문자열을 얻은 후, 각 줄의 처음 19자를 시작부터 받고, 날짜 형식이 충족되는지 확인하며, 만족하면 이 19자가 시작 시간입니다. 그리고 같은 방식으로 뒷부분부터 각 줄을 통해 종료 시간을 얻습니다. 코드는 다음과 같습니다:
샘플 IIS 로그(크기: 1k)의 실행 결과는 예상한 대로입니다.
하지만 한 번 선택하면요더 큰 IIS 로그(크기: 2G)가 발생하면 브라우저가 다운됩니다。 그 이유는 readAsText()가 전체 파일을 먼저 메모리에 로드하기 때문에, 파일이 너무 크면 메모리가 부족해 브라우저 프로세스가 다운되기 때문입니다.
readAsArrayBuffer() 구현 사용
JavaScript의 File 객체는 Blob에서 상속되기 때문에, Blob.slice() 메서드를 사용해 파일을 작은 조각으로 분할할 수 있습니다. 일반적인 아이디어는 다음과 같습니다:
먼저, 파일의 처음 1만 개의 내용을 텍스트로 변환하세요 각 줄의 처음 19자를 뽑아 날짜 형식이 맞는지 확인하고, 만약 맞으면 이 19자가 시작 시간입니다 그 다음 파일 끝에 있는 10,000개의 콘텐츠를 텍스트로 변환하세요 마찬가지로, 끝 부분에서 각 줄을 따라 이동하면 종료 시간을 알 수 있습니다
코드는 다음과 같습니다:
readAsArrayBuffer()를 사용해 2G 이상의 IIS 로그에도 불구하고 원하는 결과를 매우 짧은 시간 내에 얻을 수 있었습니다.
|