Skip to content
isdnetworks
Go back

다시 만들면 멀쩡하던 것도 달라진다

(수정됨)

인수인계 문서에 넣을 일별 거래대금과 수수료 표를 전 기간 다시 만들어야 했다. 작업 전에 백업을 떠 뒀다. 끝난 뒤 백업과 비교해 의도한 것만 바뀌었는지 보려 했는데 거의 전부 달랐다.

Table of contents

Open Table of contents

배경 — 일별 통계 표를 전 기간 다시 만들었다

관리 화면의 daily_stats 표는 날짜마다 한 행이다. 거래대금 volume_krw 와 수수료 fee_krw 와 입출금 합계가 든다. 지난봄에 수수료를 maker 와 taker 로 나누면서 집계 식이 바뀌었다. 그런데 옛 날짜의 행은 옛 식으로 남아 있었다.

인계 문서에 두 식이 섞인 표를 넣을 수는 없었다. 그래서 StatsRebuildJob 을 전 기간으로 돌리기로 했다. 표 하나를 통째로 바꾸는 일이라 먼저 되돌릴 수단을 챙겼다.

해 본 것 — 백업과 바이트 비교

작업 전에 mysqldump 로 daily_stats 만 덤프했다. gzip 으로 묶어 오브젝트 스토리지 버킷에 올렸다. 재생성이 끝난 뒤 같은 방식으로 덤프를 하나 더 떴다. 두 파일을 풀어 diff 로 비교했다.

기대한 그림은 옛 식으로 남아 있던 구간만 달라지고 나머지는 같은 것이었다. 그러면 달라진 줄만 읽어 재생성이 의도한 범위에 머물렀는지 판정할 수 있다.

막힌 지점 — 거의 전부 달랐다

diff 는 몇천 줄을 쏟아냈고 달라진 날짜가 표의 거의 전부였다. 옛 식과 무관한 지난달 행까지 바뀌어 있어서 이 출력으로는 아무것도 판정할 수 없었다.

처음에는 재생성 작업이 잘못됐다고 봤다. 그런데 바뀐 행을 몇 개 열어 보니 값 차이가 아주 작았고 updated_at 만 다른 행도 많았다.

원인과 조치 — 구조 축과 변동폭 축

이유는 재생성이 그 시점의 trades 와 deposits 와 withdrawals 를 다시 읽는다는 점이었다. 백업과 재생성 사이에 늦게 확정된 입금과 취소된 출금이 들어왔다. 전 행의 updated_at 도 새로 찍혔다.

그러면 원래 정상이던 날짜도 정당하게 달라진다. 바이트 비교는 같은지 다른지만 말하고 왜 다른지는 말하지 않는다. 그래서 정당한 변동까지 전부 변경으로 잡는다.

그래서 비교를 두 축으로 나눴다. 구조 축은 행 수가 날짜 수와 같은지를 본다. 새 컬럼 fee_maker_krw 가 전 행에 채워졌는지도 여기서 본다. 변동폭 축은 월별 volume_krw 합계가 백업 대비 몇 퍼센트 달라졌는지를 본다.

기준선은 정산이 끝나 settled_at 이 찍힌 달이다. 그 구간은 원장이 안 움직이므로 다시 만들어도 같은 값이 나와야 하고 실제로 0% 였다. 최근 두 달만 소폭 줄어 있었고 그것은 취소된 출금이 빠진 만큼이었다.

정산이 끝난 달이 움직였으면 집계가 아니라 원장 쪽 신호다. 그 기준선이 없으면 뭔가 바뀐 것 같다에서 못 나간다. 대신 월별 합계만 보기로 하면서 개별 행의 오류를 이 비교로는 못 잡는 것을 감수했다.

되돌릴 조건 — 헤더와 표본까지 본 백업

관리 화면이 읽는 일별 통계 JSON 은 같은 버킷에 압축된 채로 있다. Content-Encoding: gzip 헤더를 보고 브라우저가 풀어서 본다. 이 객체들도 재생성 전에 복사해 뒀다. 그런데 복사 뒤 HEAD 로 다시 조회하니 그 헤더가 빠져 있었다.

이 헤더는 본문에 적용된 부호화를 가리킨다. 받는 쪽이 그것을 풀어야 Content-Type 의 자료가 된다는 것은 RFC 7231 의 3.1.2.2 절이 정한다. 헤더가 빠진 채 복원하면 압축된 본문을 그대로 내려보내 화면이 깨진다.

버킷의 버전 관리가 꺼져 있어 이 복사본이 유일한 되돌리기 수단이었다. 그래서 헤더를 다시 붙이고 개수와 크기 합계를 맞춘 다음 표본 몇 개를 실제로 열어 봤다.

정리


Share this post on:

Previous Post
상한치는 수요가 아니다
Next Post
처리 단계의 모듈 구성