데이터 베이스 앱의 업데이트 전략

Down-time

시스템 업데이트를 위해, 시스템을 잠시 종료시켰다가 재개하는 데 걸리는 시간을 가리킵니다.

시스템 종료 => 업데이트 => 시스템 재개

현대적인 배포 방식은 이 다운 타임을 0에 수렴하게 만드는 것인데, 이를 Zero Down-time 이라고 합니다.

0이 아닌, Zero에 수렴하게 만드는 것이라는 정의는, 어떻게 하더라도 0로 만들 수 없기 때문입니다.

예를 들어, 웹앱의 경우,

MVC : 페이지를 다운받고, submit 버튼을 누르기 전에 시스템이 업데이트 됨.
블레이저 : 강력한 새로 고침(캐시 제거) 전에 시스템이 업데이트 됨.

이는 다운 타임을 갖지 않는 이상, 구버전 앱과 신버전 앱이 공존하는 시간이, 매우 짧은 찰라라도 반드시 존재한다는 의미입니다.

구버전과 신버전의 공존

만약 앱이 DB와 연동된 경우라면, 이 공존의 시간은 문제상황으로 나타나기 쉽습니다.

앱의 버전은 깃을 통해, DB의 버전은 마이그레이션을 통해 관리되고 있다는 가정을 하면, 앱과 DB는 아래의 쌍을 이루도록 개발될 것입니다.

(G : git, M: migration)

버전 DB
old G1 M1
new G2 M2

아래는, 공존할 수 있는 앱과 DB의 조합과, 그 조합의 문제 상황을 보여줍니다.

DB
G1 M1 문제 없음
G2 M1 문제1
G1 M2 문제2
G2 M2 문제 없음

공존 문제의 해결

위 문제의 상황들을 회피하는 방법은 아래 두 가지를 염두해 두는 것입니다. .

신/구버전 앱 모두와 호환될 수 있도록 DB를 변경
앱과 DB 의 업데이트 순서

상황 별, 구체적으로 알아 본다면,

테이블 삭제

M1 에 있던 테이블이 M2에서는 사라진 경우 - G1에서 사용하던 테이블을 G2에서는 사용하지 않는 경우입니다.

G2 는 M1-Table2의 존재를 모르기 때문에, M1 과도 호환이 됩니다.
테이블이 존재하지만, 앱이 사용하지는 않는 것이죠.

그러나, G1은 동 테이블이 없으면, 에러를 일으킵니다.
따라서, M2는 반드시 G1 이 사용되지 않을 때만 적용할 수 있습니다.

그래서, 앱을 먼저 업데이트시키고, 공존 시간이 없을 것으로 판단, 다시 말하면, G1이 더 이상 사용되지 않는다는 판단이 들면 DB를 M2로 업데이트시킵니다.

즉, 업데이트 순서는 앱 먼저, DB 나중입니다.

G2 → M2

M2를 적용할 때, Transction으로 처리하면, G2 의 쿼리와 DB 업데이트 쿼리는 충돌하지 않기 때문에 G2는 다운타임이 없어도 됩니다. (앱의 실행을 중지시킬 필요가 없습니다)

필드 삭제

M1 에 있던 테이블은 그대로인데, 특정 필드만 M2에서는 사라진 경우입니다.

G2는 M1을 사용할 수도 있고 못할 수도 있습니다.
M1의 필드가 not null 로 설정되어 있지만, 기본 값은 지정지 않은 경우가 못하는 상황입니다.

이 경우, G2가 M1-Table1 에 Insert 를 하면, G2가 채워넣지 않은 Not Null 필드때문에, DB 에러가 납니다.

G1은 M2를 사용할 수 없습니다.

이 경우, 삭제될 필드의 기본 값을 설정하는 PM2(Pre-migration2, M2 적용 전에 적용할 마이그레이션)가 도입해야 합니다.

PM2는 G1과도 호환되고, G2와도 호환되기 때문입니다.
따라서, 업데이트 순서는

PM2 → G2 → M2

G1의 사용이 더 이상 없다고 판단될 때, 즉, G2만 사용된다고 판단될 때, M2를 적용합니다.

PM2를 Transction으로 처리하면, G1은 다운타임이 없어도 됩니다.
M2를 Transction으로 처리하면, G2는 다운타임이 없어도 됩니다.

테이블 추가

추가된 테이블은 G1에 문제를 일으키지 않습니다. 그 테이블의 존재를 모르니까요.
G2는 그 테이블이 없으면 안됩니다. 다시 말하면, M1과는 공존할 수 없습니다.

따라서 업데이트 순서는

M2 → G2

입니다.

G1만 있을 때, M2를 적용하는데, M2를 Transction으로 처리하면, G1은 다운타임이 없어도 됩니다.

필드 추가

M1의 테이블에 필드만 추가된 경우입니다.

G2는 M1과 공존할 수 없고, G1은 M2와 공존할 수도, 없을 수도 있는데, M2의 추가된 필드가 Not Null인데, 기본값을 지정하지 않으면, 공존할 수 없습니다. (Insert 시 에러)

그래서, M2에는 반드시 G1과의 호환성을 위해, Not Null 필드에 기본값을 지정하는 것을 잊지 말아야 합니다.
이것만 잊지 않는다면, 업데이트 순서는

M2 → G2

입니다.

M2를 Transction으로 처리하면, G1은 다운타임이 없어도 됩니다.

필드 변경

필드의 속성, 대표적으로 자료형이 변경된 경우입니다.
그런데, 사실 나타날 확률은 매우 적다 할 수 있습니다.

이는 필드를 추가하는 마이그레이션, 필드를 삭제하는 마이그레이션으로 나눠서 처리하면 G1/2 와의 호환성을 유지할 수 있습니다.

마이그레이션 파편화

실무에서는 마이그레이션에 너무 많은 변경이 포함되기도 하는데, 이는 반드시 다운 타임을 갖게 만드는 요인이 됩니다.

이 것이 가급적 마이그레이션은 매우 작은 단위로 유지해야 하는 이유입니다.

현실적으로 힘들다면, 적어도 업데이트 순서가 같은 것들을 모아서 하나의 마이그레이션로 설정해야 합니다. .

순서 별로 구분해 보자면,

업데이트 순서 마이그레이션 내용
M → G 테이블 추가, 필드 추가, 필드 삭제(PM2)
G → M 테이블 삭제, 필드 삭제 (M2)
2 Likes

뭔가… 뭔가… 느낌이 확 안옵니다!!

그림이 있으면 좋겠습니다!!

3 Likes

헉헉… 됐나요?

다시 보니, 그림이 잘 못 됬네요 ^^. 필드를 날려야 하는데, 레코드를 날렸네요.

2 Likes