Dropbox / database-design

3 개의 포스트

dropbox

Improving storage efficiency in Magic Pocket, our immutable blob store (새 탭에서 열림)

Dropbox의 엑사바이트급 불변(Immutable) 블록 저장소인 'Magic Pocket'은 데이터 무결성과 효율적인 확장을 위해 설계된 핵심 인프라입니다. 최근 새로운 데이터 배치 서비스인 'Live Coder' 도입 과정에서 볼륨이 채 5%도 채워지지 않는 심각한 파편화 문제가 발생하여 스토리지 오버헤드가 급격히 증가하는 위기를 맞았습니다. 이를 해결하기 위해 Dropbox 엔지니어링 팀은 기존의 안정 상태 압축 방식을 넘어, 저밀도 볼륨을 집중적으로 재구성하는 다각적인 전략을 통해 스토리지 효율을 이전 수준보다 더욱 개선하는 데 성공했습니다. **불변 스토리지 구조와 공간 회수 메커니즘** * Magic Pocket은 데이터를 한 번 쓰면 수정하지 않는 불변 방식을 채택하고 있어, 사용자 데이터가 삭제되거나 수정되어도 기존 데이터는 즉시 지워지지 않고 볼륨 내에 그대로 남습니다. * 이러한 특성상 시간이 지남에 따라 실제 데이터보다 더 많은 디스크 공간을 점유하는 '파편화'가 발생하며, 이를 관리하지 않으면 스토리지 오버헤드가 기하급수적으로 늘어납니다. * 공간 회수는 가비지 컬렉션(참조되지 않는 데이터 식별)과 압축(Compaction)이라는 두 단계로 이루어지며, 압축은 유효한 데이터만 골라 새 볼륨에 옮겨 적고 기존 볼륨을 퇴거시키는 방식으로 수행됩니다. * 데이터 가용성을 위해 에러저 코딩(Erasure Coding)을 사용하여 복제 방식보다 적은 비용으로 결함 허용 능력을 유지합니다. **신규 서비스 도입으로 인한 저밀도 볼륨 문제** * 배경 쓰기 증폭을 줄이기 위해 도입된 'Live Coder' 서비스가 예상치 못하게 할당량의 5% 미만만 채워진 수많은 저밀도 볼륨을 생성하는 부작용을 일으켰습니다. * Magic Pocket의 볼륨은 고정된 크기를 가지기 때문에, 데이터가 적게 들어있어도 전체 용량을 점유하게 되어 실제 저장된 바이트 대비 물리적 디스크 소비량이 급등했습니다. * 기존의 압축 방식은 데이터 분포가 비교적 균일한 상태를 가정하고 설계되었기에, 엑사바이트 규모에서 발생한 대량의 저밀도 볼륨을 빠르게 정리하기에는 역부족이었습니다. **기존 L1 압축 전략의 동작과 한계** * 기존의 L1 전략은 거의 다 채워진 '호스트 볼륨'의 빈 공간에 파편화된 '공여 볼륨(Donor)'의 데이터를 채워 넣는 방식입니다. * 이 방식은 단순하고 메타데이터 업데이트 비용이 적지만, 한 번의 실행으로 회수되는 공간이 제한적이라는 단점이 있습니다. * 데이터 밀도가 극도로 낮은 볼륨이 대량으로 존재하는 상황에서는 L1 전략의 처리 속도가 파편화 속도를 따라잡지 못해 스토리지 비용을 실시간으로 절감하기 어려웠습니다. **실용적인 결론 및 권장 사항** 대규모 불변 스토리지 시스템을 운영할 때는 데이터의 배치 로직 변화가 스토리지 효율에 미치는 영향을 실시간으로 모니터링하는 것이 필수적입니다. 특히 데이터 밀도가 급격히 변하는 이례적인 상황에 대비하여, 단순히 빈 공간을 채우는 방식의 압축뿐만 아니라 저밀도 볼륨들을 한데 묶어 대량으로 정리할 수 있는 유연한 압축 전략을 병행 구축하는 것이 인프라 비용 최적화의 핵심입니다.

dropbox

Reducing our monorepo size to improve developer velocity (새 탭에서 열림)

Dropbox는 87GB에 달하던 서버 모노레포 크기를 20GB로 약 77% 줄여 개발자 속도와 CI 효율성을 획기적으로 개선했습니다. 이 과정에서 Git의 기본 델타 압축 알고리즘이 특정 디렉토리 구조에서 비효율적으로 작동한다는 점을 발견했으며, GitHub 팀과 협력하여 최적화된 리팩(Repack) 설정을 적용해 저장소 용량 한계 문제를 해결했습니다. 결과적으로 1시간 이상 걸리던 클론 시간을 15분 미만으로 단축하며 운영상의 리스크를 제거했습니다. ### 대규모 모노레포 성장이 유발하는 운영 병목 - 저장소 크기가 87GB를 넘어서면서 초기 개발 환경 구축을 위한 클론 시간이 1시간을 초과했고, 이는 매번 신규 클론을 수행하는 CI(지속적 통합) 파이프라인의 성능 저하로 이어졌습니다. - 코드 데이터는 매일 20~60MB씩 증가하며 GitHub Enterprise Cloud의 하드 리밋인 100GB에 근접해 가고 있었으며, 이는 단순한 코드 양의 증가라기보다 저장 방식의 구조적 결함에 의한 현상이었습니다. - 내부 동기화 시스템의 타임아웃 발생 빈도가 높아지는 등 저장소 크기 자체가 엔지니어링 루프 전체를 느리게 만드는 핵심 원인이 되었습니다. ### Git 델타 압축 알고리즘과 디렉토리 구조의 충돌 - Git은 파일 간의 차이점(Delta)만 저장하여 용량을 줄이는데, 비교 대상 파일을 선정할 때 파일 경로의 '마지막 16자'만을 참조하는 휴리스틱 방식을 사용합니다. - Dropbox의 다국어(i18n) 파일 구조는 `i18n/[언어코드]/LC_MESSAGES/[파일명].po` 형태였는데, 언어 코드가 경로 중간에 있어 Git은 서로 다른 언어의 동일 파일명을 가진 파일들을 비교 대상으로 묶었습니다. - 내용이 전혀 다른 언어 간의 파일을 비교하다 보니 압축 효율이 극도로 낮아졌고, 아주 작은 번역 수정에도 불필요하게 큰 팩(Pack) 파일이 생성되는 결과로 이어졌습니다. ### GitHub 서버 측 리팩 최적화를 통한 문제 해결 - 실험적 플래그인 `--path-walk`를 사용하면 파일 경로 전체를 탐색해 압축 효율을 극대화할 수 있음을 로컬 테스트로 확인했으나, 이는 GitHub 서버의 비트맵 및 델타 아일랜드 최적화 기능과 호환되지 않았습니다. - 로컬에서 최적화하여 푸시하더라도 GitHub 서버가 전송 시 자체 설정으로 다시 팩을 구성하기 때문에, GitHub 지원팀과 협력하여 서버 측 리팩 설정을 조정하는 방식을 택했습니다. - Git이 더 넓고 깊게 유사성을 검색할 수 있도록 `window`와 `depth` 매개변수를 각각 250으로 상향 조정한 공격적인 리팩을 수행하여, 데이터 손실 없이 저장소 크기를 20GB 수준으로 압축하는 데 성공했습니다. ### 대규모 저장소 관리를 위한 제언 - 모노레포의 크기가 비정상적으로 급증한다면 단순한 바이너리 파일 유입뿐만 아니라, Git의 델타 압축 메커니즘과 현재의 디렉토리 구조가 상충하고 있지는 않은지 점검해야 합니다. - 저장소 최적화는 클라이언트 단의 노력만으로는 한계가 있으며, 호스팅 서비스(GitHub 등)의 서버 측 리팩 설정과 인프라 호환성을 반드시 고려하여 전략을 수립해야 합니다.

dropbox

How we optimized Dash's relevance judge with DSPy (새 탭에서 열림)

Dropbox는 검색 및 답변 서비스인 Dash의 핵심 기능인 '관련성 판단 모델(relevance judge)'을 최적화하기 위해 DSPy 프레임워크를 도입했습니다. 기존의 수동 프롬프트 엔지니어링 방식에서 벗어나, 인간의 평가 점수와 모델 점수 간의 차이를 최소화하는 체계적인 최적화 루프를 구축함으로써 더 저렴한 오픈 소스 모델에서도 고성능을 유지할 수 있게 되었습니다. 결과적으로 모델 교체 시 발생하는 성능 저하 문제를 해결하고, 대규모 데이터 처리를 위한 비용 효율성과 신뢰성을 동시에 확보했습니다. **인간 평가 기반의 성능 측정 체계** * 관련성 판단 모델은 쿼리와 문서의 연관성을 1~5점 척도로 할당하며, 이를 인간 평가자의 점수와 비교하여 성능을 측정합니다. * 주요 평가지표로 NMSE(Normalized Mean Squared Error)를 사용하며, 이는 AI 점수가 인간의 판단에서 얼마나 벗어나는지를 0~100 사이의 수치로 나타냅니다. * 단순 점수 외에도 프로덕션 환경에서의 안정성을 위해 JSON 출력 형식이 올바른지, 구조적 가이드라인을 준수하는지를 엄격히 관리합니다. **고비용 모델에서 효율적인 모델로의 이식** * 초기에는 성능이 뛰어난 OpenAI의 o3 모델을 사용했으나, 서비스 규모가 확장됨에 따라 수천 배 더 많은 데이터 처리를 위한 비용 절감이 필요해졌습니다. * 상대적으로 저렴한 gpt-oss-120b 모델로 이전을 시도했으나, 기존 고성능 모델에 최적화된 프롬프트가 그대로 작동하지 않아 성능 저하가 발생했습니다. * 이를 해결하기 위해 수동으로 프롬프트를 수정하는 대신, DSPy를 통해 특정 모델에 최적화된 프롬프트를 자동 생성하는 방식을 선택했습니다. **DSPy와 GEPA를 활용한 프롬프트 최적화** * DSPy의 GEPA(Generalized Evaluation-based Prompt Adaptation) 옵티마이저를 사용하여 모델이 인간과 다른 판단을 내린 지점을 분석하고 피드백을 생성합니다. * 모델의 예측 점수와 인간의 점수 차이, 그리고 인간의 작성 이유(Rationale)를 결합하여 구체적인 피드백 루프를 구성합니다. * 피드백 과정에서 특정 키워드에 과적합(Overfitting)되지 않도록 일반적인 규칙을 도출하며, "최신성을 과소평가함"이나 "키워드 일치에 과도하게 비중을 둠" 같은 구체적인 오류 패턴을 수정합니다. * 이 최적화 루프는 '평가-피드백-프롬프트 수정-재평가' 과정을 반복하며 목표 지표인 NMSE를 최소화하는 최적의 프롬프트를 찾아냅니다. **결론 및 권장사항** LLM 시스템을 프로덕션 수준으로 확장할 때 가장 큰 장애물은 모델 변경이나 프롬프트 수정 시 발생하는 예기치 못한 성능 저하입니다. Dropbox의 사례처럼 DSPy와 같은 프레임워크를 활용해 프롬프트 엔지니어링을 '체계적인 최적화 프로세스'로 전환하면, 모델 이식성을 높이고 운영 비용을 획기적으로 낮추면서도 품질을 일정하게 유지할 수 있습니다. 특히 대규모 관련성 평가가 필요한 시스템이라면 수동 튜닝 대신 측정 가능한 지표 중심의 자동화된 최적화 루프를 구축하는 것을 권장합니다.