본문 바로가기
프로그래밍/기타

[flyway] flyway를 통해 DDL 형상관리를 하자 - Spring Boot (Java API) 편

by 사바라다 2021. 9. 17.

안녕하세요. 오늘은 flyway를 이용하여 로컬 환경에서 DDL의 형상관리를 하는 방법을 알아보도록 하겠습니다.

flyway

flyway는 데이터베이스의 형상관리를 목적으로 하는 툴입니다. 데이터베이스의 형상 관리란 어떤 것일까요? git을 통하여 우리가 코드를 관리하는 것의 데이터베이스 버전으로 볼 수 있습니다. git에서는 코드를 파일별로 로깅을 통해서 변화의 이력을 추적합니다. flyway는 데이터베이스의 DDL의 이력을 쌓아서 DDL이 어떻게 변화되었는지 관리하는 툴로 사용할 수 있습니다.

위 이미지는 flyway 공식 홈페이지에 나와있는 이미지로 DDL 형상관리의 이해를 위해서 가져왔습니다. 위 이미지를 보시면 Axel과 Christian이 별개로 DDL을 만들고 있습니다. 그리고 서버로 배포할 때 자동화 빌드 과정에서 함께 통합하여 DDL을 실행되는 것입니다. flyway를 잘 사용하면 이렇게 DDL을 관리할 수 있게 됩니다.

flyway는 다양한 방법으로 실행할 수 있습니다. 공식 사이트에 따르면 gradle, maven, CLI, 그리고 JAVA API입니다. 오늘은 Spring Boot로 서버를 띄울때 자동으로 DDL이 실행될 수 있도록 해보겠습니다. 이방법은 JAVA API를 사용하는 것입니다.

의존성 및 환경 설정

flyway의 JAVA API를 사용하기 위해서는 org.flywaydb:flyway-core 모듈에 대한 의존성이 필요합니다. 해당 모듈은 현재 8버전 beta까지 나와있습니다. 하지만 만약 Spring Boot 2.3.x 버전을 사용하고 계신다면 flyway 6 버전, Spring Boot 2.4.x 이상은 이시라면 7버전 이상을 사용해주시면 됩니다. 제가 사용하는 프로젝트는 2.3.12.RELEASE를 사용하고 있었기 때문에 flyway는 6버전의 가장 최신인 6.5.7 버전을 사용하였습니다.

implementation("org.flywaydb:flyway-core:6.5.7")

yaml 파일 설정

Spring Boot에서는 고맙게도 flyway에 대해서 autoconfigure를 지원하고 있습니다. Properties 또는 yml을 이용할 수도 있는데요. 이때는 prefix를 spring.flyway를 이용하시면 됩니다. 다양한 설정할 수 있는 방법이 있습니다. 이러한 부분은 FlywayProperties 클래스를 참고하시면 확인하실 수 있습니다.

spring:
  datasource:
    hikari:
      jdbc-url: jdbc:mariadb://localhost:3306/pika
      username: pika_app
      password: pika_password

  flyway:
    locations: classpath:/db/migration # migration 파일들이 위치하는 directory
    sql-migration-suffixes: ddl        # 파일 확장자
    baseline-on-migrate: true          # flyway_schema_history 테이블을 자동으로 생성할지 여부 
    baseline-version: 0                # 최초 버전 정보

마이그레이션 파일

flyway에서는 데이터베이스에 일어나는 모든 행위를 마이그레이션(migration) 이라고 표현하고 있습니다. 이러한 마이그레이션은 파일로 관리되어 집니다. 파일의 이름은 지정하는 형식이 있으며 이를 따라야합니다.

위 이미지는 공식 사이트에서 가져온 파일 이름을 설정하는 방법입니다. 파일 이름에는 아래와 같은 요소가 포함되게됩니다.

  • Prefix - V, U, R 중 하나를 입력하게 됩니다. V는 Verion, U는 undo, R은 Repeatable 입니다. 오늘은 V 만 사용하도록 하겠습니다.
  • Version - 버전 정보입니다. 정수, 소수, 날짜 등이 가능합니다.
  • Seperator - __ ( underscore 2개를 이용합니다. )
  • Description - 추가되는 설명입니다. _ (underscore)가 space를 대신합니다.

위 규칙으로 파일을 만들면 아래와 같이 만들 수 있습니다.

V0_create_table_user.sql

V1.1_create_table_game.sql

V20210909_create_table_screenshot.sql

프로젝트에서는 아래와 같이 파일을 위치시켰습니다. 각파일에는 table을 생성하는 DDL이 하나씩 들어있습니다.

이렇게까지하면 일단 기본적으로 spring boot를 띄우면서 flyway를 실행하기 위한 기본적인 설정은 마무리가 되었습니다. 그렇다면 Spring Boot를 실행해보도록 하겠습니다.

정상일 경우

Spring Boot 배너가 뜨면서 로그가 올라올 것입니다. 그리고 아래와 같은 DbMigrate에서의 로깅을 확인할 수 있습니다. 우리가 만들어둔 V0, V1, V2에 대한 DDL이 실행되고 있는 모습을 확인할 수 있었습니다.

2021-09-15 23:32:56.083  INFO 70245 --- [  restartedMain] o.f.core.internal.command.DbMigrate      : Current version of schema `pika`: 0
2021-09-15 23:32:56.098  INFO 70245 --- [  restartedMain] o.f.core.internal.command.DbMigrate      : Migrating schema `pika` to version 1 - create table game.
2021-09-15 23:32:56.136  INFO 70245 --- [  restartedMain] o.f.core.internal.command.DbMigrate      : Migrating schema `pika` to version 2 - create table screenshot.
2021-09-15 23:32:56.164  INFO 70245 --- [  restartedMain] o.f.core.internal.command.DbMigrate      : Successfully applied 2 migrations to schema `pika` (execution time 00:00.088s)

DB에 정상적으로 반영되었는지 확인해보도록 하겠습니다. DB 확인은 Adminer를 이용하였습니다. 정상적으로 원하는 table 이었던 game, screenshot, user 테이블들이 만들어진 것을 확인할 수 있었습니다.

flyway_schema_history 테이블

flyway_scheme_history 테이블은 제가 직접 만든 테이블이 아닙니다. 해당 테이블은 flyway에서 형상관리를 위하여 자동으로 만드는 테이블입니다. 이 테이블에는 어떤 데이터들이 저장되는지 한번 확인해보도록 하겠습니다. 테이블에 저장된 데이터는 아래와 같습니다.

여기서 눈여겨 봐야할 정보는 version, checksum, 그리고 success 정도가 될것 같습니다.

  • version은 파일의 V 뒤에 붙어있던 숫자로 낮은 순서부터 실행되며 실행 순서대로 테이블에 쌓이는 구조를 가집니다.
  • checksum은 파일의 내용을 hashing한 것입니다. 만약 파일의 내용이 달라지면 이 체크섬이 달라지게 됩니다. 한번 체크섬을 만들어 둔 후 파일을 수정한다면 그렇게 되면 누군가에 의해서 형상관리에 문제가 생겼다고 판단하기 때문에 flyway는 에러처리를 하게됩니다. 이럴 경우 해당 파일에 대한 체크섬을 repair한 후 success를 0으로 돌리는 등의 작업이 필요합니다.
  • success는 파일 실행에 성공했는지 여부를 나타내는 값입니다. 이 값에 따라서 flyway에서 해당 파일의 내용을 실행할지 말지 정합니다.

발생할 수 있는 에러

Spring Boot가 실행되며 가장 먼저 flyway가 실행되게 됩니다. 이때 발생할 수 있는 에러에 대해서 알아보도록 하겠습니다.

가장 많이 확인하실 수 있는 에러는 한번 flyway로 서비스를 모두 올린 후 일부 파일을 수정하여 checksum이 틀어지게 되어 발생하는 에러입니다. 이때 에러는 아래 처럼 발생하게 됩니다. 이 경우에는 해결하는 방법으로 2가지 방법이 있습니다. 첫번째는 해당 row를 포함한 이후 row를 삭제하고 다시 올리는 방법입니다. 두번째는 checksum을 강제로 수정하고 (repair 또는 수동으로 수정) success를 1로 돌리는 방법입니다. 1번의 방법이 편하기는 하지만 정밀한 조정이 필요하다면 2번 방법을 추천드립니다.

Caused by: org.flywaydb.core.api.FlywayException: Validate failed: 
Migration checksum mismatch for migration version 1
-> Applied to database : 1727247623
-> Resolved locally    : -1198089893

아래는 누군가가 파일을 삭제하던지 또는 table에서 row를 delete 했을 때 나타나는 에러 로그입니다. 이때는 누군가 의도를 가지고 처리한 것이므로 새롭게 처음부터 실행하는것을 추천드립니다.

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.FlywayException: Validate failed: 
Detected applied migration not resolved locally: 1

repair

repair는 checksum이 틀어지는 등의 문제가 생겼을 때 자동으로 checksum을 맞춰주는 방법입니다. flyway 6에서는 bean을 아래처럼 등록하시면 migrate 하기전 repair를 먼저하여 checksum을 재설정하는 작업을 진행하여 형상이 깨지는것을 막아줍니다.

@Bean
public FlywayMigrationStrategy cleanMigrateStrategy() {
    return flyway -> {
        flyway.repair();
        flyway.migrate();
    };
}

알아두면 좋은 점

하나의 파일에 2개의 DDL은 좋지 않습니다. flyway는 checksum을 파일 단위로 관리하며 파일에 문제가 생겼을 때 이 이후의 로직을 실행하지 않기 때문입니다. 따라서 DDL은 파일 하나씩 두는것을 추천합니다.

마무리

JAVA API 방법은 여러대의 서버가 돌아가는 클라우드 서버 환경보다는 로컬에서 1대만 띄우는 환경에 적합합니다. flyway는 여러가지 Java API 방법 뿐만 아니라 gradle, maven, CLI와 같은 방법을 제공하는데 환경에 맞춰서 적절하게 사용하는 것을 추천드립니다.

오늘은 여기까지 알아보도록 하겠습니다.

감사합니다.

참조

flywaydb_why

stackoverflow_failed-to-ugrade-a-spring-boot-app-to-flyway-7-0-0

stackoverflow_caused-by-org-flywaydb-core-api-flywayexception-validate-failed-migration-che

댓글