zip, gzip, zstd, bzip2, xz — 압축 알고리즘에 대해 알아보자
이번 포스팅에서는 소프트웨어의 압축 알고리즘에 대한 이야기를 해보려고 한다.
사내 프로젝트의 배포 프로세스를 개선하는 업무를 맡게 되었다. 높은 용량의 빌드 결과물을 S3에 업로드해야 하는 구조였는데, 빌드 폴더의 용량이 곧 업로드 시간과 스토리지 비용에 직결된다는 것을 체감하게 되었다. 자연스럽게 "어떻게 하면 효율적으로 압축해서 올릴 수 있을까?"라는 고민이 시작되었다.
그런데 막상 압축에 대해 찾아보니, zip, gzip, zstd, bzip2, xz 등 종류가 생각보다 많았다. 이름은 비슷비슷한데 각각 뭐가 다른 건지, 어떤 상황에서 어떤 걸 써야 하는지 정리된 자료를 찾기가 쉽지 않았다. (압축이라고 하면 다 같은 거 아니었나 싶었는데, 세상은 넓고 압축 방법은 많았다.)
그래서 이번 기회에 각 압축 형식의 원리와 특성을 비교하고, 필자가 왜 특정 방식을 선택했는지 정리해 보려고 한다.
무손실 압축이란?
무손실 압축(Lossless Compression)은 원본 데이터를 완벽하게 복원할 수 있는 압축 방식이다. 이미지나 오디오에서 사용하는 손실 압축(Lossy Compression)과 달리, 압축을 풀었을 때 원본과 1비트도 다르지 않다. 소스 코드나 빌드 결과물처럼 데이터 무결성이 중요한 경우에 반드시 무손실 압축을 사용해야 한다.
무손실 압축의 핵심 아이디어는 데이터에 존재하는 통계적 중복성을 활용하는 것이다. 반복되는 패턴을 짧은 표현으로 대체하면 전체 크기가 줄어드는 원리인 것이다.
이 중에서 사전 기반(Dictionary-Based) 방식이 무손실 압축에서 가장 널리 사용되는 알고리즘 계열이다. (여기서 "사전"은 국어사전의 그 사전이 아니라, 이전에 등장한 데이터 조각들을 짧은 코드와 매핑해 저장해 둔 참조 테이블을 뜻한다.) 1977년 Abraham Lempel과 Jacob Ziv가 발표한 논문 "A Universal Algorithm for Sequential Data Compression"(IEEE Transactions on Information Theory)에서 처음 제안된 LZ77, 그리고 이듬해인 1978년에 발표된 LZ78이 이 계열의 시조이다. 두 사람의 이름에서 알파벳 한 글자씩 따와 "LZ"가 된 것인데, 이 두 알고리즘은 이후 등장한 거의 모든 사전 기반 압축 알고리즘(DEFLATE, LZMA, LZ4, Zstd 등)의 뿌리가 되었다. (압축 알고리즘 족보의 대부분이 이 두 사람으로 수렴한다고 봐도 과언이 아니다.)
쉽게 설명하면 이런 것이다. "Linux"라는 단어가 텍스트에서 100번 반복된다면, 처음 등장할 때 사전에 등록해 두고 이후에는 "사전의 1번 항목"이라는 짧은 참조(포인터)로 대체하는 방식이다. "Linux"는 5바이트지만, 포인터는 이보다 훨씬 적은 바이트로 표현할 수 있으므로 전체 크기가 줄어든다.
그렇다면 LZ77과 LZ78은 구체적으로 어떻게 다를까?
LZ77: 슬라이딩 윈도우(Sliding Window) 방식
LZ77은 명시적인 사전을 만들지 않고, 입력 스트림의 일정 구간을 그 자체로 사전처럼 사용한다. 이 구간을 슬라이딩 윈도우라고 부르는데, 데이터를 처리하는 동안 윈도우가 한 칸씩 앞으로 이동한다는 뜻에서 붙은 이름이다. (알고리즘 문제 풀 때 많이보았다)
윈도우는 두 영역으로 나뉜다.
- 검색 버퍼(Search Buffer) : 이미 처리된, 직전까지의 데이터. 사전 역할을 한다.
- 룩어헤드 버퍼(Look-ahead Buffer) : 아직 처리되지 않은, 앞으로 압축할 데이터.
알고리즘은 룩어헤드 버퍼의 첫 부분이 검색 버퍼 어딘가에 등장한 적이 있는지를 찾는다. 같은 패턴이 발견되면, 그 매치를 (거리, 길이, 다음 문자) 형태의 튜플로 인코딩한다. "거리"는 검색 버퍼 내에서 매치가 시작되는 위치까지 몇 글자 뒤로 가야 하는지를, "길이"는 매치가 몇 글자나 이어지는지를 의미한다.
예를 들어 "banana_banana" 라는 문자열을 LZ77로 압축한다고 해보자. 두 번째 "banana"를 만난 시점에서 알고리즘은 이렇게 말하는 셈이다. "7글자 뒤로 가서 6글자를 그대로 복사해라." 그러면 6바이트짜리 문자열이 단 두 개의 숫자로 표현된다.
이 방식의 핵심은 사전을 별도로 저장하거나 전송할 필요가 없다는 점이다. 디코더는 압축을 풀어 나가면서 자연스럽게 검색 버퍼를 재구성하기 때문에, 사전은 데이터 그 자체에 암묵적으로 내장되어 있다고 볼 수 있다. 다만 그 대가로, 압축 해제는 항상 데이터의 처음부터 순차적으로 진행해야 한다. 중간부터 임의로 풀어내는 것은 원리적으로 불가능하다.
윈도우 크기는 압축률과 직접적인 트레이드오프 관계에 있다. 윈도우가 크면 더 멀리 떨어진 패턴까지 참조할 수 있어 압축률이 높아지지만, 매치 검색에 드는 연산량과 메모리 사용량이 함께 늘어난다.
LZ78: 명시적 사전(Explicit Dictionary) 방식
LZ78은 LZ77과 달리, 사전을 명시적으로 구축하면서 압축을 진행한다. 슬라이딩 윈도우 같은 것은 없다. 대신 이전에 본 패턴들을 인덱스가 붙은 사전 항목으로 저장해 두고, 이후에 같은 패턴이 등장하면 인덱스로 대체한다.
LZ78이 출력하는 단위는 (사전 인덱스, 다음 문자) 형태의 태그이다. 인코더는 사전에서 가장 길게 일치하는 항목을 찾은 뒤, 그 항목의 인덱스와 매치를 깨뜨린 다음 문자를 묶어서 출력한다. 그리고 *"방금 매치된 항목 + 새로운 문자"*를 다시 사전에 새 항목으로 추가한다. 이렇게 사전이 점진적으로 자라나는 구조이다.
LZ78의 가장 유명한 변종이 바로 LZW(Lempel-Ziv-Welch)이다. 1984년 Terry Welch가 LZ78을 개선하여 발표한 것으로, GIF 이미지 포맷과 유닉스의 compress 유틸리티(.Z 확장자)에서 사용되었다. (한때 LZW는 특허 분쟁의 중심에 서기도 했는데, 이 사건이 PNG 포맷이 탄생하는 계기 중 하나가 되었다.)
그래서 현대 압축 알고리즘은 어느 쪽 후손인가?
흥미롭게도, 오늘날 우리가 사용하는 거의 모든 주류 압축 알고리즘은 LZ77 계열의 후손이다.
1982년 Storer와 Szymanski가 발표한 LZSS는 LZ77을 개선한 변종으로, 1비트 플래그를 도입해 매 출력이 "리터럴(원본 문자)"인지 "길이-거리 쌍"인지를 구분했다. 매치가 너무 짧아서 오히려 손해일 때는 그냥 원본 문자를 그대로 출력하도록 한 것이다.
1993년 Phil Katz는 이 LZSS에 허프만 부호화(빈도가 높은 심볼에 짧은 비트를 할당하는 엔트로피 코딩)를 결합해 DEFLATE를 만들었다. ZIP, GZIP, PNG가 모두 이 DEFLATE를 사용한다. 즉, 우리가 매일같이 만지는 .zip, .gz, .png 파일은 모두 LZ77의 직계 후손인 셈이다.
이후에 등장한 LZMA(7-Zip, XZ), LZ4, Zstd 또한 모두 LZ77의 슬라이딩 윈도우 아이디어를 출발점으로 삼아, 매치 검색 자료구조와 엔트로피 코딩 방식을 진화시켜 온 것이다. 반면 LZ78 계열은 LZW를 끝으로 주류 무대에서 사실상 물러났다고 봐도 무방하다.
이론적으로 두 알고리즘은 "전체 데이터를 압축 해제할 경우" 동등한 능력을 가진다는 것이 증명되어 있다. 그럼에도 LZ77이 살아남은 이유는, 사전을 데이터에 내장한다는 설계가 구현과 확장 양면에서 더 유연했기 때문이다. 슬라이딩 윈도우의 크기, 매치 검색 알고리즘, 뒤에 붙일 엔트로피 코더 등을 자유롭게 조합할 수 있어서, 시대의 요구에 맞춰 계속 진화할 여지가 있었던 것이다.
압축 성능을 평가할 때는 두 가지 축을 고려해야 한다. 압축률(얼마나 작아지는가)과 압축 속도(얼마나 빨리 끝나는가)이다. 이론적으로 더 높은 압축률을 추구하면 더 많은 연산이 필요하기 때문에 압축 시간이 길어진다. 이 둘 사이의 절충점을 찾는 것이 현실적인 압축 전략의 핵심이다.
그럼 차근차근 여러 가지 압축 형식들을 비교해 보자.
ZIP
ZIP은 1989년 Phil Katz가 만든 파일 형식으로, 내부적으로 DEFLATE 알고리즘(LZ77 + Huffman coding의 조합)을 사용하여 압축한다. 여기서 중요한 점은, ZIP은 "압축 알고리즘"이 아니라 "파일 형식(format)"이라는 것이다. ZIP이라는 컨테이너 안에 DEFLATE라는 알고리즘이 들어가 있는 구조이다.
ZIP의 특징은 각 파일을 개별적으로 압축한다는 점이다. 이를 비솔리드 아카이브(Non-solid Archive)라고 부르는데, 덕분에 압축 파일 내의 특정 파일 하나만 꺼내는 것이 가능하다. 반면 파일 간의 중복 데이터를 활용하지 못하기 때문에, 뒤에서 설명할 tar.gz 방식에 비해 압축률이 낮을 수 있다.
Windows, macOS, Linux 등 대부분의 운영체제에서 별도의 소프트웨어 없이 기본 지원되므로, 크로스 플랫폼 호환성이 중요한 경우에 가장 무난한 선택이다.
GZIP (GNU Zip)
GZIP은 ZIP과 마찬가지로 내부적으로 DEFLATE 알고리즘을 사용한다. 같은 알고리즘인데 왜 별도의 형식이 존재할까? ZIP이 여러 파일을 하나의 아카이브에 담는 "컨테이너" 역할까지 수행하는 반면, GZIP은 단일 파일(또는 단일 스트림)의 압축에 특화된 형식이다.
그래서 여러 파일이나 디렉토리를 GZIP으로 압축하려면, 먼저 TAR로 하나의 아카이브로 묶은 뒤 GZIP으로 압축하는 2단계를 거쳐야 한다. 이것이 바로 .tar.gz(또는 .tgz) 파일이 탄생하는 과정이다.
GZIP의 파일 구조는 RFC 1952에 명세되어 있으며, 상당히 단순하다. 10바이트 고정 헤더 + 선택적 확장 헤더(원본 파일명, 코멘트 등) + DEFLATE 압축 데이터 + 8바이트 트레일러(CRC-32 체크섬과 원본 크기)로 이루어진다. 여기서 CRC-32는 압축 해제 후 데이터가 원본과 동일한지를 검증하는 무결성 체크 장치이다. 즉 GZIP은 DEFLATE 압축 데이터를 감싸는 가벼운 래퍼(wrapper)인 셈이다.
DEFLATE 내부에서 사용하는 슬라이딩 윈도우의 크기는 최대 32KB이다. 이 크기가 GZIP 압축률의 상한을 결정하는 중요한 요소인데, 32KB 이상 떨어진 패턴은 참조할 수 없기 때문이다. 또한 GZIP은 압축 레벨을 1부터 9까지 지정할 수 있다. 레벨 1은 빠르지만 압축률이 낮고(약 60%), 레벨 9는 느리지만 최대 압축률(약 75%)을 달성한다. 기본값은 레벨 6으로, 속도와 압축률 사이의 균형점이다.
Unix/Linux 환경에서 소스 코드 배포, 로그 파일 압축, 소프트웨어 패키지 등에 표준처럼 사용되고 있다. 웹 서버의 HTTP 압축(Content-Encoding: gzip)에서도 여전히 기본값으로 널리 쓰이고 있지만, 이 영역에서는 점차 Brotli로 대체되는 추세이다.
ZSTD (Zstandard)
ZSTD는 Meta(구 Facebook)의 Yann Collet이 개발하여 2016년에 오픈소스로 공개한 압축 알고리즘이다. GZIP과 비슷한 수준의 압축률을 유지하면서도, 압축/해제 속도가 압도적으로 빠르다는 것이 핵심 강점이다.
ZSTD의 내부 구조는 크게 세 단계로 나뉜다. 먼저 LZ77 계열의 매치 파인더(Match Finder) 가 입력 데이터에서 반복 패턴을 찾아낸다. 그 다음 찾아낸 매치 정보(리터럴, 매치 길이, 오프셋)를 시퀀스로 인코딩한다. 마지막으로 이 시퀀스를 엔트로피 코딩으로 압축하는데, 여기서 GZIP의 허프만 부호화 대신 FSE(Finite State Entropy) 라는 방식을 사용한다. FSE는 ANS(Asymmetric Numeral Systems) 이론에 기반한 엔트로피 코더로, 허프만 부호화와 산술 부호화(Arithmetic Coding)의 장점을 결합한 것이다. 허프만 부호화가 심볼당 정수 비트만 할당할 수 있는 반면, FSE는 분수 비트까지 표현할 수 있어 이론적 최적값에 더 가까운 압축이 가능하다. (이름이 거창하지만, 핵심은 "같은 데이터를 더 적은 비트로 표현하는 더 똑똑한 방법"이라고 이해하면 된다.)
매치 파인더도 압축 레벨에 따라 전략이 달라진다. 낮은 레벨(1~4)에서는 단순 해시 테이블로 빠르게 검색하고, 중간 레벨(5~12)에서는 여러 후보를 비교한 뒤 가장 좋은 매치를 선택하는 Lazy 방식을, 높은 레벨(13~22)에서는 이진 트리와 동적 프로그래밍을 활용해 최적에 가까운 매치를 찾아낸다. 이렇게 레벨을 1부터 22까지 세밀하게 조절할 수 있어, 실시간 전송에는 낮은 레벨을, 아카이빙에는 높은 레벨을 사용하는 식으로 유연하게 대응할 수 있다.
Silesia Corpus 벤치마크 기준으로, ZSTD 기본 레벨(3)의 압축 속도는 약 300MB/s, 해제 속도는 약 1,200MB/s이다. 반면 GZIP 기본 레벨(6)은 압축 약 34MB/s, 해제 약 380MB/s에 그친다. 압축은 약 8배, 해제는 약 3배 빠르면서도 압축률은 ZSTD(3.17) : GZIP(3.09)로 오히려 앞선다. 이 숫자가 ZSTD의 트레이드오프 개선을 가장 직관적으로 보여준다.
현재 생태계에서의 채택도 빠르게 확대되고 있다. Linux 커널의 모듈 압축과 파일시스템 투명 압축에 사용되고 있으며, Arch Linux, Fedora, Debian/Ubuntu 등 주요 배포판에서 패키지 압축 기본 형식으로 채택했다. 2025년 2월 릴리스된 v1.5.7부터는 멀티스레드 압축이 기본 활성화(최대 4스레드)되어, 싱글스레드만 지원하는 GZIP과의 실질적인 속도 격차는 더욱 벌어졌다. AWS는 내부 서비스에서 gzip을 zstd로 전환하여 S3 스토리지를 약 30% 절감했다고 밝힌 바 있다.
BZIP2
BZIP2는 여러 단계의 변환을 거쳐 압축을 수행한다. 핵심 파이프라인은 다음과 같다.
- RLE(Run-Length Encoding) : 초기 데이터의 연속 반복을 줄임
- BWT(Burrows-Wheeler Transform) : 데이터를 압축하기 쉬운 형태로 재배열
- MTF(Move-to-Front Transform) : BWT의 출력을 숫자 배열로 변환
- RLE : MTF 결과의 반복을 다시 줄임
- Huffman Coding : 최종적으로 빈도 기반 부호화로 압축
GZIP보다 높은 압축률을 제공하지만, 압축 속도와 해제 속도 모두 느리다. 고압축률이 필요하면서 속도가 덜 중요한 아카이빙 용도로 사용되어 왔다.
다만 마지막 릴리스가 2019년(v1.0.8)이며, 활발한 개발은 이루어지지 않고 있다. 압축률과 속도 양면에서 ZSTD가 BZIP2를 능가하는 벤치마크 결과가 나오면서, 새로운 프로젝트에서는 ZSTD를 선택하는 경우가 늘고 있다.
XZ
XZ는 LZMA2를 사용하는 압축 형식이다. LZMA(Lempel-Ziv-Markov chain Algorithm)는 Igor Pavlov가 개발한 알고리즘으로, LZ77 기반의 사전 압축에 범위 부호화(Range Encoding)를 결합한 것이다. LZMA2는 LZMA의 "개선된 버전"이라기보다는, LZMA 스트림을 감싸는 컨테이너 형식에 가깝다. 멀티스레드 압축/해제 지원과 비압축 데이터의 효율적인 처리가 추가된 것이 핵심이다.
이 글에서 다루는 형식 중 가장 높은 압축률을 자랑한다. 그 대신 압축 속도가 매우 느리고, 메모리 사용량도 크다. 저장 공간 절약이 최우선인 아카이빙에 적합하다.
다만 2024년 3월, XZ의 핵심 라이브러리인 xz-utils에서 백도어가 발견되는 심각한 보안 사건(CVE-2024-3094)이 있었다. 2년간의 소셜 엔지니어링 공격으로 메인테이너 권한이 탈취되어, CVSS 10.0(최고 심각도)을 받았다. 주요 배포판에서 즉시 안전한 버전으로 롤백했지만, 이 사건은 오픈소스 공급망 보안에 대한 경각심을 일깨워 주었다. (XZ 자체의 기술적 가치는 여전하지만, 도구 선택 시 이런 맥락도 알아두면 좋다.)
TAR
TAR(Tape Archive)는 그 자체로 압축 알고리즘이 아니다. 여러 파일과 디렉토리를 하나의 아카이브 파일로 묶는 도구이다. 이름에서 알 수 있듯이 원래 자기 테이프(Tape) 백업을 위해 만들어진 포맷인데, 테이프라는 매체 특성상 데이터를 순차적으로 쭉 이어 붙이는 구조가 자연스러웠다.
TAR의 내부 구조는 의외로 단순하다. 모든 데이터는 512바이트 블록 단위로 처리된다. 각 파일 앞에 512바이트짜리 헤더 블록이 붙는데, 이 헤더에 파일명(최대 100바이트), 파일 모드, 소유자 UID/GID, 파일 크기, 수정 시간, 체크섬 등의 메타데이터가 들어간다. 파일 데이터는 헤더 뒤에 이어지며, 512바이트의 배수로 패딩된다. 아카이브의 끝은 512바이트짜리 제로 블록 두 개로 표시된다. 현대의 대부분의 TAR 구현체는 POSIX에서 정의한 UStar(Unix Standard TAR) 형식을 따르며, 이 형식은 더 긴 파일명(최대 256바이트)과 추가 메타데이터 필드를 지원한다.
핵심은 TAR가 파일의 권한, 소유권, 타임스탬프, 심볼릭 링크 같은 Unix 파일시스템 메타데이터를 그대로 보존한다는 점이다. ZIP은 이러한 Unix 고유 메타데이터를 완벽히 보존하지 못하는 경우가 있어, 서버 환경에서의 배포에는 TAR가 더 적합하다.
TAR 자체는 크기를 줄여주지 않는다. 오히려 헤더와 패딩 때문에 원본보다 약간 커진다. 실제 압축은 GZIP, BZIP2, XZ, ZSTD 등과 결합하여 수행한다. 이것이 .tar.gz, .tar.bz2, .tar.xz, .tar.zst 같은 확장자가 존재하는 이유이다. TAR가 "묶기"를, 압축 도구가 "줄이기"를 각각 담당하는 Unix 철학("한 가지 일을 잘 하라") 의 전형적인 사례이다.
Unix/Linux 환경에서 표준 아카이빙 도구로 사용되며, Windows에서는 별도의 소프트웨어(7-Zip 등)가 필요하다.
잠깐, Brotli도 알아두자
프론트엔드 개발자라면 Brotli도 짚고 넘어갈 필요가 있다. Brotli는 Google이 개발한 압축 알고리즘으로, 2015년에 HTTP 스트림 압축 사양(Content-Encoding: br)으로 표준화되었다.
모든 주요 브라우저에서 HTTPS 환경에서 지원되며(지원률 96% 이상), GZIP 대비 약 15~25% 더 높은 압축률을 보인다. 특히 JavaScript, CSS, HTML 같은 텍스트 기반 정적 파일의 압축에 효과적이다. Cloudflare 등 주요 CDN에서 기본 압축 방식으로 채택하고 있으며, 현대 웹 최적화의 모범 사례는 "Brotli 우선, GZIP 폴백"으로 정리된다.
빌드 결과물을 S3에 올려 CDN으로 서빙하는 구조라면, 정적 파일을 사전에 Brotli로 압축해 두는 것이 네트워크 전송 최적화에 큰 도움이 된다. (지금 당장 고민하기에는 자료가 많지 않아 도입하기 어렵지만 추후 고민의 여지가 될 수 있기에 개발자라면 알아두면 좋을 것 같다.)
tar.gz가 zip보다 압축률이 높은 이유
이것은 솔리드 아카이브(Solid Archive) 와 비솔리드 아카이브(Non-solid Archive) 의 차이에서 비롯된다.
tar.gz는 TAR로 모든 파일을 하나의 연속된 데이터 스트림으로 묶은 뒤, GZIP이 이 전체 스트림을 한 번에 압축한다. 이 과정에서 파일 간의 중복 데이터를 인식하고 활용할 수 있다. 이것이 솔리드 아카이브 방식이다. 예를 들어 빌드 폴더에 구조가 유사한 JavaScript 번들 파일이 수십 개 있다면, 파일 A에서 등장한 패턴이 파일 B에서도 반복될 때 이를 하나의 참조로 처리할 수 있다. 또한 파일마다 별도의 헤더, 체크섬, 목차(Table of Contents)를 기록할 필요가 없으므로 메타데이터 오버헤드도 줄어든다.
반면 ZIP은 각 파일을 독립적으로 압축하는 비솔리드 방식이므로, 파일 간 중복을 활용하지 못한다. 파일 A와 파일 B에 동일한 코드 블록이 있더라도, 각각의 DEFLATE 스트림은 상대방의 존재를 모른다. 일반적으로 tar.gz가 ZIP 대비 5~15% 더 높은 압축률을 보이는 이유가 바로 이것이다. 특히 유사한 구조의 파일이 대량으로 포함된 빌드 결과물일수록 이 격차는 더 벌어진다.
다만 솔리드 아카이브에도 뚜렷한 단점이 있다.
- 압축 파일 내의 특정 파일 하나만 꺼내려면 그 파일 앞에 위치한 모든 데이터를 먼저 해제해야 한다. 모든 파일이 하나의 스트림으로 이어져 있기 때문에, 중간 지점으로 바로 건너뛸 수가 없는 것이다. ZIP은 개별 파일에 대한 랜덤 액세스가 가능하므로, 아카이브에서 특정 파일만 빈번하게 꺼내야 하는 상황이라면 ZIP이 더 적합할 수 있다.
- 아카이브의 일부가 손상되면 손상 지점 이후의 모든 데이터가 복구 불가능해질 수 있다. 비솔리드 방식에서는 손상된 파일 하나만 잃고 나머지는 살릴 수 있는 것과 대비된다.
<2026년 추가>
2024년의 선택은 tar.gz, 지금은?
필자가 당시 tar.gz를 선택한 이유는 호환성과 안정성이었다. S3 업로드 이후 다양한 환경에서 해제해야 했기 때문에, 어디서든 지원되는 tar.gz가 안전한 선택이었다.
하지만 지금 같은 상황이 다시 온다면 tar.zst(TAR + ZSTD) 에 대해 고민해볼 것이다. 앞서 살펴본 벤치마크 수치를 다시 떠올려 보자.
GZIP 기본 레벨의 압축 속도가 34MB/s인데, ZSTD 기본 레벨은 300MB/s이다. 2GB 빌드 폴더 기준으로 단순 계산하면 GZIP은 약 60초, ZSTD는 약 7초 만에 압축이 끝난다. 여기에 ZSTD v1.5.7부터 기본 활성화된 멀티스레드(최대 4스레드)까지 고려하면, 실제 체감 시간은 더 짧아진다. CI/CD 파이프라인에서 이 차이는 배포 한 사이클마다 누적되는 것이니, 무시할 수 없는 수치이다.
# tar.zst 생성 (멀티스레드 자동 활용)
tar --zstd -cf archive.tar.zst directory/
# 또는 압축 레벨 지정 (-T0은 사용 가능한 모든 코어 활용)
tar -cf archive.tar.zst -I 'zstd -3 -T0' directory/압축률 면에서도 ZSTD는 GZIP과 동등하거나 오히려 앞서기 때문에, "속도를 위해 압축률을 포기한다"는 트레이드오프가 사실상 존재하지 않는다. 속도도 빠르고, 결과물도 작다.
다만 수신 측 환경에서 zstd 해제가 가능한지는 반드시 확인해야 한다. 주요 Linux 배포판에는 이미 기본 설치되어 있고, macOS에서도 Homebrew(brew install zstd)로 간단히 설치할 수 있다. 하지만 레거시 시스템이나 최소 설치 환경에서는 별도 설치가 필요할 수 있으므로, 팀 내 모든 환경을 사전에 점검하는 것이 중요하다. 호환성이 최우선이라면 여전히 tar.gz가 가장 무난한 선택이다.
한눈에 비교하기
| 형식 | 알고리즘 | 압축률 | 속도 | 특징 |
|---|---|---|---|---|
| ZIP | DEFLATE | 보통 | 빠름 | 크로스 플랫폼, 비솔리드 |
| GZIP | DEFLATE | 보통 | 빠름 | 단일 스트림, TAR와 결합 |
| ZSTD | Zstandard | 높음 | 매우 빠름 | 압축 레벨 조절, 최신 표준 |
| BZIP2 | BWT+MTF+Huffman | 높음 | 느림 | 개발 정체 |
| XZ | LZMA2 | 매우 높음 | 매우 느림 | 최고 압축률, 보안 사건 주의 |
| Brotli | Brotli | 높음 | 보통 | 웹 최적화 특화 |
마치며
압축이라는 주제를 파보기 전까지는, 솔직히 "그냥 zip으로 묶으면 되는 거 아닌가?"라고 생각했다. 하지만 실제로 2GB가 넘는 빌드 폴더를 다루다 보니, 어떤 알고리즘을 선택하느냐에 따라 업로드 시간과 비용이 유의미하게 달라진다는 것을 체감할 수 있었다.
각 압축 형식은 저마다의 설계 철학과 트레이드오프를 가지고 있다. ZIP의 호환성, GZIP의 범용성, ZSTD의 속도, XZ의 압축률까지 어느 것이 "최고"라고 단정할 수 없고, 프로젝트의 맥락에 따라 적합한 선택이 달라진다.
평소에 무심코 사용하던 도구의 원리를 파보는 것은, 다음에 비슷한 문제를 만났을 때 더 나은 판단을 할 수 있게 해준다. 이 글이 압축 알고리즘을 선택해야 하는 누군가에게 작은 참고가 되었기를 바란다.