공식팀에서 Flyway를 도입하게 된 이유와 Flyway의 작동방식, Flyway를 사용하며 겪은 트러블 슈팅을 공유합니다!
flyway는 데이터베이스의 DDL의 이력을 쌓아서 DDL이 어떻게 변화되었는지 관리하는 툴입니다.
이를 통해서 데이터베이스의 형상관리 및 마이그레이션을 할 수 있습니다.
그래서 이를 해결하기 위해 Flyway를 도입하여 언제 어디서든 배포를 할 수 있도록 했습니다.
공식팀은 개발용 서버와 운영용 서버가 따로 있고, 각 서버마다 db가 있습니다.
데이터베이스 스크립트가 수정된다면, 서버마다 입력을 해야했습니다.
Flyway를 사용하면 이런 문제를 코드로 해결할 수 있습니다.
Flyway를 쓰지 않고, 스크립트를 따로 문서화해도 되지만 코드상에서가 아니라면 문서화까지 신경써야하므로 변경에 리소스가 더 들어가게 됩니다.
그냥 파일에 적어도 되겠지만, Flyway를 사용하면 더 빠르게 스크립트에 문제가 생겼는지 알 수 있습니다.
Flyway의 작동방식을 살펴봅시다.
Flyway를 적용하고 어플리케이션을 실행하면, Flyway는 DB에서 flyway_schema_history
테이블을 찾습니다.
flyway_schema_history
는 아래와 같은 형태로 저장됩니다.
중요한 컬럼에 대해서만 살펴볼게요.
script는 저희가 migration을 위해 만든 파일의 이름을 의미합니다.
version은 저희가 만든 파일의 prefix(V) 뒤에 붙은 숫자로 버전 순서대로 테이블에 row가 쌓입니다.
checksum은 파일의 내용을 hashing한 것입니다.
success는 파일 실행에 성공했는지 여부를 나타내는 값입니다. 이 값을 보고 해당 버전의 ddl이 실행됐는지 알 수 있어요.
flyway_schema_history는 DDL의 이력을 찾기 위해서 사용됩니다.
flyway_schema_history가 없다면 flyway_schema_history테이블을 만들고 설정한 위치에 있는 스카마 파일을 찾아 DDL을 입력합니다.
flyway_schema_history가 있다면 application.yml에 설정한 혹은 기본 경로인 migration 파일이 위치하는 directory에 새로운 파일이 있는지 확인하고 있다면 해당 파일을 읽어 sql을 실행한 후 flyway_schema_history에 추가합니다.
지금까지 말한 내용으로 보면 무조건 Flyway를 도입하는 것이 좋아보이지만, Flyway가 마법은 아닙니다.
항상 기술의 선택은 트레이드 오프인 법...
처음 설정부터 운영까지 불편한 점이 없진 않았는데요.
먼저 파일명에 대한 제약이 있어요.
참고참고 Naming
또한 여러 사람과 같이 개발하며 버전 충돌 이슈도 있었습니다.
그리고 오늘 있었던 Flyway를 사용하며 겪은 트러블을 공유합니다.
어제 CD 도중 아래와 같은 에러가 발생했습니다.
[2022-10-07 15:49:51:5728] [main] ERROR [org.springframework.boot.SpringApplication.reportFailure:824] - Application run failed
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.exception.FlywayValidateException: Validate failed: Migrations have failed validation
Migration checksum mismatch for migration version 3
-> Applied to database : -2066146599
-> Resolved locally : 748858877. Either revert the changes to the migration, or run repair to update the schema history.
Migration checksum mismatch for migration version 4
-> Applied to database : -1344707923
-> Resolved locally : -1113837987. Either revert the changes to the migration, or run repair to update the schema history.
Need more flexibility with validation rules? Learn more: https://rd.gt/3AbJUZE
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1154)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:908)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)
at com.woowacourse.gongseek.GongseekApplication.main(GongseekApplication.java:10)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65)
Caused by: org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
Migration checksum mismatch for migration version 3
-> Applied to database : -2066146599
-> Resolved locally : 748858877. Either revert the changes to the migration, or run repair to update the schema history.
Migration checksum mismatch for migration version 4
-> Applied to database : -1344707923
-> Resolved locally : -1113837987. Either revert the changes to the migration, or run repair to update the schema history.
Need more flexibility with validation rules? Learn more: https://rd.gt/3AbJUZE
at org.flywaydb.core.Flyway$1.execute(Flyway.java:131)
at org.flywaydb.core.Flyway$1.execute(Flyway.java:124)
at org.flywaydb.core.FlywayExecutor.execute(FlywayExecutor.java:214)
at org.flywaydb.core.Flyway.migrate(Flyway.java:124)
at org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer.afterPropertiesSet(FlywayMigrationInitializer.java:66)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
... 26 common frames omitted
checksum은 위에 설명과 같이 파일의 내용을 hashing한 것입니다.
그런데, 확인해도 file changed가 없었습니다.
그래서 일단 로그 설명에 따라 flyway_schema_history테이블에서 checksum을 Resolved locally에 있는 값으로 수정해주었습니다.