2011년, 2001년, 1996년. 이 글에서 다루는 세 편의 논문이 발표된 해예요. 그런데 15년의 시차가 있는 이 논문들이 지금 여러분의 홈서버에서 돌아가는 Syncthing, rclone, restic의 동작 방식을 그대로 결정짓고 있습니다. CRDT, rsync 알고리즘, LBFS의 콘텐츠 정의 청킹은 각각 다른 학회, 다른 저자, 다른 문제의식에서 출발했지만 결국 “네트워크로 데이터를 어떻게 효율적으로 맞출 것인가”라는 같은 질문의 세 가지 답이었어요. 그렇다면 이 세 논문의 문제의식 차이가 실제로 어떤 도구를 언제 써야 하는지를 어떻게 갈라놓을까요?
CRDT 논문(2011)은 어떤 문제를 풀려고 했나?
CRDT는 여러 복제본이 동시에 값을 바꿔도 중앙 조율 없이 결국 같은 상태로 수렴하는 자료구조예요. Marc Shapiro, Nuno Preguiça, Carlos Baquero, Marek Zawirski가 2011년 SSS(Stabilization, Safety, and Security of Distributed Systems) 학회에 발표한 이 논문은 “복제본 간 원격 동기화 없이도 갱신을 즉시 받아들이면서, 결국 모든 복제본이 같은 상태로 수렴한다는 걸 수학적으로 보장할 수 있는가”라는 질문에서 출발했습니다. 논문은 이를 강한 최종적 일관성(Strong Eventual Consistency)이라는 형식 모델로 정의하고, 상태 기반(state-based)과 연산 기반(operation-based)이라는 두 가지 접근에 대해 이 조건을 만족시키는 충분조건을 각각 증명했어요. 핵심은 “충돌을 해결하는 로직”이 아니라 “애초에 충돌이 발생하지 않도록 자료구조 자체를 설계”한다는 발상 전환에 있어요.
rsync 알고리즘 논문(1996)은 어떤 문제를 풀려고 했나?
rsync 알고리즘은 두 기기에 이미 비슷한 파일이 각각 존재할 때 바뀐 부분만 네트워크로 전송해 대역폭을 아끼는 방법이에요. Andrew Tridgell과 Paul Mackerras가 호주국립대(ANU) 기술보고서(TR-CS-96-05)로 1996년 발표한 이 논문은 “저대역폭·고지연 양방향 링크로 연결된 두 기기에서, 파일 전체를 다시 보내지 않고 한쪽 파일을 다른 쪽과 동일하게 맞추려면 어떻게 해야 하는가”라는 문제를 다뤘습니다. 목적지 파일을 고정 크기 블록으로 나눠 약한 체크섬과 강한 체크섬을 계산해 원본 쪽으로 보내면, 원본은 자신의 데이터를 롤링 체크섬으로 훑으며 일치하는 블록을 찾아내고 일치하지 않는 부분만 전송하는 방식이에요. 이 논문이 겨냥한 시나리오는 파일이 비슷할수록 유리하지만, 파일이 완전히 달라도 정상적으로 동작한다는 점이 핵심 기여였어요.
LBFS 콘텐츠 정의 청킹 논문(2001)은 어떤 문제를 풀려고 했나?
LBFS는 파일 중간에 내용이 삽입되거나 삭제돼도 나머지 대부분을 재사용해 대역폭을 아끼는 네트워크 파일시스템이에요. Athicha Muthitacharoen, Benjie Chen, David Mazières가 SOSP 2001(제18회 ACM 운영체제 원리 심포지엄)에 발표한 이 논문은 “파일을 고정 크기로 자르면 파일 맨 앞에 한 글자만 추가돼도 그 뒤 모든 블록의 경계가 밀려버려 중복 탐지가 무력화된다”는 문제에서 출발했습니다. 해결책은 파일 내용 자체로 청크 경계를 정하는 것이었어요. 48바이트 슬라이딩 윈도우의 Rabin 지문을 계산하다가 하위 13비트가 0이 되는 지점을 청크 경계로 삼으면, 평균 8KB 크기의 청크가 만들어지고 이 경계는 파일 어디에 삽입·삭제가 일어나든 그 지점 주변 청크만 바뀔 뿐 나머지 청크는 그대로 유지돼요. 논문은 이 방식으로 일반적인 워크로드에서 기존 NFS 대비 최대 두 자릿수(최대 100배) 수준의 대역폭 절감을 보고했습니다.
그래서 Syncthing은 왜 그렇게 동작할까?
Syncthing이 실시간 기기 간 동기화에 강한 이유는 CRDT의 문제의식과 닿아있으면서도 실제 구현은 훨씬 단순화되어 있기 때문이에요. Syncthing의 Block Exchange Protocol(BEP) 공식 스펙을 보면, 여러 기기가 가진 같은 폴더의 파일 버전 중 “전역(global) 버전”을 하나 선택하고 각 기기가 그 버전으로 수렴하도록 블록을 요청·전송하는 구조인데, 이는 CRDT가 추구하는 “중앙 조율 없는 수렴”이라는 목표와 방향이 같아요. 다만 공식 문서 어디에도 CRDT라는 용어는 등장하지 않고, 실제 충돌 해결은 수정 시각과 기기 ID를 비교해 한쪽을 .sync-conflict 파일로 남기는 비교적 단순한 최종 갱신 우선(LWW) 방식이라, CRDT 논문이 증명한 “자동 병합 수렴”보다는 훨씬 실용적으로 타협된 형태예요. 블록 나누기 방식도 흥미로운데, LBFS의 콘텐츠 정의 청킹과 달리 Syncthing은 파일 크기에 따라 블록 수가 2000개를 넘지 않도록 정해진 고정 블록 크기(128KiB~16MiB, 2의 거듭제곱 단위)를 쓰기 때문에, 파일 앞부분에 데이터가 삽입되면 뒤따르는 블록 경계가 전부 밀려 재전송 범위가 커질 수 있어요. Syncthing으로 클라우드 없이 기기 간 파일을 동기화하는 방법은 이런 실시간성과 P2P 구조에 최적화된 반면, 저장공간을 최소화하는 데는 상대적으로 약점을 갖는 이유가 여기에 있어요.
그래서 rclone은 왜 파일 전체를 다시 올릴까?
rclone이 변경된 파일을 통째로 다시 업로드하는 이유는 rsync 알고리즘이 요구하는 조건을 클라우드 스토리지 API가 애초에 제공하지 않기 때문이에요. rsync 알고리즘은 목적지가 자신의 파일을 블록 단위로 체크섬화해 원본 쪽에 돌려보내고, 원본이 롤링 체크섬으로 일치 구간을 찾아 차이만 보내는 양방향 상호작용을 전제로 합니다. 그런데 Google Drive, AWS S3, Backblaze B2 같은 클라우드 오브젝트 스토리지는 “이미 저장된 객체의 일부 바이트 범위만 갱신”하는 API 자체를 제공하지 않아서, rclone은 로컬 파일과 원격 파일의 체크섬이나 수정 시각을 비교해 변경 여부만 판단하고 변경됐다면 파일 전체를 새로 전송해요. --checksum 옵션을 켜면 이 사전 비교를 수정 시각 대신 체크섬으로 더 정확하게 할 수 있지만, 그렇다고 rsync처럼 파일 내부의 일부 바이트만 전송하는 건 아니라는 점은 변하지 않습니다. 대신 rclone은 40개가 넘는 클라우드 제공사를 하나의 명령 체계로 다루는 폭과 병렬 전송 성능에 집중한 도구이고, 이 전략이 통하는 이유는 rclone으로 클라우드 스토리지를 동기화·백업하는 글에서 다룬 것처럼 rclone의 역할이 이미 만들어진 백업 결과물을 오프사이트로 복제하는 “마지막 다리”이기 때문이에요 — 매번 통째로 올리더라도, 그 앞단에서 저장공간과 전송량을 이미 줄여놓은 restic 같은 도구와 짝을 이루면 문제가 되지 않아요.
그래서 restic은 왜 저장공간을 적게 쓸까?
restic이 반복 백업에서도 저장공간을 적게 쓰는 이유는 rsync 계열이 아니라 LBFS 계열의 콘텐츠 정의 청킹을 저장 전략의 핵심으로 채택했기 때문이에요. restic 공식 설계 문서는 “Rabin 지문을 이용한 콘텐츠 정의 청킹(CDC)“을 명시하고 있고, 512KiB~8MiB 범위에서 평균 1MiB 크기의 가변 청크로 파일을 잘라 각 청크를 SHA-256 해시로 식별합니다. restic init 시점에 저장소마다 고유한 64비트 다항식을 생성해 청크 경계 계산에 쓰기 때문에, LBFS 논문이 증명한 대로 파일 중간에 몇 바이트가 삽입되거나 삭제돼도 그 지점 주변 청크 몇 개만 새로 저장되고 나머지 청크는 이미 저장소에 있는 것을 그대로 재사용해요. 이 재사용은 한 번의 백업 안에서만이 아니라 저장소 전체의 모든 이전 백업에 걸쳐 이루어지기 때문에, 매일 전체 백업을 돌려도 실제로 디스크에 새로 쓰이는 양은 바뀐 부분에 비례할 뿐이에요. Restic과 Duplicati를 비교한 글에서 다뤘듯 restic이 가볍고 빠르다는 평가를 받는 배경에는, 목적 자체가 “네트워크로 옮기는 데이터량을 줄이는 것”이 아니라 “저장소에 쌓이는 데이터량을 줄이는 것”이라는 설계 초점의 차이가 있어요.
속도·대역폭·저장공간, 세 축으로 정리하면
세 도구의 트레이드오프는 각자가 계승한 논문이 애초에 무엇을 최적화 대상으로 삼았는지를 그대로 반영합니다. Syncthing은 CRDT가 추구한 “조율 없는 수렴”을 실용적으로 구현해 여러 기기 사이의 반영 지연을 최소화하는 데 최적화돼 있고, 그 대가로 저장공간 절약이나 시점별 복구 같은 백업 본연의 기능은 없어요. rclone은 rsync 알고리즘이 전제한 양방향 델타 전송을 클라우드 API 한계 때문에 포기한 대신, 어떤 클라우드로든 파일을 옮길 수 있는 범용성과 전송 속도 자체(병렬 업로드, 멀티스레드)에 집중한 도구이고, LBFS 계열의 청킹이 없어 저장공간 관점에서는 원본 파일 크기만큼 그대로 소비돼요. restic은 LBFS의 콘텐츠 정의 청킹을 저장 계층에 적용해 저장공간을 가장 아끼지만, 네트워크로 옮기는 순간의 전송 속도 자체는 청크 해싱과 암호화 연산 때문에 단순 파일 복사보다 느릴 수 있습니다.
- 여러 기기의 최신 상태를 실시간으로 맞추고 싶다면: Syncthing이 맞아요. 서버 없이 P2P로 즉시 반영되지만, 이건 백업이 아니라 동기화라는 점을 기억해야 해요.
- 로컬 백업을 오프사이트 클라우드로 옮기는 마지막 다리가 필요하다면: rclone이 맞아요. 40개가 넘는 클라우드를 하나의 명령으로 다루지만 변경분만 골라 보내진 않는다는 걸 감안해야 해요.
- 반복 백업으로 쌓이는 저장공간과 중복을 최소화하고 싶다면: restic이 맞아요. 청크 단위 중복 제거 덕분에 매일 전체 백업을 돌려도 실제 증가량은 작아요.
- 세 마리 토끼를 한 번에 잡고 싶다면: 한 도구로는 안 되고, Syncthing(기기 간 실시간 동기화) + restic(시점별 백업, 저장공간 절약) + rclone(오프사이트 복제)을 계층으로 쌓는 조합이 3-2-1 백업 원칙에도 가장 잘 들어맞아요.
결론
2011년의 CRDT, 1996년의 rsync 알고리즘, 2001년의 LBFS는 표면적으로는 전혀 다른 논문이지만, 결국 “네트워크로 무엇을 얼마나 보낼 것인가”라는 같은 문제를 서로 다른 축에서 풀어낸 세 가지 답이었어요. Syncthing이 실시간성에, rclone이 범용성과 전송 속도에, restic이 저장공간 효율에 각각 강한 이유는 우연이 아니라 이 도구들이 계승한 논문의 문제의식이 애초에 달랐기 때문입니다. 어떤 도구를 골라야 할지 고민된다면, “나에게 지금 부족한 게 실시간 반영인지, 오프사이트 복제인지, 저장공간인지”부터 따져보는 게 논문 세 편의 30년 역사를 가장 실용적으로 활용하는 방법이에요.
참고 자료
- Shapiro, M., Preguiça, N., Baquero, C., Zawirski, M. (2011). Conflict-free Replicated Data Types. SSS 2011, Springer LNCS 6976. 원문 PDF
- Tridgell, A., Mackerras, P. (1996). The rsync algorithm. Technical Report TR-CS-96-05, Australian National University. 공식 페이지
- Muthitacharoen, A., Chen, B., Mazières, D. (2001). A Low-bandwidth Network File System. SOSP 2001. 원문 PDF
- Syncthing Block Exchange Protocol 공식 문서
- restic 공식 설계 문서
- rclone 공식 문서
자주 묻는 질문
Q1. Syncthing, rclone, restic 중 성능이 가장 좋은 도구는 뭔가요?
상황마다 다릅니다. 여러 기기 간 실시간 반영 속도는 Syncthing이, 클라우드로의 초기 대량 업로드는 rclone의 병렬 전송이, 반복 백업 시 저장공간 절약은 restic의 청크 단위 중복 제거가 각각 가장 유리해요.
Q2. rclone도 rsync처럼 바뀐 부분만 전송하나요?
아니요, rclone은 대부분의 클라우드 백엔드에서 파일이 바뀌면 전체를 다시 업로드합니다. S3나 Google Drive 같은 클라우드 API 자체가 rsync 알고리즘이 요구하는 롤링 체크섬 비교나 부분 패치 업로드를 지원하지 않기 때문이에요.
Q3. restic은 rsync와 같은 알고리즘을 쓰나요?
아니요, restic은 rsync의 롤링 체크섬 방식이 아니라 LBFS 논문에서 제안된 콘텐츠 정의 청킹(Content-Defined Chunking)을 씁니다. Rabin 지문으로 파일을 가변 크기 청크로 자르고 청크 해시로 중복을 제거하는 방식이라 목적이 데이터 이동 최소화가 아니라 저장공간 절약에 있어요.
Q4. Syncthing은 CRDT를 그대로 구현한 프로그램인가요?
아니요, Syncthing 공식 문서에는 CRDT라는 용어가 등장하지 않습니다. 파일별로 가장 최신 버전을 전역 상태로 채택하고 충돌이 나면 두 버전을 모두 `.sync-conflict` 파일로 남기는 방식이라, 자동 병합을 보장하는 CRDT의 이상보다는 단순화된 최종 갱신 우선(LWW) 방식에 가까워요.
Q5. 세 도구를 함께 쓰는 조합도 있나요?
네, 흔한 조합이에요. Syncthing으로 여러 기기의 최신 파일을 실시간으로 맞추고, restic으로 그 데이터의 시점별 백업을 만든 뒤, restic 저장소를 rclone으로 오프사이트 클라우드에 복제하는 3단 구조를 쓰는 홈랩 사용자가 많습니다.
Q6. 파일 하나의 중간 내용만 바꿔도 세 도구의 동작이 다 다른가요?
네, 크게 갈립니다. restic은 청크 경계가 바뀐 지점 이후 몇 개 청크만 새로 저장하고, Syncthing은 블록 크기가 파일 크기로 고정돼 있어 뒤 블록들이 밀리면 재전송 범위가 커질 수 있고, rclone은 애초에 부분 전송 자체를 하지 않아 파일 전체가 다시 올라가요.
관련 글


