생각을 정리하는 마인드맵, 풀맵 →
기술 딥다이브마지막 수정

[기술 딥다이브] UTF-8이 웹의 99%인 이유


한 줄 요약: UTF-8은 ASCII 호환·가변 길이(1~4바이트)·자기 동기화라는 세 가지 설계 덕분에 기존 시스템을 깨지 않고 전 세계 문자를 담아 웹의 99% 표준이 됐다.

2026년 기준 전 세계 웹페이지의 99%가 UTF-8을 사용해요. 왜 하필 UTF-8일까요? 인코딩 선택은 취향이 아니라 호환성, 공간, 안전성의 종합 점수예요. 한글 ’가’가 실제로 몇 바이트가 되는지 직접 인코딩해 가며 풀어 설명하겠어요.

ASCII 호환: 가장 큰 장점

UTF-8의 가장 중요한 설계 목표는 ASCII와의 완벽한 호환이었어요. ASCII 문자(영문 알파벳, 숫자, 기호)는 UTF-8에서도 1바이트로 동일하게 인코딩돼요. 즉, 기존 ASCII 소프트웨어는 UTF-8 텍스트도 그대로 처리할 수 있어요. 이 ‘기존 시스템에 거슬리지 않는’ 설계가 도입의 가장 큰 장벽을 낮췄어요. 웹페이지의 골격인 HTML 태그, 속성, JavaScript 문법이 전부 ASCII라는 점에서, 이 호환성은 곧 웹 전체의 전환 비용을 낮춘 의미예요.

가변 길이: 1~4바이트, 문자에 따라 다르다

UTF-8은 가변 길이 인코딩이에요. 문자의 코드 포인트(번호)에 따라 바이트 수가 달라져요.

범위 바이트 수 예시
U+0000~U+007F 1바이트 영문 알파벳(A = 0x41)
U+0080~U+07FF 2바이트 라틴 확장, 그리스, 키릴
U+0800~U+FFFF 3바이트 한글, 한자, 일본어
U+10000~U+10FFFF 4바이트 이모지, 고대 문자

한글 ’가’는 실제로 몇 바이트인가

파이썬으로 ‘A’, ‘가’, ’😀’를 UTF-8로 인코딩한 실제 출력이에요:

'A'    U+0041  1바이트  41
'가'    U+AC00  3바이트  ea b0 80
'😀'   U+1F600 4바이트  f0 9f 98 80

한글은 3바이트, 이모지는 4바이트예요. 그런데 ea b0 80이라는 세 바이트가 어떻게 ’가’가 되는 걸까요? 여기서 바이트 패턴의 설계가 드러나요.

바이트 패턴: 앞부분이 길이를 알려준다

UTF-8 바이트의 첫 비트를 보면 이 바이트가 문자의 시작인지 연속인지 판별돼요.

  • 0xxxxxxx: 1바이트 문자 (ASCII)
  • 110xxxxx: 2바이트 문자의 시작
  • 1110xxxx: 3바이트 문자의 시작
  • 11110xxx: 4바이트 문자의 시작
  • 10xxxxxx: 연속 바이트(continuation byte)

‘가’(U+AC00)가 3바이트로 인코딩되는 과정을 도식으로 보겠어요. 코드포인트 16비트를 4+6+6으로 쪼개어 템플릿의 빈칸에 끼워 넣는 방식이에요.

한글 '가'의 UTF-8 인코딩 과정 유니코드 코드포인트 U+AC00의 16비트를 4+6+6비트로 나누어 1110xxxx 10xxxxxx 10xxxxxx 템플릿에 채워 세 바이트 ea b0 80을 만드는 과정. ① 코드포인트 U+AC00 = 2진수 16비트 1010 110000 000000 파랑 4비트 + 노랑 6비트 + 초록 6비트 = 16비트 ② UTF-8 3바이트 템플릿 1110xxxx 10xxxxxx 10xxxxxx 고정 비트(1110·10)는 '길이 표시 + 연속 바이트 표지', x가 빈칸 ③ 템플릿에 비트를 채움 11101010 10110000 10000000 ④ 결과 3바이트: EA B0 80 = '가' 첫 바이트가 1110으로 시작하므로 '3바이트 문자의 시작'임을 바로 알 수 있다

이 구조 덕분에 자기 동기화(self-synchronizing)가 가능해요. 데이터 스트림의 중간부터 읽기 시작해도 10으로 시작하는 바이트는 건너뛰고 다음 문자의 시작(0 또는 11로 시작하는 바이트)을 찾을 수 있어요. 손상된 바이트를 건너뛰고 복구할 수 있다는 의미예요. 파일 일부가 손상되어도 화면에 물음표 모양의 대체 문자(replacement character)가 한두 개만 나타나고 문서 전체가 깨지지 않는 이유가 이 설계 덕분이에요.

공간 효율: 영어는 1바이트, 한글은 3바이트

영어 텍스트는 ASCII와 동일하게 문자당 1바이트로 UTF-8이 가장 효율적이에요. 한글은 3바이트로 UTF-16(2바이트)보다 어요. 하지만 웹페이지의 대부분은 HTML 태그, 코드, 영어 단어가 혼합되어 있어 전체 용량에서 ASCII 비율이 크게 작용해요. 이 블로그 글 하나를 예로 들면, HTML 마크업과 영문 기술 용어가 1바이트로 처리되기 때문에 한글이 3바이트인 부담을 상쇄해요.

왜 UTF-16이 아닌가: 엔디안 문제와 비호환

UTF-16은 CJK 문자에 2바이트로 공간 효율이 좋아요. 그러나 두 가지 문제가 있어요:

  • 엔디안(endianness): 같은 UTF-16이라도 바이트를 앞부터 쓰느냐 뒤부터 쓰느냐가 시스템마다 달라요. 그래서 파일 앞에 BOM(바이트 순서 표시)을 붙여 순서를 알려야 해요. UTF-8은 바이트 단위 설계라 순서 문제 자체가 없어요.
  • ASCII 비호환: 영문도 2바이트가 되어 기존 ASCII 기반 소프트웨어와 호환되지 않아요. C 언어의 char 문자열 처리, 오래된 프로토콜의 구분자 등이 전부 깨져요.

‘CJK에 더 작은’ UTF-16보다 ‘기존 세계에 거슬리지 않는’ UTF-8이 이긴 것이에요.

어떻게 연결되는가

한 줄로 요약하면: ASCII 호환, 가변 길이, 자기 동기화의 세 가지 설계가 결합하여 기존 시스템을 깨지 않으면서 전 세계 문자를 담은 것이 UTF-8예요. ‘가장 우수한’ 것이 아니라 ‘가장 거슬리지 않는’ 것이 승리한 사례예요. 이 인코딩은 웹의 모든 텍스트에 적용되며, 예컨대 로그인 토큰인 JWT의 JSON 페이로드도 UTF-8 바이트를 base64로 감싼 것이에요. 그 구조는 JWT 글에서 이어져요.

출처: RFC 3629: UTF-8 · 위키백과: UTF-8

이미지: Callidus, Wikimedia Commons (CC-BY-SA 3.0) — 원본