백업이 진짜 백업인지

「돌았다」가 아니라 「받는 쪽에 온전히 있고, 거기서 되살릴 수 있다」

협동조합과 사회연대경제 조직의 서버와 자료를 AI와 함께 옮기고 지키면서 겪은 백업 사고를 모았습니다. 사례는 모두 품앗이와 함께 일한 현장에서 나왔고, 조직 이름과 기계 이름은 지웠습니다.

한 줄로

백업은 스크립트가 성공했다는 말이 아니라, 받는 쪽에 자료가 온전히 있고 거기서 되살릴 수 있다는 사실입니다. 그리고 실패했을 때 그 실패를 읽는 누군가가 있어야 백업입니다.

1. 백업의 증거는 받는 쪽에 있다

기록에는 「매일 동기화 가동 중, 첫 실행 검증 완료」라고 적혀 있었습니다. 받는 쪽 서버를 직접 재 보니 53일 동안 새로 들어온 파일이 한 건도 없었습니다. 첫 실행이 성공한 것만 보고 「가동 중」이라 적은 기록이 다음 사람의 눈을 가린 것입니다.

「가동 중」이라고 적을 때는 받는 쪽을 실제로 잰 날짜를 같이 적습니다. 날짜 없는 「가동 중」은 믿지 않습니다.

받는 쪽에서는 파일 수, 용량, 마지막 성공 표시, 가장 최근 파일의 날짜 이렇게 네 가지를 봅니다. 보내는 쪽 로그의 「성공」은 참고로만 씁니다.

현장 기록에 따르면 백업 스크립트가 성공을 알렸는데 담긴 파일이 0개였던 일도 있습니다. 「담았다」가 아니라 「몇 개 담겼다」를 찍게 합니다. 이 판정법은 「끝났다」를 무엇으로 판정하나에서 더 자세히 다룹니다.

백업 축을 하나 더 세울 때는 스크립트를 복사해 만들지 않습니다. 같은 스크립트에서 대상만 환경변수로 바꿉니다. 복사해 두면 언젠가 한쪽만 고쳐지는 날이 옵니다.

2. 울리는데 아무도 받지 않는 경보는 없는 것과 같다

사고 기록에 따르면 본체 백업이 7일 연속 「실패」 알림을 보냈고, 알림 전송 자체는 매번 성공했는데 아무도 조치하지 않았습니다. 실패 알림은 누가 받아서 무엇을 하는지까지 정해져 있어야 알림입니다.

한 협동조합의 오프사이트 백업은 어느 날 새벽부터 멈춰 있었습니다. 스크립트는 정직하게 실패 코드를 내고 로그에 실패를 남겼지만, 그 로그를 읽는 것이 없었습니다. 감시 장치를 둔 다른 조합에서는 이상을 알아챘습니다.

실패 코드를 내는 것과 누가 그것을 읽는 것은 다른 일입니다. 실패를 알리는 백업을 세우는 날, 그 실패를 읽을 자리도 같은 날 함께 세웁니다.

반대 방향의 함정도 있어서, 감시 스크립트를 고쳐 놓고 배포를 빠뜨려서 옛 사본이 계속 경보를 낸 일이 있었습니다. 그런데 기록을 다시 보니 그 경보는 처음 엿새 동안은 진짜였고, 그 사이 백업 6회가 모두 실패했습니다. 경보가 울리면 「또 오경보겠지」로 넘기지 않고 받는 쪽 실물부터 손으로 잽니다.

3. 권한 하나 고친 것이 백업을 깬다

한 협동조합의 사고 기록에 따르면 다른 서비스가 폴더를 지나가지 못하는 문제를 고치느라 폴더 소유자를 바꾼 일이 있었습니다. 그런데 같은 경로를 전제로 둔 백업 전용 접속이 조용히 깨졌습니다. 그 접속은 가둔 폴더 안에서만 움직이게 설정돼 있었는데, 이 설정은 경로의 소유자가 바뀌면 접속을 거부합니다.

증상은 인증 실패가 아니라 「접속하고 1초 만에 끊김」이었습니다. 스크립트 로그에는 「저쪽 목록이 비었다」만 남았습니다. 이 한 줄은 열쇠 문제로도, 파일이 없는 것으로도 읽혀서 둘 다 헛짚게 됩니다.

따라 하기

  • 권한이나 소유자를 바꾸기 전에 그 경로를 전제로 둔 것을 전부 셉니다. 접속 설정, 서비스 설정, 디스크 연결 설정을 모두 뒤집니다.
  • 바꾼 뒤에는 그 경로를 쓰는 쪽을 하나씩 모두 실제로 확인합니다. 두 가지 고침이 각자 「통과」를 찍으면 그 사이의 구멍은 어느 쪽 검사에도 걸리지 않습니다.

「백업이 없다」고 말하기 전에는 대장부터 읽습니다. 방금 만든 한 칸만 보고 조합 전체에 백업이 없다고 알렸는데, 실제로는 두 조합 모두 백업이 돌고 있었던 일이 있습니다.

4. 범위는 실측으로 정한다

이관 기록에 따르면 지시서가 「본체 데이터는 홈 폴더 22GB」라고 해서 그대로 잡은 일이 있었습니다. 실제로는 다른 사용자의 홈 폴더, 별도로 깔린 실행 환경, 관리자 홈 폴더가 더 있었고, 원본 서버를 지우기 직전에야 발견했습니다. 지시서는 원하는 것을 말하지 현장에 있는 것을 말하지 않으므로, 디스크를 크기 순으로 직접 셉니다.

「캐시니까 뺀다」는 관행 때문에 AI 검색용 벡터 DB 167MB를 지울 뻔한 일도 있습니다. 이름이 캐시 폴더 아래에 있다고 캐시는 아닙니다. 제외 목록은 크기 순으로 하나씩 열어 보고 정합니다.

백업본에서 파일 권한 정보가 0개로 나와 「권한이 안 넘어갔다」고 판단했는데, 사실은 받는 쪽에 그것을 재는 도구가 깔려 있지 않았습니다. 도구를 깔고 다시 재니 원본과 같았습니다. 측정값이 0이면 대상보다 재는 도구부터 의심합니다.

사이트가 라이브로 잘 떠 있어서 다섯 달 동안 git 백업이 0건인 것을 몰랐던 일도 있습니다. 그 폴더는 한 번도 추적된 적이 없었고, 무시 목록이 소스 파일까지 막고 있었습니다. 라이브로 떠 있다는 것은 백업이 있다는 뜻이 아닙니다. 새 폴더가 생기면 추적 정책부터 확인합니다.

클라우드 드라이브의 계정 사용량과 폴더 합계가 192GiB나 달랐던 일도 있습니다. 데스크톱 동기화 프로그램이 만든 백업 폴더는 드라이브의 맨 위 목록에 잡히지 않았습니다. 총계와 트리의 합이 다르면 트리가 틀린 것입니다.

5. 무엇을 백업이라 부를 수 있나

화면 내보내기는 백업이 아니다

한 현장에서는 옛 홈페이지 신청 폼이 20여 칸을 받는데, 관리자 화면의 내보내기 파일에는 7칸만 들어 있었습니다. 유일본에 대해 불완전한 사본을 만들면 「받아 놨다」는 안심만 생깁니다.

같은 현장의 판단에 따르면 순서는 다음과 같아야 합니다.

  1. DB 덤프로 구조와 데이터를 모두 받습니다.
  2. 덤프에 들어가지 않는 첨부 파일을 따로 받습니다.
  3. 덤프의 행 수를 화면이 알려 주는 건수와 대조하고, 맞지 않으면 백업으로 치지 않습니다.
  4. 화면 긁기는 1과 2가 막혔을 때만, 밤에 순서대로 간격을 두고 합니다.

같은 현장 기록에 따르면 화면을 긁으면 남의 운영 서버에 733쪽을 요청해야 했고, 덤프는 한 번이면 됐습니다.

DB 파일 하나만 복사하면 빈 DB를 옮긴다

로그 선기록 방식을 쓰는 SQLite는 실제 데이터가 본체 옆의 별도 파일에 들어 있을 수 있습니다. 한 현장에서는 본체 파일이 4KB짜리 껍데기였습니다. SQLite가 제공하는 온라인 백업 기능으로 일관된 스냅샷을 뜨고, 파일 크기가 아니라 열어서 행 수를 셉니다. DB 파일이 두 벌 있으면 옮길 때 빈 쪽이 따라오기도 합니다.

백업 기능이 담지 않는 것

한 그래프 DB의 백업 기능은 사용자 계정 정보를 담지 않았고, 설정으로 바꿔도 서버가 그 설정을 무시했습니다. 그대로 복원하면 아무도 로그인하지 못하므로 계정 파일은 따로 백업합니다.

같은 서버에서 백업이 다른 무거운 작업과 겹치자 메모리가 모자라 서버가 죽었습니다. 백업 시각은 이미 잡혀 있는 예약 작업과 대조해 빈 시간대에 둡니다. 메모리 설정은 문서에 적힌 값이 아니라 실제로 돌고 있는 값을 확인합니다.

키를 함께 안은 백업

드라이브나 홈 폴더를 통째로 백업하면 그 안의 키와 토큰도 통째로 옮겨집니다. 키를 함께 안은 백업은 백업이 아니라 유출 사본입니다. 자세한 사례와 처방은 자동 백업과 배포가 비밀을 실어 간다에 있습니다.

6. 여러 벌 보관은 선언이 아니라 상태다

인수인계 기록에는 백업을 푸는 복호화 키가 「3곳」에 있다고 적혀 있었습니다. 그런데 운영체제를 새로 깔면서 그 안의 가상 환경과 함께 한 곳이 사라졌고, 다음 날 디스크를 정리하다 우연히 발견할 때까지 아무도 몰랐습니다. 남은 한 곳이 다른 디스크에 있어서 살아남은 것은 운이었습니다.

「운영체제를 민다」는 말은 그 안의 가상 환경과 컨테이너를 모두 같이 민다는 뜻입니다. 재설치 계획에는 「안에 든 것」 목록을 넣습니다. 같은 기계 안의 두 곳은 두 곳이 아니라 1.5곳입니다. 키를 다시 맞춰 볼 때는 값을 화면에 띄우지 않고 파일 크기로 대조합니다.

7. 지우기 전에

받은 것을 확인한 뒤에 지운다

사고 기록에 따르면 「압축하고, 올리고, 결과를 걸러 보고, 지운다」를 한 줄 명령으로 이은 일이 있었습니다. 올리기는 실패했는데 그 줄의 마지막 명령이 성공으로 끝나서 지우기가 실행됐습니다. 백업하고 지우는 일은 한 줄로 잇지 않습니다. 받는 쪽에 있는지 따로 확인한 뒤에 지웁니다. 클라우드 도구가 「삭제 성공」이라고 답해도 목록을 다시 불러와 확인합니다.

암호화된 디스크를 먼저 확인한다

한 현장의 기록에 따르면 윈도를 밀고 난 뒤에야 둘째 디스크가 BitLocker로 암호화돼 있었다는 것을 안 일이 있습니다. 윈도 안에서는 자동으로 열려 있어서 사람 눈에는 잠긴 것이 보이지 않았습니다. 「그 디스크는 안 건드린다」는 계획이었지만, 열쇠를 쥔 윈도를 지우는 순간 그 디스크도 건드린 것과 같았습니다.

이번에는 암호화가 켜져 있되 보호 장치가 실제로 활성화되지 않은 상태여서 복구 키 없이 열 수 있었고, 자료 70GB를 살렸습니다. 그런 상태가 아니었다면 복구 키가 필요했을 것이고, 그 키는 PC가 아니라 그 PC에 로그인했던 클라우드 계정에 있을 수 있습니다. 지우기 전 확인 목록에 「암호화된 볼륨」 칸을 고정해 둡니다.

정리는 이동이지 삭제가 아니다

폴더를 정리하면서 원본을 남겨 둔 덕분에 나중에 필요한 파일을 찾은 일이 있습니다. 삭제는 명시적으로 승인받은 뒤에 하고, 원본과 정리본이 어떻게 이어지는지 대응표를 남깁니다.

파일 이동 도구에서 「옮기지 못한 파일은 원본에 남긴다」는 선택지를 켜 놓고 원본 폴더를 통째로 지우면, 옮겨지지 않은 파일까지 함께 사라집니다.

같은 크기, 다른 해시

드라이브 정리 기록에 따르면 이름도 크기도 같은데 해시만 다른 사진 사본이 2,533묶음 있었습니다. 열어 보니 클라우드 사진 동기화로 생긴 사본은 촬영 일시와 위치 정보가 0으로 지워진 판이었습니다. 증빙 사진이라면 그 정보가 곧 증거 가치입니다.

중복을 정리할 때는 촬영 정보가 살아 있는 쪽을 남기고, 어느 쪽이 원본인지 판정하지 못한 묶음은 둘 다 보존합니다. 표본 몇 개는 바이트 단위로 비교해 어디가 다른지 봅니다.

8. 다 받아야만 알 수 있다는 전제를 의심한다

98GiB짜리 압축 파일 안에 무엇이 들었는지 알려고 통째로 받을 필요는 없었습니다. zip은 파일 목록을 맨 끝에 둡니다. 끝부분과 목록만 받는 데 4초가 걸렸고, 5,153개 파일 목록을 본 뒤 필요한 287개만 해당 구간을 받아 검사값으로 확인했는데, 실제로 받은 양은 484MB였습니다.

파일 형식의 구조를 알면 대개 일부만 읽어도 됩니다. 동영상 파일과 PDF도 색인을 따로 두는 형식입니다.

9. 백업 계층을 나누는 법

백업은 성격에 따라 한 계층이 1차 책임을 지게 나눕니다.

계층맡는 것
재앙 복구디스크 전체 스냅샷
버전 이력git, 텍스트로 된 정본만
산출물문서와 영상, 드라이브 계열
데이터셋원자료와 DB 덤프

오프사이트는 같은 사무실이 아닌 곳입니다. 같은 사무실에 둔 기계 여러 대는 불이 나거나 물이 들면 함께 사라집니다. 협력하는 조직끼리 서로의 오프사이트가 되어 주는 상호 백업도 하나의 방법입니다.

흩어진 사본을 하나로 합칠 때는 이 순서를 지킵니다.

  1. 무엇이든 옮기기 전에 먼저 안전망을 두 겹으로 만들어 둡니다.
  2. 양쪽을 비교해 한쪽에만 있는 것을 찾아냅니다.
  3. 이미 있는 것과 부딪히지 않게 빠진 것만 복사합니다.
  4. 파일만 합치면 검색에 잡히지 않으니, 합친 파일을 검색 색인에도 올립니다.
  5. 이 네 가지가 끝난 다음에야 옛 자리를 지웁니다.

일곱 줄로 줄이면

  1. 백업의 증거는 받는 쪽의 파일 수와 최신 날짜다.
  2. 실패를 알리는 백업을 세우는 날, 그 실패를 읽을 자리도 같이 세운다.
  3. 권한을 바꾸기 전에 그 경로를 쓰는 것을 전부 세고, 바꾼 뒤에 전부 확인한다.
  4. 범위는 지시서가 아니라 디스크를 크기 순으로 세어 정한다.
  5. 화면 내보내기와 DB 파일 한 장 복사는 백업이 아니니, 덤프를 받고 행 수를 대조한다.
  6. 「3곳」은 적힌 숫자가 아니라 오늘 잰 숫자여야 한다.
  7. 지우기 전에 받는 쪽 확인, 암호화 볼륨 확인, 원본 보존.

관련 노드