데이터 직렬화(Serialization)는 메모리 내 데이터 구조를 전송/저장 가능한 형식으로 변환하는 과정이다. 형식 선택은 성능, 인간 가독성, 스키마 진화, 언어 지원에 영향을 준다.
형식별 비교
| 형식 | 인코딩 | 스키마 | 가독성 | 크기 | 속도 |
|---|
| JSON | 텍스트 | 없음 | 높음 | 크다 | 보통 |
| XML | 텍스트 | XSD | 높음 | 매우 큼 | 느림 |
| MessagePack | 바이너리 | 없음 | 없음 | 작음 | 빠름 |
| CBOR | 바이너리 | 없음 | 없음 | 작음 | 빠름 |
| Avro | 바이너리 | 필수 | 없음 | 가장 작음 | 매우 빠름 |
| Protobuf | 바이너리 | 필수 | 없음 | 작음 | 매우 빠름 |
| Thrift | 바이너리 | 필수 | 없음 | 작음 | 빠름 |
| FlatBuffers | 바이너리 | 필수 | 없음 | 보통 | 역직렬화 없음 |
MessagePack
python
import msgpack
import json
data = {"user_id": 1001, "name": "홍길동", "scores": [95, 87, 92], "active": True}
# JSON vs MessagePack 크기 비교
json_bytes = json.dumps(data, ensure_ascii=False).encode('utf-8')
msgpack_bytes = msgpack.packb(data, use_bin_type=True)
print(f"JSON: {len(json_bytes)} bytes") # 약 75 bytes
print(f"MsgPack: {len(msgpack_bytes)} bytes") # 약 45 bytes (40% 감소)
# 역직렬화
decoded = msgpack.unpackb(msgpack_bytes, raw=False)
Protocol Buffers (Protobuf)
protobuf
// schema.proto
syntax = "proto3";
package myapp;
message User {
uint32 user_id = 1;
string name = 2;
repeated uint32 scores = 3;
bool active = 4;
optional string email = 5; // proto3: optional
}
message UserList {
repeated User users = 1;
}
python
# 생성된 코드 사용 (protoc로 컴파일)
from schema_pb2 import User
user = User(user_id=1001, name="홍길동", scores=[95, 87, 92], active=True)
serialized = user.SerializeToString() # 직렬화
print(f"Protobuf: {len(serialized)} bytes") # 약 22 bytes
# 역직렬화
user2 = User()
user2.ParseFromString(serialized)
print(user2.name)
Apache Avro (스키마 진화 강점)
python
import avro.schema
from avro.datafile import DataFileWriter, DataFileReader
from avro.io import DatumWriter, DatumReader
import io
schema_json = json.dumps({
"type": "record",
"name": "User",
"fields": [
{"name": "user_id", "type": "int"},
{"name": "name", "type": "string"},
{"name": "email", "type": ["null", "string"], "default": None} # 선택 필드
]
})
schema = avro.schema.parse(schema_json)
# 쓰기 (스키마 포함 저장)
buf = io.BytesIO()
writer = DataFileWriter(buf, DatumWriter(), schema)
writer.append({"user_id": 1001, "name": "홍길동", "email": "hong@example.com"})
writer.flush()
# 읽기 (스키마 자동 추출)
buf.seek(0)
reader = DataFileReader(buf, DatumReader())
for record in reader:
print(record)
관련 문서