Skip to content
isdnetworks
Go back

스키마 변경은 코드 배포가 아니다

(수정됨)

stake_rewards 테이블을 하나 추가하는 변경을 코드와 함께 배포하려고 Flyway 마이그레이션 파일 V20201228__create_stake_rewards.sql 을 넣었다. Jenkinsfile 을 확인하다 멈췄다.

Table of contents

Open Table of contents

증상 — 한 서비스에만 있던 마이그레이션

배포 스크립트를 전부 찾아보니 flyway migrate 를 실행하는 자리가 한 곳뿐이었다. 배포 대상은 api·wallet·notice·batch 넷인데 그중 wallet 의 배포 후 단계에만 들어 있었다.

그리고 넷이 parallel 블록으로 나간다. 마이그레이션이 도는 wallet 이 먼저 끝난다는 보장이 없다.

원인 — 병렬 배포가 만드는 창

그러면 api 에 새 코드가 나가는데 테이블이 아직 없을 수 있다. 새 코드가 없는 테이블을 조회하고 오류를 낸다.

wallet 안에서도 jar 교체와 flyway migrate 실행 사이에 창이 있다. batch 에서 @Scheduled 가 매분 도는데 그 창에 걸린 작업이 없는 테이블을 참조하고 변경이 클수록 창이 길어진다.

실패하면 버전이 갈린다

배포 후 단계에서 flyway migrate 가 실패하면 wallet 만 롤백되고 나머지 셋은 새 코드를 유지한다. 그러면 서로 다른 버전이 동시에 도는 상태가 된다.

한 단계의 실패가 전체를 되돌리지 못하고 일부만 되돌리는 구조라 수습에 사람이 개입해야 한다. 배포 단위와 스키마 적용 단위가 다르다는 것이 이 문제의 형태였다.

조치 — DDL 을 분리한 뒤

두 가지 방법이 있었다. parallel 을 풀어 wallet 을 먼저 배포하고 나머지를 뒤에 세우는 것과, 스키마 적용을 배포에서 아예 빼고 먼저 적용한 뒤에 코드를 배포하는 순서로 나누는 것이다. 뒤쪽을 골랐다. 이유는 순서를 세워도 jar 교체와 migrate 사이의 창은 그대로 남아서다. 대신 배포가 두 단계로 갈려 사람이 한 번 더 손대야 하는 것을 감수했다.

적용은 Jenkins 가 아니라 별도 절차로 사람이 확인하며 하고 시간이 걸리는 변경은 트래픽이 적은 시간에 했다. 되돌릴 수 있게 mysqldump 로 적용 전 상태를 먼저 확보하는 것도 절차에 넣었다.

부재 시 처리와 파일명 순서

선행 적용이라도 롤백하면 코드는 옛것으로 돌아가고 테이블은 남는 구간이 생긴다. 그래서 새 코드에 테이블이 없을 때 조용히 넘어가지 않고 WARN 을 남기며 건너뛰는 처리를 넣었다.

이것은 임시 코드이므로 언제 뺄지를 주석에 적어 뒀다. Flyway 6.5 소스의 MigrationVersion 이 Comparable 로 버전을 비교하므로 파일 이름의 버전이 순서를 정하고, 생성이 변경보다 앞서는지 확인했다. @Scheduled 가 어느 서버에서 도는지는 확인하지 못해 미확인으로 적었다.

정리


Share this post on:

Previous Post
구조만 보고 한 분류의 오류
Next Post
확정과 제안의 표시 구분