Data Migration 작업(with tip)

마이그레이션 작업이란?

  • A 저장소에서 B 저장소로 데이터를 이관하여 좀 더 확장성 있게 구조를 개선하거나, 신규 기능을 위해 작업이 필요할 경우도 있다.
    • 반정규화 되어있는 테이블을 정규화한다던가…?

마이그레이션시에 필요한 작업 목록

Dual Write : 신규 테이블로의 데이터를 쓰기로직 추가.

  • 기존에 데이터를 쓰거나 업데이트 하는 영역에 대해서 동일하게 신규 테이블(or 저장소)로 쓰기 처리가 이뤄질 수 있도록 기능을 추가한다.
  • 마이그레이션 전 해당 로직은 배포가 나가있는게 좋다.
  • 만약 변경점이 많을 경우, 로직 추가한 곳을 전부 목록화 해서 하나씩 검증하는 것이 좋다.
    • 변경에 대한 이벤트 누락이 발생하면 빠르게 목록을 확인하여 대응 할 수 있다. 마이그레이션할 때 검증하기 좋다.
  • 로직을 추가할 때, 신규 테이블로 추가하는 로직에는 아래와 같이 추가하는 것이 좋다.
    • 영향도를 최소화 한다.
asisRepository.save(entity); //이전 로직

try {
  tobeRepository.save(entity); //신규 테이블
} catch(Exception e){
  log.error(e);
}

Migration : AS-IS 데이터를 TO-BE 테이블로 이관!

  • AS-IS 에 대한 모델을 TO-BE 모델로 변경하여 안전하게 이관하는 작업!

개발시 고려하면 좋을 부분.

실행장치

  • CLI 나 API 를 호출하여 마이그레이션 시작을 하도록 개발을 진행한다면 아래와 같은 사항들을 주의하면 좋다.
    • GET 보다는 POST 를 호출하는 것이 좋다.
      • GET 으로 할 경우 브라우저나 링크를 공유할 때 잘못하여 타인이 실행시킬 수 있음.
      • Header 에 특정 문자열을 넣어서 그 문자열일 경우에만 실행되도록 만드는 것도 안전 장치다.
POST http://localhost:8080/migration
Check : HELLO-WORLD
  • 싱글 인스턴스로 마이그레이션 하는 경우, 중복 실행을 방어하기 위해 전역변수 를 세팅하여 방어하는 것이 좋다.
    • 병렬처리를 위해 멀티 인스턴스를 이용하게 되면 redis 를 이용하여 방어처리를 간단하게 처리할 수 있다.
  • 파라미터 추가 작업
    • 재배포 없이 이것저것 대응할 수 있게 장치를 마련해 놓는게 좋다.
    • 파라미터를 받아서 병렬처리나 처리 속도를 컨트롤 할 수 있도록 함.
    • 실패할 경우 등을 대비하여 특정 페이징 키들을 넣어서 재시작 할 수 있도록 해야한다.
  • 마이그레이션 외 부가적인 기능
    • 강제 정지 기능!
      • 만약 강한 부하가 들어가거나 문제가 발생했을 때 멈출 수 있는 기능이 필요하다.
    • 진행상황 모니터링
      • 로그로 진행사항 들을 남겨놓고 보면 좋지만, 간혹 큰 단위의 작업이 진행되면 로그가 안남고 계속 동작 중일 때, 잘 돌고있는지 알고 싶을 때가 있다.
      • 단순하게 상태값을 전역변수로 놓고, 호출해서 확인해볼 수 있다.
    • 로그!
      • 위에서 이야기한 진행상황을 보여주는 API 같은 것도 좋지만, 로그를 잘 남겨서 상황을 잘 볼 수 있어야한다.

현재 진행상황에 대한 정보, 데이터 읽은 수, 데이터 쓴 수 등 모니터링에 필요한 정보들을 남겨 놓는다. (단, 모든 정보를 남기면 로그가 많아서 문제가 될 수 있다. 10,000개면 100개 단위로 남기도록 하는 로직을 넣는 것도 중요하다)

처리 단위

  • 어느정도 읽어서 어느정도 것인지 중요하다.
    • 데이터를 읽어서 추가적인 메타 데이터를 많이 읽어서 작업을 해야한다면, 메모리가 부족할 수 있다. 보수적으로 설정하여 개발할 필요가 있다.
    • 데이터를 쓰는 작업도, DB 마다 다르겠지만 묶어서 처리하는 것이 좋다.
      • 단 묶음처리에 사이즈도 꼭 지정해야한다. 패킷이 넘쳐서 짤리면 재배포해야한다….
insert into (name, value, create_date) values ('철수', '안녕하세요', now()), ('영희', '반갑습니다', now());

분산처리

  • 싱글 인스턴스로 해서 싱글 쓰레드로 처리할 수도 있겠지만 대용량 처리를 해야할 경우에는 분산처리하여 처리시간을 단축할 수 있다.
  • 분산단위는 읽는것, 쓰는것도 고려해야겠지만, 멀티 프로세스로 할 것이냐, 멀티 쓰레드로 할 것이냐? 등을 고민해보면 좋다.

마이그레이션 작업시에 주의해야할 사항.

  • 처리 속도
    • 한번에 너무 많은 데이터를 처리하게 되면 저장소 장비에 큰 부하가 들어갈 것이고, 그렇게 되면 서비스에 영향을 줄 수 있다.
    • 실행기에 속도를 컨트롤 할 수 있는 장치를 추가하여 모니터링하며 속도 조절하는 것이 중요하다.

Validation : 검증작업

  • 데이터가 의도한 형태로 잘 들어갔는지 확인하는 작업
  • AS-IS 에서 읽어서 TO-BE 데이터와 비교하여 정합성 체크!

있으면 좋은 기능

  • 단순 검증하여 로그만 남기는 것보다, 자동 보정장치나 잘못된 정보들에 대해서 어딘가에 저장해 놓고 확인 할 수 있도록 한다.
  • 만약, 꽤 많은 데이터가 불일치로 검출 될 경우에는 Dual Write 등에서 이벤트가 누락되어 있을 경우가 있다.
    • 이런 경우 핫픽스 후에 정도에 따라 재 마이그레이션 여부를 결정해야겠지만, 불일치건들만 보정해가며 점검하는 것도 작업 시간 단축에 효율적이다.

Read : 조회 영역 변경(With 쓰기 영역 변경)

  • 검증이 완료되면, 읽는 데이터를 AS-IS 에서 TO-BE 로 저장소 호출 영역을 변경한다.
  • 추가로 쓰기 영역도 dual write 를 제거하고 try catch 를 제거하여 일반 로직화(?)를 한다.

Remove : 기존 로직들 제거

  • 기존에 로직들을 제거하고, AS-IS 데이터 제거

추가 팁.

마이그레이션 예상 시간 산출하기

  • 개발계에서 n 개 row 에 대해서 어느정도 시간이 소요되었는지 계산하게 되면, 운영계의 장비 등 스팩을 고려하여 n 배하여 예상 시간을 계산할 수 있다.
    • 단, 이렇게 뽑은 정보는 단순 예상치로 사용하고 꼭 +@ 를 해야한다.

일정산정

  • Dual Write 로직이 배포될 때 마이그레이션 로직(+Validation)도 같이 배포되면 좋다. Dual Write 안정성 확보되면 바로 Migration 동작할 수 있으니 시간 단축이 된다.
  • 위와 같은 단계에 대해서 어느정도 시간이 계산되고 일정을 산정해야할 경우 +@ 를 더해서 버퍼를 꼭 가지고 있어야한다.
  • 급하게 처리하게 되면, 분명 누락이 발생하고 문제가 생긴다.
    • 이벤트 누락 등이 발생하더라도 버퍼 기간으로 커버 할 수 있따.

정합성 체크

  • 1:1 로 이관하는 작업의 경우에는 크게 고민하지 않지만, 1:N, N:1, N:M 등 트랜잭션 처리가 필요한 경우가 있다.
  • 개인적인 생각이지만, 이럴 경우 1 : 1 로 해서 매번 트랜잭션처리하여 마이그레이션 하는 것보다, 같은 정보들 끼리 묶어서 Batch 처리 할 수 있도록 하고, 검증 단계에서 틀어진 데이터를 찾아내고 보정해가면서 진행하는게 마이그레이션 시간 및 부하를 줄일 수 있다.
  • 만약 여러번 검증을 돌렸을 때, 틀어지는 데이터가 줄어들지 않고, 늘어나기만 하는 상황이면 마이그레이션 로직이나 Dual Write 로직을 점검하여 채워나가는 형태가 좋다.

PK 가 변경되는 이슈…

  • 기존 테이블과 PK 가 다르게 될 경우, AS-IS 와 TO-BE 에 대한 Mapping Table 을 추가하여 Old 로직으로 들어올 경우 맵핑 정보를 조회하여 신규 로직을 거쳐서 나갈 수 있도록 개발한다.
  • 이후 Old 로직 제거시에 mapping 정보도 같이 제거하게되면, 수월하게 넘어갈 수 있다.

후기

  • 이전 마이그레이션 경험을 기반으로 작성해봤다.
    • 다른 사람들이 작업할 때 해당 경험이 도움이 되었으면 좋겠다.

Related Posts