
솔직히 말해, 대다수의 개발자들은 pip install protobuf를 입력하는 순간 데이터 직렬화에 대한 모든 고민이 끝났다고 착각합니다. 구글(Google)이 만들었으니 당연히 효율적이고 빠를 것이라는 막연한 믿음 때문입니다. 하지만 트래픽이 폭증하고 페이로드(Payload) 크기가 GB 단위로 넘어가는 순간, 그 믿음은 처참하게 배신당합니다. 서버는 이유 없이 OOM(Out of Memory)으로 죽어나가고, Latency(지연 시간)는 치솟는데 프로파일링을 해보면 범인은 십중팔구 직렬화 라이브러리 자체에 있습니다. 오늘은 고성능 워크로드에서 표준 라이브러리의 한계를 직면했을 때, 이를 어떻게 기술적으로 돌파해야 하는지 Harmonic 팀의 pbcc 개발 사례를 통해 짚어보겠습니다.
기본적으로 Protocol Buffers는 훌륭한 규약이지만, 구글이 제공하는 표준 Python 구현체는 대규모 시스템에서 치명적인 결함을 드러냅니다. 가장 황당한 지점은 2GB가 넘는 메시지를 처리할 때 발생하는 강제 종료 현상입니다. 내부적으로 메시지 크기를 처리하는 변수가 부호 있는 32비트 정수(Signed 32-bit Integer)로 구현되어 있을 가능성이 높기 때문입니다. 하드웨어 스펙을 빵빵하게 늘려놔도 라이브러리 내부의 변수 타입 하나 때문에 서비스가 멈추는 겁니다. 게다가 표준 라이브러리는 repeated 필드를 네이티브 Python list가 아닌 커스텀 컨테이너로 감싸버립니다. 이로 인해 개발자는 값을 비교할 때마다 불필요한 캐스팅을 반복해야 하고, 이는 곧 CPU 사이클 낭비와 코드 가독성 저하로 이어집니다.

이 문제를 해결하기 위해 Harmonic 팀이 선택한 방식은 런타임 해석이 아닌 AOT(Ahead-of-Time) 컴파일입니다. pbcc라는 이름의 이 컴파일러는 .proto 파일을 읽어서 런타임에 해석하는 대신, 아예 최적화된 C++ 코드를 생성해버립니다. 그리고 이를 Python 확장 모듈(.so)로 빌드하여 Python이 마치 C++ 객체를 다루듯 직접 import하게 만듭니다. 중간 단계의 해석 비용을 제거하고, 직렬화/역직렬화 로직을 기계어 레벨로 내려버린 것입니다. 이는 제가 삼성전자 시절 펌웨어 레벨에서 비트를 깎아가며 최적화하던 방식과 맥락을 같이합니다. 불필요한 추상화 레이어를 걷어내는 것이 성능 최적화의 첫걸음입니다.
이들이 설계에서 가장 공을 들인 부분은 '정확성'과 '메모리 관리'입니다. 거대한 중첩 메시지를 처리할 때 Python의 GC(Garbage Collector)에만 의존하면 메모리 누수나 해제 시점 지연이 발생하기 쉽습니다. pbcc는 PyObjectRef라는 래퍼 클래스를 도입하여 C++의 std::shared_ptr처럼 Python 객체의 참조 카운트를 엄격하게 관리합니다. 또한, 모든 정수 타입을 64비트 네이티브 타입으로 처리하여 앞서 언급한 2GB 크기 제한을 원천적으로 제거했습니다. 구글 라이브러리가 32비트의 늪에 빠져 있을 때, 이들은 과감하게 하드웨어 스펙을 온전히 활용하는 설계를 택한 것입니다.
개발자 경험(DX) 측면에서도 시사하는 바가 큽니다. 성능을 위해 C++을 썼지만, Python 개발자에게 노출되는 인터페이스는 지극히 Pythonic합니다. repeated 필드는 진짜 list로, map은 진짜 dict로 매핑됩니다. 더 이상 이상한 래퍼 클래스와 씨름할 필요가 없다는 뜻입니다. 또한 .pyi 스텁 파일을 자동으로 생성하여 최신 IDE에서 타입 힌팅과 자동 완성을 완벽하게 지원합니다. 인프라 엔지니어가 시스템 성능만 챙기는 것이 아니라, 이 도구를 사용할 동료 개발자의 생산성까지 고려했다는 점에서 높은 점수를 줄 만합니다.
많은 주니어들이 "바퀴를 다시 발명하지 말라"는 격언을 핑계로 기성 라이브러리의 한계에 타협하곤 합니다. 하지만 여러분의 서비스가 임계점에 도달했다면, 그리고 표준 도구가 병목이 되고 있다면, 그때는 스택을 파고들어 직접 깎아야 합니다. Harmonic 팀은 구글의 upb 라이브러리보다 더 빠르고 가볍고 안전한 구현체를 직접 만들어냈습니다. Latency를 줄이고 TCO(총 소유 비용)를 낮추기 위해 표준을 의심하고 밑바닥부터 다시 설계하는 집요함, 그것이 진짜 엔지니어의 생존 방식입니다.


