요약
- 직렬화는 I/O가 아니라 Python 객체 순회·인코딩이라 CPU 바운드 작업이고, DRF에서 느린 API의 CPU 병목이 DB가 아니라 직렬화 계층에 있는 경우가 많다.
ModelSerializer는 init마다 필드를 동적 빌드 + Djangolazy반복 호출로 CPU를 낭비한다. 일반Serializer나.values()인라인으로 바꾸면 직렬화 CPU 시간이 극적으로 준다.- 적용 순서: 프로파일링으로 직렬화 CPU 점유 확인 → serializer 경량화 → 인코더(orjson) 교체.
본문
전제: 직렬화는 CPU 바운드다. row마다 필드를 순회하며 Python 함수를 호출하고 JSON으로 인코딩하므로, row·필드 수에 비례해 CPU 시간이 늘어난다. 따라서 직렬화 경량화는 곧 요청당 CPU 사이클 감소 = 같은 하드웨어에서 throughput 상승으로 직결된다. 손대기 전에 New Relic / py-spy 등으로 직렬화 함수의 CPU 점유부터 확인하는 게 순서다 (DB가 진범이 아닌지 먼저 배제).
케이스 1 — ModelSerializer 제거 (Haki Benita)
5,000회 반복 직렬화 벤치마크. 느림의 원인이 DB가 아니라 순수 Python(CPU) 직렬화임을 보였다.
| 방식 | 소요 시간 | 순수 함수 대비 |
|---|---|---|
| 순수 함수 | 0.034초 | 1배 |
ModelSerializer (쓰기) |
12.818초 | 377배 |
ModelSerializer (읽기전용) |
7.407초 | 218배 |
일반 Serializer |
2.101초 | 62배 |
- 원인:
ModelSerializer는 클래스 정의가 아닌 init 시점마다 필드를 동적으로 빌드하고 Djangolazy함수를 반복 호출. ModelSerializer→ 일반Serializer전환만으로 약 85% CPU 시간 감소.- 성능 critical 엔드포인트는 serializer를 아예 버리고
.values()+ 인라인 직렬화 권장. lazy패치 적용 시 쓰기 ModelSerializer 12.8초 → 5.6초(55%↓), 읽기 7.4초 → 5.3초(28%↓).
# Before
return Response(UserSerializer(qs, many=True).data)
# After: 모델 인스턴스화·필드 순회 생략
return JsonResponse(list(qs.values("id", "name", "created_at")), safe=False)
케이스 2 — DRF Serializer → serpy (BetterWorks)
New Relic + RunSnakeRun 프로파일링 결과 "대부분의 작업이 Django 모델 직렬화에 소비" — DB 쿼리는 이미 효율적, 병목은 전적으로 직렬화 CPU. serpy는 직렬화 비용을 metaclass(클래스 정의 시점)로 밀어내고 런타임엔 단순 필드 루프만 돌게 설계해 직렬화 병목을 제거했다. (정확한 % 수치 없이 벤치 그래프로 제시)
케이스 3 — orjson 인코더 교체
표준 json → orjson(Rust). 인코딩 CPU가 줄어 동일 하드웨어에서 throughput 상승:
- 처리량: 동시성 250에서 7,429 → 10,794 req/s (약 45%↑)
- 대역폭: 708 → 1,029 MB/s (약 45%↑)
- 단, 대형 페이로드에서만 유효. 병목이 다른 곳이면 효과 미미.
CPU 감소 폭 순서
ModelSerializer→ 일반Serializer/.values()인라인 (~85%↑, 가장 극적)- serpy·msgspec 등 metaclass·컴파일 기반 직렬화로 전환
- orjson 인코더 교체 (인코딩 CPU만)
세 케이스의 공통 교훈: "느린 API의 CPU 병목이 직렬화 계층에 있음을 프로파일링으로 먼저 확인한 뒤" 손댔다.
관련 노트
- serialize, deserialize(직렬화, 역직렬화)
- Protobuf는 바이너리로 인코딩되기 때문에 데이터가 작고 파싱속도가 빠르다.
- django prefetch_related objects 구현
- DB 커넥션은 풀 크기를 늘리기 전에 트랜잭션 점유시간을 줄여 회전율을 높인다