CS · Compression · Backend

압축을 켤 자리와 끌 자리 - 한 장의 판단표로 접는다

압축은 늘 이득이 아니라 바이트와 CPU를 맞바꾸는 거래다. 그래서 병목이 어디냐에 따라 답이 뒤집힌다. 이 시리즈에서 본 원리를 켤지 끌지 고르는 표 한 장으로 접는다.

·압축의 원리와 한계 7편
목차
  1. 무엇과 무엇을 맞바꾸나
  2. 병목이 어디냐가 답을 정한다
  3. 한 번 줄여 두느냐 매번 줄이느냐
  4. 켜면 손해인 자리
  5. 전송이 아니라 저장이라면
  6. 실무에서: 켜 놓고 재 보지 않는 것이 가장 흔한 실수
  7. 이 시리즈가 만든 판단표
  8. 여기서 다루지 않은 것
  9. 정리

원리를 알고 나면 남는 것은 하나다. 지금 이 자리에서 켜는 게 이득인가.

무엇과 무엇을 맞바꾸나

압축을 켤지 말지는 성능 문제가 아니라 거래 조건 문제다. 무엇을 내주고 무엇을 받는지가 늘 같기 때문이다.

받는 것내주는 것
전송량이 준다압축하는 CPU 시간
저장 공간이 준다푸는 CPU 시간
중간을 바로 못 읽는다
압축한 결과의 크기가 정보를 흘릴 수 있다

여기서 눈여겨볼 것은 받는 쪽과 내주는 쪽의 단위가 다르다는 점이다. 바이트와 시간을 맞바꾸는 거래라서, 둘 중 무엇이 지금 모자란지를 모르면 답이 안 나온다. 압축이 늘 좋다거나 늘 나쁘다는 말이 둘 다 틀린 이유가 이거다.

병목이 어디냐가 답을 정한다

같은 압축을 걸어도 어디가 좁으냐에 따라 결과가 뒤집힌다.

느린 회선 - 같은 응답을 모바일 회선으로 보낸다
압축 안 함
압축함 총 시간이 크게 준다
빠른 회선 - 똑같은 응답을 같은 데이터센터 안에서 보낸다
압축 안 함
압축함 총 시간이 오히려 는다
압축에 쓴 시간 전송에 쓴 시간

압축 칸의 폭은 위아래가 같다. 달라진 것은 회선 속도뿐인데 이득과 손해가 뒤집힌다.

회선이 좁고 데이터가 크면 압축은 압도적으로 남는다. 줄이는 데 든 시간이 아껴진 전송 시간에 비하면 티도 안 난다. 모바일 네트워크로 큰 목록 응답을 내려보내는 자리가 전형적이다.

회선이 넓고 데이터가 작으면 거래가 뒤집힌다. 어차피 순식간에 갈 데이터를 줄이느라 CPU를 태우면 총 시간이 늘어난다. 같은 기계 안의 프로세스끼리 주고받는 데이터, 같은 데이터센터 안의 서비스 간 호출이 여기 해당한다.

그래서 물어야 할 것은 압축률이 아니라 병목이다. “몇 퍼센트 줄어드나”보다 “지금 느린 게 회선인가 CPU인가”가 먼저다.

한 번 줄여 두느냐 매번 줄이느냐

같은 압축이라도 언제 하느냐로 성격이 완전히 달라진다.

  • 미리 줄여 둔다 - 배포할 때 정적 파일을 한 번 압축해 두고, 요청이 오면 그 파일을 그대로 내보낸다. 압축 비용은 배포 때 한 번이고 요청 때는 0이다
  • 그때그때 줄인다 - 요청이 올 때마다 응답을 만들어 압축한다. 내용이 매번 다른 응답은 이 방법밖에 없다

이 구별이 압축 레벨 선택을 정한다. 미리 줄여 두는 것은 최고 레벨을 써도 된다. 한 번 더 오래 걸릴 뿐이고, 푸는 시간은 레벨과 거의 무관하니 받는 쪽은 손해가 없다.

그때그때 줄이는 것은 낮은 레벨이 맞다. 요청 하나하나에 압축 시간이 붙으므로, 레벨을 올려 얻는 몇 퍼센트보다 응답이 늦어지는 대가가 크다. 대부분의 서버가 동적 압축의 기본 레벨을 낮게 잡아 둔 이유가 이것이다.

켜면 손해인 자리

이 시리즈에서 본 원리들이 그대로 금지 목록이 된다.

  • 이미 압축된 것 - 이미지, 동영상, 소리, 내려받게 하는 압축 파일. 첫 압축이 연료를 다 태웠으니 CPU만 든다
  • 아주 작은 응답 - 머리말과 이름표가 줄인 것보다 크면 결과가 오히려 커진다
  • 암호화된 뒤의 데이터 - 순서가 뒤집힌 것이다. 압축은 암호화 앞에 있어야 한다
  • 비밀이 섞인 응답 - 압축한 크기 자체가 힌트를 흘릴 수 있다
  • 자주 읽는 저장 데이터 - 읽을 때마다 푸는 비용을 문다. 공간보다 그쪽이 비쌀 수 있다

앞의 둘은 대부분의 웹 서버가 설정으로 막아 준다. 압축을 걸 대상 타입 목록과 최소 크기 기준이 그것이고, 기본값이 대개 합리적이다. 손대야 하는 경우는 직접 만든 타입을 쓰거나, 그 목록에서 빠진 텍스트 형식을 내보낼 때다.

전송이 아니라 저장이라면

여기까지는 주로 오가는 데이터 이야기였다. 저장하는 데이터는 기준이 다르다.

전송은 대체로 한 번 압축해 한 번 푸는데, 저장은 한 번 압축해 여러 번 푼다. 그래서 저울이 기울어지는 방향이 다르다.

전송저장
무엇이 아쉬운가시간공간
푸는 횟수대개 한 번읽을 때마다
레벨을 올릴 값이 있나동적이면 없다자주 안 읽으면 크다

그래서 오래된 로그와 백업은 압축의 교과서적인 대상이다. 거의 안 읽고, 반복이 지독하게 많고, 공간이 곧 비용이다. 반대로 매 요청마다 읽는 뜨거운 데이터는 압축이 오히려 짐이 된다.

여기서 저장소 압축의 결정적인 조건 하나가 나온다. 어디까지 풀어야 원하는 것이 나오나. 파일 전체를 앞에서부터 풀어야 한다면 자주 읽는 데이터에 못 쓰지만, 블록 단위로 나눠 압축해 필요한 블록만 풀 수 있다면 이야기가 달라진다. 데이터베이스와 파일 시스템의 압축 옵션이 대체로 이 방식이다.

실무에서: 켜 놓고 재 보지 않는 것이 가장 흔한 실수

압축은 설정 한 줄이라 켜기가 쉽고, 그래서 켠 다음 확인하지 않는 일이 흔하다. 실제로 자주 걸리는 것 셋이다.

켠 줄 알았는데 안 걸려 있다. 앞단 프록시가 조건에 안 맞아 그냥 흘려보내는 경우가 많다. 확인은 간단하다. 응답 헤더에 Content-Encoding이 붙어 있는지 보면 된다. 이 헤더가 어떻게 정해지는지는 요청과 응답이 주고받는 헤더에서 이미 봤다.

두 군데에서 걸려 있다. 앱과 프록시가 각각 압축하면 CPU만 두 번 태운다. 압축은 한 층에서만 건다가 원칙이고, 대개 가장 바깥이 맡는 편이 낫다.

압축률을 안 재 봤다. 이 시리즈의 모든 이론보다 대표 샘플 몇 개를 실제로 압축해 보는 것이 정확하다. 그 숫자가 20%도 안 되면 켤 값이 없고, 70%가 넘으면 켜지 않을 이유가 없다.

한 가지 더 있다. 압축이 켜져 있는 자리에서 사람이 손으로 하는 절약은 대체로 헛수고다. 필드 이름을 짧게 줄이거나 공백을 지우는 일이 그렇다. 압축기가 어차피 반복과 치우침을 걷어내므로 읽기만 나빠지고 크기는 기대만큼 안 준다. 응답을 줄이고 싶다면 문자열을 깎는 것보다 안 쓰는 필드를 빼고 페이지 크기를 줄이는 쪽이 몇 배 효과가 크다.

이 시리즈가 만든 판단표

들고 다닐 만한 것만 한 표로 접었다.

상황물어야 할 것
응답에 압축을 걸까텍스트인가. 이미 압축된 타입은 아닌가
응답이 아주 작다머리말과 이름표가 줄인 것보다 크지 않은가
압축 레벨을 고른다한 번 줄여 여러 번 보내나, 매 요청마다 줄이나
여러 파일을 묶는다하나만 꺼내 쓸 일이 있나. 없으면 이어 붙인 뒤 압축한다
이미지 포맷을 고른다되돌릴 필요가 있나. 사진인가 그림인가. 투명한 부분이 있나
이미지를 가공해 저장한다원본을 무손실로 남겨 뒀나. 손실 위에 또 손실을 얹고 있지 않나
압축과 암호화를 함께 한다압축이 먼저인가. 비밀이 섞인 응답은 아닌가
저장 데이터를 압축한다얼마나 자주 읽나. 필요한 부분만 풀 수 있나
생각보다 안 줄어든다대표 샘플로 실제 압축률을 재 봤나

각 항목의 근거는 시리즈에 흩어져 있다. 필요한 것만 골라 보면 된다.

여기서 다루지 않은 것

이 시리즈는 같은 정보를 더 적은 바이트로 담는 일만 다뤘다. 가까이 있지만 뺀 것들이 있다.

  • 특정 데이터에 맞춘 압축 - 시계열 수치나 열 단위로 쌓인 데이터에는 그 모양을 노린 전용 방법이 따로 있다. 원리는 같지만 어디에 반복이 있는지를 미리 알고 시작한다는 점이 다르다
  • 차분과 델타 - 두 버전 사이의 차이만 저장하는 방식이다. 버전 관리 시스템과 백업이 쓰는데, 압축이라기보다 “무엇을 저장할지 고르는 일”에 가깝다
  • 중복 제거 - 같은 덩어리가 여러 파일에 걸쳐 있을 때 하나만 두고 나머지는 가리키는 방식이다. 반복 지우기를 파일 단위로 올린 것이다

인코딩도 여기서는 링크로만 다뤘다. 바이트에 담는 일이라는 점은 같은데 목적이 다르다. 그쪽 이야기는 글자가 깨졌을 때에서 한 장으로 접혀 있다.

정리

  • 압축은 바이트와 CPU 시간을 맞바꾸는 거래다. 늘 좋지도 늘 나쁘지도 않다.
  • 그래서 물어야 할 것은 압축률이 아니라 지금 좁은 곳이 회선인가 CPU인가다.
  • 미리 줄여 두면 최고 레벨을 써도 되고, 매 요청마다 줄인다면 낮은 레벨이 맞다.
  • 이미 압축된 것, 아주 작은 응답, 암호문 뒤, 비밀이 섞인 응답에는 켜지 않는다.
  • 저장은 전송과 저울이 다르다. 한 번 줄여 여러 번 푸는 자리라 자주 읽는지가 기준이 된다.
  • 켠 다음에는 정말 걸렸는지, 두 번 걸리지 않았는지, 얼마나 줄었는지를 확인한다.
  • 결국 이 시리즈 전체가 한 문장이다. 줄어드는 것은 낭비뿐이고, 낭비가 없으면 줄어들 것도 없다.