Skip to content
isdnetworks
Go back

옮기고 나서 가리키는 것을 안 고쳤다

df 에 남은 자리가 얼마 없길래 수집 자료의 저장 경로를 다른 볼륨으로 옮겼다. 수집은 정상으로 돌았는데 며칠 뒤에 통계가 비어 있었다.

옮기는 것 자체는 명령 한 줄이었다. 손이 간 것은 그 자리를 가리키던 것들이었다.

Table of contents

Open Table of contents

가리키는 것이 여럿이었다

무엇이 옛 경로를 알고 있는지 적어 봤다.

수집 스크립트     설정 파일에서 읽음      → 고침
통계 배치        코드에 박혀 있음        → 안 고침
백업 스크립트     코드에 박혀 있음        → 안 고침
정리 배치        설정 파일에서 읽음      → 고쳐짐
감시 스크립트     코드에 박혀 있음        → 안 고침
문서            옛 경로 적혀 있음       → 안 고침

설정 파일을 읽는 둘만 새 자리 /mnt/data2/collect 를 따라왔다. 나머지 넷은 옛 자리를 그대로 보고 있었다.

통계가 빈 것도 그래서였다. 배치는 오류를 안 내고 정상으로 돌면서 옛 자료만 세고 있었다. 폴더도 있고 파일도 있으니 그쪽에서는 이상할 것이 없었다.

옮긴 대상은 하나인데 그것을 가리키는 것이 여섯이었다. 바꾸는 작업의 크기는 대상이 아니라 가리키는 쪽의 수로 정해졌다.

원인 — 설정을 읽는 쪽과 박아 둔 쪽

고쳐진 둘과 안 고쳐진 넷을 가른 것은 값을 어디서 얻느냐였다. 설정 파일을 읽는 쪽은 설정 한 줄을 고치니 같이 바뀌었다.

통계 배치처럼 코드에 경로가 박힌 쪽은 그 .py 파일을 직접 열어야만 바뀐다. 어느 파일에 박혔는지를 아는 사람이 그때 없으면 안 바뀐 채로 남는다.

값을 아는 자리가 흩어져 있으면 고칠 때마다 같은 수색을 반복하게 된다. 이번에 넷을 빠뜨린 것은 기억에 의존해서 고쳤기 때문이었다.

옛 값으로 검색해 세어 봤다

기억 대신 grep -rn 으로 옛 경로 /data/collect 를 훑었다.

$ grep -rn "/data/collect" --include=*.py --include=*.sh --include=*.md . | wc -l
      23

파일 형식을 --include 로 좁혀 스물세 곳이 나왔다. 안 좁히면 수가 크게 늘어난다.

$ grep -rn "/data/collect" . 2>/dev/null | wc -l
      41

--include 없이 세면 마흔한 곳이고 여기에는 로그와 임시 파일이 섞여 있다. 그것까지 고칠 것은 아니므로 형식을 좁힌 쪽을 작업 목록으로 삼았다.

이 검색을 옮기기 전에 먼저 돌렸으면 좋았다. 몇 군데인지 알고 시작하는 것과 옮긴 뒤에 하나씩 발견하는 것은 다른 일이다.

설정 — 흩어진 값을 한 곳으로

각자 박아 두던 경로를 파일 하나에서 읽게 했다.

# /etc/collect/paths.conf
DATA_DIR=/mnt/data2/collect
BACKUP_DIR=/mnt/backup/collect
LOG_DIR=/var/log/collect

파이썬 쪽은 configparser 로 읽는다.

import configparser
cfg = configparser.ConfigParser()
cfg.read('/etc/collect/paths.conf')
DATA_DIR = cfg['DEFAULT']['DATA_DIR']

셸 쪽은 그냥 읽어 들인다.

. /etc/collect/paths.conf

같은 파일을 configparser 도 셸도 읽을 수 있게 하려고 값에 공백과 따옴표를 안 넣기로 했다. 형식을 한 칸 양보하고 읽는 쪽을 둘로 늘린 것이다.

이제 경로가 바뀌면 paths.confDATA_DIR 한 줄만 고친다. BACKUP_DIRLOG_DIR 도 같은 자리에 뒀다. 다음 이사의 크기가 여섯에서 하나로 줄었다.

문서에 값을 적지 않기

문서에 적힌 경로도 같이 낡는다. 코드처럼 검색해 고치기가 애매하고 고쳐도 다른 사본이 남는다.

그래서 문서에는 값 대신 값이 있는 자리를 적었다.

자료 경로는 `/etc/collect/paths.conf``DATA_DIR` 을 따른다.

경로 자체를 안 적으니 이사를 해도 이 문장은 그대로 맞다. 값을 꼭 보여야 하는 문서는 sed 로 만들 때 채워 넣게 했다.

sed "s|{{DATA_DIR}}|$DATA_DIR|" docs/setup.md.tpl > docs/setup.md

setup.md.tpl 에 자리표시자를 두고 sed 로 현재 값을 넣어 만든다. 경로가 바뀌면 문서를 다시 만들면 된다.

옛 경로에 표시를 남겼다

옮긴 뒤에 옛 자리를 바로 지우지 않았다. 못 고친 곳이 아직 있을 수 있어서다.

대신 그 자리에 안내 파일을 뒀다.

/data/collect/MOVED.txt

이 경로는 2016-10-31 에 /mnt/data2/collect 로 옮겼습니다.
여기를 보고 있다면 설정을 확인하십시오.

누가 옛 경로를 열면 MOVED.txt 가 먼저 눈에 띈다. 빈 폴더만 있는 것보다 다음 행동이 정해진다. 옮긴 날짜와 새 경로가 그 안에 적혀 있어서 설정을 어디로 고칠지도 같이 나온다.

그 자리를 여는 프로세스가 남았는지도 봤다.

$ lsof +D /data/collect 2>/dev/null

lsof 가 이틀 동안 아무것도 안 내놓으면 그때 지웠다. 사람의 기억이 아니라 관측으로 지울 시점을 정한 것이다.

검증 — 옮긴 뒤 확인할 다섯 가지

확인할 것을 목록으로 적어 두고 순서대로 봤다.

1. 새 경로에 파일이 쌓이는가       ls -l 로 최근 시각 확인
2. 옛 경로에 파일이 안 쌓이는가    ls -l 로 최근 시각 확인
3. 통계가 나오는가               어제 자료로 조회
4. 백업이 도는가                 백업 로그 마지막 줄
5. 옛 경로를 여는 것이 있는가     lsof

이 중에 둘째가 핵심이었다. ls -l 로 새 자리에 쌓이는 것을 봤다고 옛 자리에 안 쌓이는 것이 아니다.

양쪽에 나뉘어 쌓이면 자료가 갈라지고 나중에 합치는 일이 생긴다. 그래서 성공 조건을 새 자리의 최근 시각과 옛 자리의 멈춘 시각 둘로 잡았다.

같은 구조가 반복된다

이 모양은 경로에만 있는 것이 아니었다. 서버 주소를 바꿨을 때도 데이터베이스 이름을 바꿨을 때도 계정을 바꿨을 때도 똑같았다.

DB 이름이든 계정이든 바꾼 것보다 그것을 가리키는 쪽이 많다는 구조다. 그래서 무엇을 바꾸든 먼저 옛 값을 세는 것을 습관으로 뒀다.

$ grep -rn "옛 값" . --include=... | wc -l

wc -l 로 나온 이 숫자를 보고 나서 작업 시간을 잡는다. 세어 보기 전에는 한 줄짜리 일로 보였던 것이 스물세 군데짜리 일이었다.

정리


Share this post on:

Previous Post
운영에 손대기 전에 확인하는 것
Next Post
두 팀이 한 DB를 쓸 때