PHP에서 JSON을 커스텀 바이너리 형식으로 교체했습니다
앱과 웹사이트를 위한 리치 텍스트(rich text)를 저장할 더 나은 방법이 필요했습니다.
처음에는 데이터베이스에 가공되지 않은 HTML을 저장했습니다. 나중에는 편집과 출력을 분리하기 위해 JSON으로 전환했습니다. JSON은 한동안 잘 작동했지만, 규모가 커지면서 새로운 문제들이 발생했습니다.
JSON은 우리의 요구 사항을 충족하기에 너무 느려졌습니다.
오래된 링크를 검색하고 업데이트해야 할 때, 전체 배열을 파싱하고 다시 구축해야 했습니다. 이 과정은 느리고 비효율적이었습니다. 우리는 더 빠른 데이터 조작과 스트리밍이 가능한 형식이 필요했습니다.
저는 PHP를 사용하여 커스텀 바이너리 형식을 직접 만들기로 했습니다.
많은 개발자가 PHP가 저수준 바이트 관리(low-level byte management)에 적합하지 않다고 생각합니다. 하지만 PHP에는 이를 위한 내장 함수가 있습니다:
pack(): 숫자나 문자열을 로우 바이트(raw bytes)로 변환합니다.unpack(): 해당 바이트를 다시 숫자나 문자열로 변환합니다.
저는 멀티바이트 문자열 연산 사용을 중단했습니다. 대신 특정 바이트 청크(chunk)를 읽는 데 집중했습니다. 예를 들어, 부호 없는 64비트 정수(unsigned 64-bit integer)는 정확히 8바이트가 필요합니다. 바이너리 데이터를 다룰 때는 정밀도가 핵심입니다.
데이터 구조화 방식도 변경했습니다.
대부분의 사람들은 문서를 깊고 중첩된 트리 구조로 유지하려고 합니다. 이는 종종 실수입니다. 저는 텍스트, 태그, 리스트와 같은 요소들의 평탄한 리스트(flat list) 방식으로 전환했습니다. HTML을 재구축하기 위해 간단한 오프셋(offset) 트리를 사용합니다. 이를 통해 모든 링크를 찾거나 HTML을 제거하는 작업이 매우 빨라졌습니다.
10,000번의 루프를 실행한 결과, 확실한 승자가 나타났습니다:
기존 JSON 인코딩: 2.18s 기존 JSON 디코딩: 0.86s
새로운 바이너리 인코딩: 1.19s 새로운 바이너리 디코딩: 0.67s
새로운 형식은 인코딩과 디코딩 모두에서 더 빠릅니다.
바이너리 형식은 JSON이나 HTML보다 크기가 큽니다. JSON보다 약 두 배의 공간을 차지합니다. 하지만 우리는 서버 사이드 렌더링(server-side rendering)을 사용하므로, 이러한 저장 공간의 증가는 성능에 영향을 미치지 않습니다.
트레이드오프를 감수할 가치가 충분합니다. 이제 간단하고 빠른 함수로 링크를 변경하고 HTML을 정리할 수 있습니다.
커스텀 형식을 만든다면 명확한 사양(specification)을 작성하세요. 나중에 코드를 다시 살펴볼 때 반드시 필요할 것입니다.
출처: https://dev.to/tomj/i-replaced-json-with-a-custom-binary-format-in-php-mok