목차
원리를 알고 나면 남는 것은 하나다. 지금 이 자리에서 켜는 게 이득인가.
무엇과 무엇을 맞바꾸나
압축을 켤지 말지는 성능 문제가 아니라 거래 조건 문제다. 무엇을 내주고 무엇을 받는지가 늘 같기 때문이다.
| 받는 것 | 내주는 것 |
|---|---|
| 전송량이 준다 | 압축하는 CPU 시간 |
| 저장 공간이 준다 | 푸는 CPU 시간 |
| 중간을 바로 못 읽는다 | |
| 압축한 결과의 크기가 정보를 흘릴 수 있다 |
여기서 눈여겨볼 것은 받는 쪽과 내주는 쪽의 단위가 다르다는 점이다. 바이트와 시간을 맞바꾸는 거래라서, 둘 중 무엇이 지금 모자란지를 모르면 답이 안 나온다. 압축이 늘 좋다거나 늘 나쁘다는 말이 둘 다 틀린 이유가 이거다.
병목이 어디냐가 답을 정한다
같은 압축을 걸어도 어디가 좁으냐에 따라 결과가 뒤집힌다.
압축 칸의 폭은 위아래가 같다. 달라진 것은 회선 속도뿐인데 이득과 손해가 뒤집힌다.
회선이 좁고 데이터가 크면 압축은 압도적으로 남는다. 줄이는 데 든 시간이 아껴진 전송 시간에 비하면 티도 안 난다. 모바일 네트워크로 큰 목록 응답을 내려보내는 자리가 전형적이다.
회선이 넓고 데이터가 작으면 거래가 뒤집힌다. 어차피 순식간에 갈 데이터를 줄이느라 CPU를 태우면 총 시간이 늘어난다. 같은 기계 안의 프로세스끼리 주고받는 데이터, 같은 데이터센터 안의 서비스 간 호출이 여기 해당한다.
그래서 물어야 할 것은 압축률이 아니라 병목이다. “몇 퍼센트 줄어드나”보다 “지금 느린 게 회선인가 CPU인가”가 먼저다.
한 번 줄여 두느냐 매번 줄이느냐
같은 압축이라도 언제 하느냐로 성격이 완전히 달라진다.
- 미리 줄여 둔다 - 배포할 때 정적 파일을 한 번 압축해 두고, 요청이 오면 그 파일을 그대로 내보낸다. 압축 비용은 배포 때 한 번이고 요청 때는 0이다
- 그때그때 줄인다 - 요청이 올 때마다 응답을 만들어 압축한다. 내용이 매번 다른 응답은 이 방법밖에 없다
이 구별이 압축 레벨 선택을 정한다. 미리 줄여 두는 것은 최고 레벨을 써도 된다. 한 번 더 오래 걸릴 뿐이고, 푸는 시간은 레벨과 거의 무관하니 받는 쪽은 손해가 없다.
그때그때 줄이는 것은 낮은 레벨이 맞다. 요청 하나하나에 압축 시간이 붙으므로, 레벨을 올려 얻는 몇 퍼센트보다 응답이 늦어지는 대가가 크다. 대부분의 서버가 동적 압축의 기본 레벨을 낮게 잡아 둔 이유가 이것이다.
켜면 손해인 자리
이 시리즈에서 본 원리들이 그대로 금지 목록이 된다.
- 이미 압축된 것 - 이미지, 동영상, 소리, 내려받게 하는 압축 파일. 첫 압축이 연료를 다 태웠으니 CPU만 든다
- 아주 작은 응답 - 머리말과 이름표가 줄인 것보다 크면 결과가 오히려 커진다
- 암호화된 뒤의 데이터 - 순서가 뒤집힌 것이다. 압축은 암호화 앞에 있어야 한다
- 비밀이 섞인 응답 - 압축한 크기 자체가 힌트를 흘릴 수 있다
- 자주 읽는 저장 데이터 - 읽을 때마다 푸는 비용을 문다. 공간보다 그쪽이 비쌀 수 있다
앞의 둘은 대부분의 웹 서버가 설정으로 막아 준다. 압축을 걸 대상 타입 목록과 최소 크기 기준이 그것이고, 기본값이 대개 합리적이다. 손대야 하는 경우는 직접 만든 타입을 쓰거나, 그 목록에서 빠진 텍스트 형식을 내보낼 때다.
전송이 아니라 저장이라면
여기까지는 주로 오가는 데이터 이야기였다. 저장하는 데이터는 기준이 다르다.
전송은 대체로 한 번 압축해 한 번 푸는데, 저장은 한 번 압축해 여러 번 푼다. 그래서 저울이 기울어지는 방향이 다르다.
| 전송 | 저장 | |
|---|---|---|
| 무엇이 아쉬운가 | 시간 | 공간 |
| 푸는 횟수 | 대개 한 번 | 읽을 때마다 |
| 레벨을 올릴 값이 있나 | 동적이면 없다 | 자주 안 읽으면 크다 |
그래서 오래된 로그와 백업은 압축의 교과서적인 대상이다. 거의 안 읽고, 반복이 지독하게 많고, 공간이 곧 비용이다. 반대로 매 요청마다 읽는 뜨거운 데이터는 압축이 오히려 짐이 된다.
여기서 저장소 압축의 결정적인 조건 하나가 나온다. 어디까지 풀어야 원하는 것이 나오나. 파일 전체를 앞에서부터 풀어야 한다면 자주 읽는 데이터에 못 쓰지만, 블록 단위로 나눠 압축해 필요한 블록만 풀 수 있다면 이야기가 달라진다. 데이터베이스와 파일 시스템의 압축 옵션이 대체로 이 방식이다.
실무에서: 켜 놓고 재 보지 않는 것이 가장 흔한 실수
압축은 설정 한 줄이라 켜기가 쉽고, 그래서 켠 다음 확인하지 않는 일이 흔하다. 실제로 자주 걸리는 것 셋이다.
켠 줄 알았는데 안 걸려 있다. 앞단 프록시가 조건에 안 맞아 그냥 흘려보내는 경우가 많다. 확인은 간단하다. 응답 헤더에 Content-Encoding이 붙어 있는지 보면 된다. 이 헤더가 어떻게 정해지는지는 요청과 응답이 주고받는 헤더에서 이미 봤다.
두 군데에서 걸려 있다. 앱과 프록시가 각각 압축하면 CPU만 두 번 태운다. 압축은 한 층에서만 건다가 원칙이고, 대개 가장 바깥이 맡는 편이 낫다.
압축률을 안 재 봤다. 이 시리즈의 모든 이론보다 대표 샘플 몇 개를 실제로 압축해 보는 것이 정확하다. 그 숫자가 20%도 안 되면 켤 값이 없고, 70%가 넘으면 켜지 않을 이유가 없다.
한 가지 더 있다. 압축이 켜져 있는 자리에서 사람이 손으로 하는 절약은 대체로 헛수고다. 필드 이름을 짧게 줄이거나 공백을 지우는 일이 그렇다. 압축기가 어차피 반복과 치우침을 걷어내므로 읽기만 나빠지고 크기는 기대만큼 안 준다. 응답을 줄이고 싶다면 문자열을 깎는 것보다 안 쓰는 필드를 빼고 페이지 크기를 줄이는 쪽이 몇 배 효과가 크다.
이 시리즈가 만든 판단표
들고 다닐 만한 것만 한 표로 접었다.
| 상황 | 물어야 할 것 |
|---|---|
| 응답에 압축을 걸까 | 텍스트인가. 이미 압축된 타입은 아닌가 |
| 응답이 아주 작다 | 머리말과 이름표가 줄인 것보다 크지 않은가 |
| 압축 레벨을 고른다 | 한 번 줄여 여러 번 보내나, 매 요청마다 줄이나 |
| 여러 파일을 묶는다 | 하나만 꺼내 쓸 일이 있나. 없으면 이어 붙인 뒤 압축한다 |
| 이미지 포맷을 고른다 | 되돌릴 필요가 있나. 사진인가 그림인가. 투명한 부분이 있나 |
| 이미지를 가공해 저장한다 | 원본을 무손실로 남겨 뒀나. 손실 위에 또 손실을 얹고 있지 않나 |
| 압축과 암호화를 함께 한다 | 압축이 먼저인가. 비밀이 섞인 응답은 아닌가 |
| 저장 데이터를 압축한다 | 얼마나 자주 읽나. 필요한 부분만 풀 수 있나 |
| 생각보다 안 줄어든다 | 대표 샘플로 실제 압축률을 재 봤나 |
각 항목의 근거는 시리즈에 흩어져 있다. 필요한 것만 골라 보면 된다.
- 압축이 왜 되는가 - 반복과 치우침, 그리고 바이트와 CPU의 거래
- 반복을 가리킨다 - 개수로 접기와 뒤돌아 가리키기, 창의 크기
- 허프만 코드 - 짧은 이름 주기, 접두어 조건, 이름표 비용
- DEFLATE - 두 방법을 겹치는 순서, gzip과 zip의 차이, 레벨
- 손실 압축 - 편도라는 성질, 포맷 고르기, 재저장의 누적 손해
- 안 줄어드는 것들 - 개수로 나오는 한계, 엔트로피, 압축과 암호화의 순서
여기서 다루지 않은 것
이 시리즈는 같은 정보를 더 적은 바이트로 담는 일만 다뤘다. 가까이 있지만 뺀 것들이 있다.
- 특정 데이터에 맞춘 압축 - 시계열 수치나 열 단위로 쌓인 데이터에는 그 모양을 노린 전용 방법이 따로 있다. 원리는 같지만 어디에 반복이 있는지를 미리 알고 시작한다는 점이 다르다
- 차분과 델타 - 두 버전 사이의 차이만 저장하는 방식이다. 버전 관리 시스템과 백업이 쓰는데, 압축이라기보다 “무엇을 저장할지 고르는 일”에 가깝다
- 중복 제거 - 같은 덩어리가 여러 파일에 걸쳐 있을 때 하나만 두고 나머지는 가리키는 방식이다. 반복 지우기를 파일 단위로 올린 것이다
인코딩도 여기서는 링크로만 다뤘다. 바이트에 담는 일이라는 점은 같은데 목적이 다르다. 그쪽 이야기는 글자가 깨졌을 때에서 한 장으로 접혀 있다.
정리
- 압축은 바이트와 CPU 시간을 맞바꾸는 거래다. 늘 좋지도 늘 나쁘지도 않다.
- 그래서 물어야 할 것은 압축률이 아니라 지금 좁은 곳이 회선인가 CPU인가다.
- 미리 줄여 두면 최고 레벨을 써도 되고, 매 요청마다 줄인다면 낮은 레벨이 맞다.
- 이미 압축된 것, 아주 작은 응답, 암호문 뒤, 비밀이 섞인 응답에는 켜지 않는다.
- 저장은 전송과 저울이 다르다. 한 번 줄여 여러 번 푸는 자리라 자주 읽는지가 기준이 된다.
- 켠 다음에는 정말 걸렸는지, 두 번 걸리지 않았는지, 얼마나 줄었는지를 확인한다.
- 결국 이 시리즈 전체가 한 문장이다. 줄어드는 것은 낭비뿐이고, 낭비가 없으면 줄어들 것도 없다.