운영·배포

[운영 장애] JPA ddl-auto validate에서 엔티티 변경 시 DB 스키마 동기화 누락

leevigong 2026. 1. 24. 11:08
반응형

문제 상황

서비스 오픈 초창기, 혼자 백엔드를 맡아 개발하던 중이었다. 실제 서비스 운영 경험이 처음이라 매일 긴장하며 작업하던 나날 중 운영 서버에 배포 직후 서버가 다운되었다는 알림을 받았다.

 

에러 로그

[main] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; 
nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; 
nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing column [has_event_invitation_reward] in table [member]

 

에러 메시지 분석:

  • member 테이블에 has_event_invitation_reward 컬럼이 없음
  • Hibernate 스키마 검증(validation) 단계에서 실패
  • EntityManagerFactory 생성 실패로 애플리케이션 기동 불가

 

원인 분석

발생 경위

  1. 초대 이벤트 기능 구현을 위해 Member 엔티티에 hasEventInvitationReward 필드 추가
  2. 로컬 환경에서 테스트 후 dev 브랜치에 머지
  3. main 브랜치로 머지 후 운영 배포
  4. 운영 DB에 컬럼 추가 작업을 하지 않은 채 배포하여 애플리케이션 기동 실패

근본 원인

엔티티 변경 시 운영 DB 스키마 동기화 누락

# 로컬 환경
spring:
  jpa:
    hibernate:
      ddl-auto: update

# 운영 환경  
spring:
  jpa:
    hibernate:
      ddl-auto: validate

 

  • 로컬 환경: update 모드로 인해 엔티티 변경 시 자동으로 컬럼이 추가되어 문제를 인지하지 못했다
  • 운영 환경: validate 모드로 정상적인 설정으로 수동으로 DB 스키마를 변경했어야 했다

 

해결 방법

1. 데이터베이스 스키마 확인

DESC member;

 

has_event_invitation_reward 컬럼이 존재하지 않음을 확인

2. 컬럼 추가

ALTER TABLE member 
ADD COLUMN has_event_invitation_reward VARCHAR(1) NULL;

3. 애플리케이션 재시작

  • 컬럼 추가 확인
  • 애플리케이션 정상 기동 확인

 

ddl-auto 옵션

옵션동작 방식사용 환경
create 기존 테이블 삭제 후 재생성 사용 금지 (데이터 손실)
create-drop 애플리케이션 종료 시 테이블 삭제 테스트 환경
update 엔티티 변경사항만 스키마에 반영 로컬 개발 환경만
validate 스키마 검증만 수행, 변경 없음 운영 환경
none 아무 작업도 수행하지 않음 운영 환경

운영 환경에서 validate를 사용하는 이유

  • 안전성: 의도하지 않은 스키마 변경 방지
  • 명시성: 모든 스키마 변경을 명시적으로 관리
  • 추적성: 변경 이력 관리 용이
  • 롤백 가능성: 문제 발생 시 되돌릴 수 있음

 

추가 개선 방안

- Flyway 도입하기

 

 

후기

분명 스프링부트를 공부할 때 JPA의 ddl-auto 설정 5가지를 모두 테스트하며 각 옵션의 동작 방식을 확인했었다. create는 테이블을 삭제하고 재생성하고, update는 변경사항만 반영하고, validate는 검증만 한다는 것을 알고 있었다.

하지만 막상 실제 운영 서비스에서 에러가 발생했다. 더 심각한 건 새벽도 아닌 낮시간대 유저들이 한창 서비스를 이용하고 있는 시간대에 서버가 다운되었다는 것이었다. 운영 서버 장애는 처음이었다. 로그를 확인하고, 원인을 파악하고, 급하게 SQL을 실행하고 서버를 재시작하는 30분에 온 에너지를 다 썼다. 심장이 매우 빠르게 뛰고 기진맥진했다.

 

정말 이론과 실전은 다르다

로컬에서는 ddl-auto: update로 설정되어 있어 엔티티만 수정하면 테이블 구조가 자동으로 변경되어서 이게 너무 편했고 당연하게 여겼다. 하지만 운영 환경에서는 validate 모드가 설정되어 있는 걸 알고 있어도 바로 대응하지 못했다.

 

이후로 스타트업이라 스프린트 단위가 짧고 그만큼 기능 추가가 잦아 DB 스키마 변경이 빈번하다는 꺠닫고 PR에 배포 전 체크리스트를 만들어 항상 확인하면서 작업해서 이 날 이후로는 해당 에러로 서버가 다운되는 일은 없었다.

 

백엔드를 혼자 작업하다보니 검토해 줄 사수도 물어볼 동료도 없었다. PR을 올려도 내가 직접 머지했고, 배포도 내가 직접 했다. 평소에는 이런 자율성이 좋았다. 빠르게 결정하고, 빠르게 구현하고, 빠르게 배포할 수 있었으니까. 하지만 이번 일로 자율성에는 그만큼의 책임이 따른다는 것을 뼈저리게 느끼게 되었다.

 

 

 

반응형