방주
15년 넘게 3-2-1 백업의 마지막 1을 맡겨 온 Arq를 앞으로도 신뢰하기 위해 Arq 7 백업 포맷을 바이트 단위로 해부하고 개인이 검증할 수 있는 수준에서 바이트 퍼펙트하게 동작하는 validator, reader, writer를 직접 만들어 본 이야기입니다. 계속 신뢰하기로 했지만 검증도 하기로 했습니다.
독일 어딘가의 데이터센터에 제가 지금까지 쌓아 온 모든 데이터가 통째로 들어 있습니다. 경기도 집에 있는 홈랩에서 직선거리로 8천 킬로미터가 넘고 비행기로 쉬지 않고 날아도 열한 시간이 넘게 걸리는 곳입니다. Hetzner의 Storage Box 한 칸이고 용량은 20TB 남짓이며 SFTP로만 접근할 수 있습니다. 평소에는 이 백업을 열어볼 일이 거의 없습니다. 백업 하고 데이터의 무결성을 확인할 뿐 이 데이터로부터 복원할 일은 없습니다. 집의 맥이 멀쩡히 돌아가는 동안, 홈랩의 퍼포스 서버가 멀쩡한 동안, 책상 옆 외장 디스크가 멀쩡한 동안 독일의 그 사본은 그냥 거기 가만히 있습니다. 매달 얼마씩 자동으로 빠져나가는 요금 명세 말고는 그 존재를 떠올릴 일조차 거의 없습니다. 이 사본이 의미를 갖는 순간은 눈앞의 다른 모든 사본이 한꺼번에 사라진 날 단 하나뿐입니다. 화재가 집을 가져가거나 도난이 기계를 가져가거나 옆자리 기계에서 시작된 랜섬웨어가 로컬 사본을 차례로 암호화하고 지나간 날에야 비로소 독일의 사본 앞에 앉아 암호를 입력하게 됩니다.
이 마지막 한 벌이 3-2-1 백업 원칙에서 말하는 그 1입니다. 데이터는 최소 세 벌을 두고 서로 다른 매체 두 곳에 나눠 담되 그중 한 벌은 물리적으로 떨어진 곳에 둔다는 백업을 조금이라도 진지하게 다뤄 본 사람이라면 누구나 알고 있을 원칙입니다. 앞의 둘인 로컬 사본들은 사실상 복구 속도와 편의를 위한 것입니다. 실수로 지운 파일을 어제 버전으로 되돌리거나 디스크 하나가 죽었을 때 빠르게 갈아 끼우는 일에 쓰입니다. 마지막 1은 성격이 전혀 다릅니다. 이 한 벌의 유일한 임무는 한 번의 재앙에 다른 모든 사본과 함께 사라지지 않는 것입니다. 평소에 빠르거나 편할 필요가 없고 그저 가장 나쁜 날에 거기 그대로 있어 주기만 하면 됩니다. 노아가 홍수가 언제 올지 정확히는 모르면서도 미리 지어 둔 방주처럼 이 사본은 오지 않기를 바라는 날을 위해 미리 띄워 두는 배입니다. 평소에는 쓸모를 증명할 길이 없고 정작 필요한 날에는 다시 만들 시간이 없어 미리 준비해 두는 수밖에 없는 물건입니다.
그 방주를 지난 15년 넘게 띄워 준 도구가 Arq Backup입니다. 그동안 몇 번의 진짜 위기에서 저를 건져 냈고 지금도 장기 보관에 관해서는 가장 깊이 신뢰하는 도구입니다. 드라이브가 죽었을 때, 실수로 지웠을 때, 옆 기계가 랜섬웨어 비슷한 사고를 겪었을 때 결국 마지막에 손을 내민 것은 Arq가 어딘가에 올려 둔 사본이었습니다. 백업 도구에 관한 글을 여러 번 쓰면서도 Arq 자체를 정면으로 다룬 적은 없는데 지난 '크래시플랜을 사용하지 마세요'에서 값이 싼 데는 다 이유가 있다는 점을 알려준 서비스나 '개인 백업 전략'과 '백업 전략 회고 (2025)'에서 매년 시행착오를 늘어놓을 때도 그 모든 사건의 한가운데는 늘 변하지 않고 Arq가 있었기 때문입니다. 너무 당연해서 오히려 한 번도 의심해 본 적이 없는 도구였습니다.
Arq가 어떻게 시작했는지를 생각하면 이 신뢰의 뿌리가 어디에 있는지 알 수 있습니다. Stefan Reitshamer라는 개발자가 2009년 초에 혼자 만들기 시작한 도구입니다[^The story behind Arq]. 당시 그는 Time Machine을 좋아했지만 집에 있을 때만 백업이 된다는 한계가 있었고 Mozy와 Carbonite와 Backblaze 같은 서비스를 써 보니 무제한이라던 약속에 실은 온갖 단서가 붙어 있었습니다. 그래서 직접 만들기로 한 백업 도구는 시장의 빈자리를 정확히 겨냥했습니다. 맥 전용이었고 백엔드는 오직 아마존 S3였으며 사용자가 자기 AWS 계정에 직접 백업하는 구조였습니다. S3를 고른 이유도 분명했는데 내구성과 가용성 수치가 명확하고 여러 데이터센터에 복제된다는 점을 신뢰했기 때문입니다. 자기 클라우드에 자기가 직접 올린다는 이 BYO 즉 bring-your-own-storage 모델이 Arq가 17년 가까이 같은 정체성을 지켜 온 출발점입니다.
이 출발점이 왜 중요한지는 함께 출발했거나 더 컸던 경쟁자들이 어떻게 되었는지를 보면 알 수 있습니다. 같은 시기에 더 큰 마케팅 예산으로 무제한을 외치던 Mozy는 인수된 끝에 종료됐고[^Farewell to Mozy] CrashPlan은 가정용 제품을 접고 기업 시장으로 떠났으며[^CrashPlan Discontinues Consumer Backups] Arq와 가장 닮은 BYO 모델이던 JungleDisk조차 소비자 시장에서는 사실상 물러났습니다. 이들에게는 공통점이 있었는데 외부 자본이나 대기업의 자회사였고 데이터량과 무관한 정액 무제한을 약속했으며 사용자의 평균 데이터가 늘어나면서 그 경제성이 무너졌다는 점입니다. 한 회사가 사면 새 주인이 소비자 사업을 정리하는 패턴이 거의 매번 반복됐습니다. Arq는 그 반대편에 있었습니다. 외부 투자가 없었고 한 사람이 모든 결정을 내렸고 가격이 데이터량과 무관했으며 무엇보다 사용자가 자기 클라우드 비용을 직접 내기 때문에 사용자의 데이터가 늘어도 회사의 변동비가 함께 늘지 않았습니다. 데이터량과 매출과 비용 사이의 그 비대칭이 경쟁자들을 죽였고 Arq의 BYO 모델에는 애초에 그 비대칭이 없었습니다. 그래서 Arq는 같은 회사, 같은 개발자, 비슷한 가격대로 17년을 버텼습니다.
그 17년이 평탄하기만 했던 것은 아닙니다. 첫 버전의 내용 주소화 저장소는 깃에서 영감을 받은 SHA-1 기반이었고 신뢰가 본격적으로 쌓이기 시작한 것은 포맷을 공개하고 arq_restore를 BSD로 풀던 2010년대 초였습니다. 그 무렵 S3의 객체 목록 일관성 문제로 오래된 커밋 객체가 사라지는 일이 보고됐는데[^Arq 4.0] 같은 문제를 겪은 사용자가 여럿이라는 것을 확인한 Reitshamer가 빠르게 고쳐 낸 일이 그가 빨리 고치는 사람이라는 기본 신뢰의 출발점이 됐습니다. 이후 Arq 4는 Glacier와 Google Cloud Storage와 SFTP를 더했고 곧이어 Google Drive와 OneDrive까지 백엔드를 늘렸습니다. Arq 5는 2016년에 윈도우를 지원하면서 맥 전용 인디 도구가 처음으로 플랫폼을 둘로 나눠 짊어지게 됐습니다. 그런데 바로 그 윈도우 빌드에서 백업 도구가 한 번의 버그로 무엇을 할 수 있는지를 보여 준 사고가 있었습니다. 5.7.8 무렵의 버그가 예산을 0으로 강제하는 바람에 가장 최근 한 벌을 뺀 모든 백업 레코드를 지워 버린 것입니다. 다행히 곧 패치됐지만 몇 달치가 아니라 몇 년치 이력을 두고 있던 사람이라면 등골이 서늘했을 사고입니다. 마지막 1을 맡긴 도구가 스스로 그 1의 과거를 지울 수도 있다는 사실은 왜 두 번째 줄의 백업이 늘 다른 도구여야 하는지를 한 번에 알려 줍니다.
그리고 2020년에 Arq 6이 나왔습니다. Arq 역사상 가장 나빴던 한 주로 기록될 출시였습니다. 맥 네이티브 앱이던 Arq가 갑자기 Electron으로 바뀌면서 맥 커뮤니티의 핵심 인사들이 곧장 등을 돌렸고 Arq 5의 백업 셋을 6으로 가져오는 과정에서 데이터가 손상되거나 사라졌다는 보고가 쏟아졌습니다. 한 사용자의 import는 170만 건의 오류를 뱉어 냈고 Electron 인터페이스는 그 무게에 멈췄으며 에이전트 프로세서는 메모리를 25GB까지 점유했습니다[^Arq 6]. 그런데 정작 가장 큰 문제는 회사의 응답 속도였습니다. 모든 문의에 한 사람이 1:1로 답하다 보니 며칠 동안 사실상 지원이 없는 상태가 됐습니다. Reitshamer는 닷새 만에 import 기능 자체를 들어내 손해를 줄였고 사과문을 올렸으며[^Arq 6 Next Steps] 그해 9월에는 UI를 다시 네이티브로 짜겠다고 예고했습니다. 그렇게 나온 것이 2021년의 Arq 7입니다[^Arq 7: Lots More Power]. Electron을 버리고 네이티브로 돌아왔고, 체크섬을 SHA-1에서 SHA-256으로 바꿨으며, APFS 스냅샷을 정식으로 통합하고, treepacks와 blobpacks 구조와 JSON 사이드카를 도입했습니다. 비즈니스 쪽으로는 그동안의 평생 라이선스를 접고 첫해 49.99달러에 이후 연 25달러 갱신이라는 구조로 바꿨고 동시에 자기들이 클라우드를 직접 운영해 주는 Arq Premium을 연 59.99달러에 내놓았습니다. 제가 Premium을 쓰지 않는 이유는 두 가지입니다. 하나는 비용인데 제가 쓰는 Hetzner Storage Box는 오브젝트 스토리지가 아니라 SFTP뿐이라는 단점이 있지만 그 단점을 감수하고도 Premium보다 더 저렴합니다. 다른 하나는 Premium이 대신 져 주는 검증의 번거로움인데 그 부담은 validator를 직접 만들어 어느정도 완화했습니다.
그 뒤로 Arq 7은 큰 사고 없이 점진적으로 다듬어졌습니다. Storj와 Filebase와 Mega S4 같은 백엔드가 더해졌고, 사용자 데이터가 예기치 않게 지워진다는 이유로 백업 레코드 자동 솎아내기 기능을 오히려 없앴으며, GCS 객체 보존 잠금 같은 변화가 매월 소규모 패치를 통해 적용되었습니다[^Release Notes for Arq Backup Version 7.44.1]. 2026년 5월 현재 최신은 macOS용 7.44.1이고 17년이 지나도록 같은 한 사람이 매달 소규모 패치를 내고 있습니다.
그런데 바로 이 강점을 조금만 더 생각해보면 약점이 됩니다. Arq를 만드는 Haystack Software라는 회사는 공개된 외부 투자자가 없고 직원 수도 공식적으로 밝힌 적이 없으며 블로그와 지원 메일과 트위터에서 회사를 대변하는 사람은 지난 17년 내내 사실상 Stefan Reitshamer 한 명입니다. 소프트웨어 엔지니어링에서 이런 상태를 버스 펙터가 1이라고 부릅니다. 핵심 인물 한 사람이 버스에 치이면 — 어느 날 갑자기 사라지면 — 프로젝트 전체가 멈춘다는 뜻입니다. Arq의 일관된 비전과 합리적인 가격과 사용자 친화적인 결정들이 모두 이 한 사람에게서 나왔다는 사실은 강점인 동시에 그가 은퇴하거나 회사를 팔거나 건강을 잃거나 단지 흥미를 잃는 순간 그대로 위험이 된다는 뜻이기도 합니다. 매년 macOS는 한두 가지 정책을 바꾸고 그때마다 누군가는 SFTP 동작 변화나 키체인 동작 변경이나 새 권한 모델에 대응해 줘야 하는데 그 대역폭이 한 사람 분량밖에 없는 회사가 5년 뒤, 10년 뒤에도 같은 속도로 따라와 줄지는 아무도 보장하지 못합니다.
여기서 보통은 마음을 놓게 하는 답이 하나 준비되어 있습니다. Arq는 데이터 포맷을 공개해 두었고[^Arq 7 Data Format] arq_restore라는 복원 도구까지 BSD 라이선스로 풀어 두었습니다[^arqbackup/arq_restore]. 그러니 회사가 사라져도 포맷 문서를 보고 제 손으로 데이터를 꺼내면 된다는 vendor lock-in을 거부한다는 가장 강력한 약속입니다. 저도 오랫동안 이 약속을 보험 증서처럼 마음 한구석에 두고 살았습니다. 그런데 어느 순간 이 보험이 정말 보험금을 지급하는지 한 번도 확인해 본 적이 없다는 사실을 깨달았습니다. 포맷이 공개되어 있다는 것과 그 문서만 보고 실제로 동작하는 복원 도구를 만들 수 있다는 것은 다른 이야기입니다. arq_restore가 GitHub에 올라와 있다는 것과 그것이 지금 제 destination을 실제로 복원해 준다는 것도 다른 이야기입니다. 보험 증서가 서랍에 있다는 사실과 정작 청구하는 날 보험사가 멀쩡히 돈을 내준다는 사실은 전혀 다른 문제입니다. 방주가 마당에 세워져 있다고 해서 그 배가 물에 뜨리란 보장은 없습니다.
그래서 한동안 미뤄 두었던 일을 하기로 했습니다. Arq 7을 기준으로 백업 포맷의 구조와 특징을 바이트 단위까지 상세히 살펴보기로 한 것입니다. 그리고 살펴보는 데서 그치지 않고 그 과정에서 개인이 검증할 수 있는 수준에서 Arq.app과 바이트 퍼펙트하게 맞물려 동작하는 validator와 reader와 writer를 직접 만들어 보기로 했습니다. 전체 코드는 공개해 두었습니다[^neoocean/arq-backup-tui]. validator는 destination이 형식에 맞는지 그리고 모든 객체의 무결성이 유지되는지 확인하고, reader는 Arq.app이 만든 백업을 제 손으로 파일 트리로 되돌리며, writer는 거꾸로 Arq 포맷에 맞는 새 백업을 만들어 냅니다. 셋이 합쳐지면 제 데이터의 방주가 실제로 물에 뜨는지를 Arq.app 없이도 제가 직접 확인할 수 있습니다. 70k 라인에 600개가 넘는 테스트가 붙은 이 구현체의 상당 부분은 기계와 함께 만들었는데 이 작업 방식 자체에 대한 생각은 지난 '기계와 함께'에서 따로 정리한 적이 있습니다.
S3나 Wasabi나 B2나 Storj 같은 오브젝트 스토리지를 직접 다루는 클라우드 백엔드 지원은 의도적으로 만들지 않았습니다. 여러 클라우드 백엔드를 GUI에서 편하게 관리하는 일이야말로 Arq Backup의 핵심 셀링포인트라고 생각하기 때문입니다. 제 워크플로의 빈틈을 메우려고 만든 도구가 제작사의 상업적 가치를 갉아먹는다면 그것은 도구의 본분을 넘어선 일입니다. 그래서 이 구현체는 로컬과 NAS와 SFTP만 다루고 클라우드가 필요하면 rclone 마운트 같은 우회 경로를 사용하면 됩니다.
그렇게 시작한 포맷 분석은 생각보다 깊은 곳까지 내려갔습니다. Arq 7의 destination은 최상위에 컴퓨터 UUID 디렉토리를 하나 두고 그 아래에 모든 것을 담습니다. 대략 이런 모양입니다.
<destination 루트>/
└── <COMPUTER-UUID>/ # 8-4-4-4-12 대문자 hex
├── encryptedkeyset.dat # 마스터 키 묶음(암호화)
├── backupconfig.json # 컴퓨터별 설정
├── backupplan.json # 백업 plan 스냅샷
├── backupfolders.json # 디렉토리 색인
├── standardobjects/<2hex>/<62hex> # 낱개 blob
├── treepacks/<2hex>/<UUID>.pack # 트리 blob 묶음
├── blobpacks/<2hex>/<UUID>.pack # 데이터 blob 묶음
├── largeblobpacks/<2hex>/<UUID>.pack # 큰 blob 묶음
└── backupfolders/<FOLDER-UUID>/
├── backupfolder.json
└── backuprecords/<bucket>/<num>.backuprecord
이 구조에서 가장 먼저 눈에 들어오는 특징은 destination이 그 자체로 자기를 설명한다는 점입니다. 클라이언트 쪽에 별도의 카탈로그 데이터베이스가 없어도 이 디렉토리 하나만 있으면 모든 백업 정보를 다시 구성할 수 있습니다. 모든 백업의 의미가 destination 안의 내용 주소화된 그래프 한 장으로 표현되어 있는데 그래프의 뿌리는 backuprecord라는 JSON 봉투이고 그 안의 treeBlobLoc이 암호화·압축된 바이너리 Tree를 가리키며 Tree 안의 각 Node가 pack 내부의 실제 blob 조각들을 가리킵니다. 이 방식 덕분에 destination은 S3나 B2 같은 평범한 불변 객체 저장소 위에 그대로 올라갈 수 있고 별도의 서버 프로세스도 필요 없습니다. 읽을 때는 그저 위치와 길이를 알고 해당 범위를 잘라 오면 됩니다.
모든 blob은 ARQO라는 봉투에 담깁니다. 봉투의 구조는 이렇습니다.