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 가 어느 서버에서 도는지는 확인하지 못해 미확인으로 적었다.
정리
- 배포 대상이 여럿이면
flyway migrate가 일부에서만 돈다 parallel배포에서는 순서가 안 정해진다jar교체와 마이그레이션 사이에 창이 있다- 변경이 클수록 그 창이 길어진다
- 배포 후 단계에서 실패하면 일부만 롤백돼 버전이 갈린다
- 스키마 적용을 배포에서 분리해 먼저 한다
- 코드에 부재 시
WARN과 함께 건너뛰는 처리를 두고 뺄 시점을 적는다 - 확인 못 한 것은 미확인으로 적는다