dd? 그게 뭔d?
합치고싶다, 대용량 파일!
회사 일과 관련해서 혼자 취미삼아 진행하던 일이 있었는데, 몇가지 파일을 가공해서 하나의 큰 파일로 합쳐야 하는 일이었다. 그런데 각 파일의 크기도 엄청나게 크거니와 JSON 파싱까지 해야해서 어떻게 하면 좋을지 고심중이었다.
예를 들어 국내 각 시/도의 특정 데이터를 수집해 하나의 전국 데이터로 만들어야 하는데, 각 시/도의 데이터를 수집하는 데 까지는 성공했으나 이를 하나의 파일로 묶는 것이 쉽지 않았다.
각 파일의 크기는 대략 4~900MB 였고, 그 수가 40여개 였으니 대략 30GB가 넘는 용량이었다.
시도해본 방법과 추천받은 방법
처음 데이터 수집을 파이썬 스크립트를 만들어서 했기 때문에 합치는 작업 또한 파이썬 스크립트로 하려고 했다. 그런데 파일 로딩 -> JSON 로딩 -> 특정 필드 Dump -> 파일 WRITE
순서로 하니 모~든 과정이 너무너무 오래 걸렸다.
그래서?
우선 최초로 데이터를 수집할 때 필요한 필드만을 저장하도록 수정하여 특정 필드를 DUMP 해야 하는 과정을 없앴고, JSON 로딩 대신 단순 파일 읽기 & 쓰기로 변경해서 불필요한 로드를 줄여보았다.
그래도..
그래도 너무 느리다. 30GB의 파일 하나를 만들기 위해 최소 2시간의 시간이 필요했다. 사실 한 번 만들고 나면 그만이라 이대로 하루 종일 기다렸다 만들어진 파일을 사용해도 되지만 그러고싶지 않았다.
DD?
보통 추천하는 방식인 cat 을 이용한 방식
cat file1.part* file2.part* file3.part* > merged.txt
은 어쨌든 cat 명령어를 대용량 파일을 대상으로 사용했을 때 퍼포먼스 이슈가 있을 수 있기 때문에 + 합쳐야 할 파일이 너무 많았기 때문에 사용할 수 없었다.
그렇게 계속해서 인터넷을 찾아 헤맨 끝에! dd 라는 유닉스 명령어를 알게 되었다.
dd
명령어에 대해 ChatGPT에 물어보았을 때 이렇게 대답해 주었다.
dd 명령은 Linux 및 기타 유닉스 계열 운영체제의 유틸리티로, 파일, 장치, 스트림 간에 데이터를 복사하고 변환하는 데 사용할 수 있습니다. "dd"라는 이름은 "데이터 복제"를 의미하며 다양한 저수준 데이터 조작 작업을 수행하는 데 사용할 수 있습니다.
dd 명령은 입력 파일이나 장치에서 데이터를 읽고 출력 파일이나 장치에 쓰는 방식으로 작동하며, 블록 크기, 바이트 오프셋, 데이터 변환 옵션 등 다양한 매개변수를 지정할 수 있습니다. dd 명령은 디스크 이미지 생성, 디스크 간 데이터 복사, 디스크 포맷, 임의 데이터 파일 생성 등의 작업에 사용할 수 있습니다.
다음은 임의의 데이터로 채워진 1GB 파일을 만드는 dd 명령의 사용 예입니다:
dd if=/dev/urandom of=randomfile bs=1M count=1024
이 명령에서 if는 "입력 파일"을 나타내며 데이터의 소스(이 경우 임의 데이터를 생성하는 /dev/urandom 장치)를 지정하고, of는 "출력 파일"을 나타내며 대상 파일(이 경우 randomfile)을 지정하며, bs는 "블록 크기"를 나타내며 한 번에 읽기/쓰기할 바이트 수를 지정하고, count는 읽기/쓰기할 블록의 수를 지정합니다.
이 명령은 /dev/urandom에서 각각 1MB씩 1024개의 블록을 읽고 randomfile에 쓰므로 임의의 데이터로 채워진 1GB 파일이 생성됩니다.
그러니까 읽고 쓸 블록 크기와 개수를 명시해 주면 source부터 destination까지 저수준 데이터 조작을 통해 파일을 복사해 준다는 것이구나!
그래서 나의 최종 작업의 일부는 아래의 모습을 하게 되었다.
for i in *.txt; do
[ -f "$i" ] || break
dd if=$i bs=1G >> merge.txt
done
대략 30GB의 파일을 합치는 데 대략 30초도 걸리지 않았다.
정말 대단해!