Spring을 사용하다보면 서두 부분이나 기초 관련하여 Bean 생성 주기 관련한 내용들이 있다.
그래서 ApplicationContext 값을 통하여 Bean이 잘 등록 되어 있는지 확인하거나 스프링 Bean 주입에 맞춰서 @DependOn, @PostConstruct를 통한 순서까지 정하기도 한다.
이번 실무 장애를 통해 발생한 내용을 개발 지식과 스킬을 쌓아가면서 해당 문제에 대해 원인을 파악하고 싶어 내용을 남긴다.
증상
코드 변경 사항이 없는 컨테이너 오케스케일링시 DB Connection 및 데이터 조회 불가
코드 형상 (예시)
@configuration
class config {
fun mongoDbFactory(): MongoDatabaseFactory {
return SimpleMongoClientDatabaseFactory(com.mongodb.client.MongoClient(), databaseName)
}
@Bean("serviceMongoTemplate")
fun reactiveMongoTemplate(): MongoTemplate {
return MongoTemplate(mongoDbFactory(), mappingMongoConverter)
}
}
위 코드를 보면 serviceMongoTemplate 생성시 MongoDatabaseFactory 구현체로 위의 mongoDbFactory를 호출한다.
하지만 일부 서버에서 DB와의 통신이 불가능해졌고 다음과 같은 에러가 발생하였다.
org.springframework.dao.DataAccessResourceFailureException:
Timed out after 30000 ms while waiting for a server that matches ReadPreferenceServerSelector{readPreference=primary}.
Client view of cluster state is {type=UNKNOWN,
servers=[{address=127.0.0.1:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException:
Exception opening socket}, caused by {java.net.ConnectException: Connection refused}}];
nested exception is com.mongodb.MongoTimeoutException:
Timed out after 30000 ms while waiting for a server that matches ReadPreferenceServerSelector{readPreference=primary}.
Client view of cluster state is {type=UNKNOWN, servers=[{address=127.0.0.1:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket},
caused by {java.net.ConnectException: Connection refused}}]
해결방안
위의 로그는 위의 mongoDbFactory()에서 properties에 지정한 DB값이 아닌 default의 localhost를 구성했다고 파악하고 bean 생성을 함수가 아닌 직접 호출을 통해 해결 하였다.
1. mongoDbFactory 직접 호출
@configuration
class config {
@Bean("serviceMongoTemplate")
fun reactiveMongoTemplate(): MongoTemplate {
val factory= SimpleMongoClientDatabaseFactory(com.mongodb.client.MongoClient(), databaseName)
return MongoTemplate(factory, mappingMongoConverter)
}
}
2. Template bean 생성시 Qalifer를 통해 직접 주입
@configuration
class config {
@Bean("sampleFactory")
fun mongoDbFactory(): MongoDatabaseFactory {
return SimpleMongoClientDatabaseFactory(com.mongodb.client.MongoClient(), databaseName)
}
@Bean("serviceMongoTemplate")
fun reactiveMongoTemplate(@Qualifer("sampleFactory") factory : MongoDatabaseFactory): MongoTemplate {
return MongoTemplate(factory, mappingMongoConverter)
}
}
최종적인 결론은 다음과 같다.
cglib 프록시가 적용된 configuration 클래스 내에서, bean 메서드가 호출될 때마다 같은 인스턴스를 반환하지 않으면, Spring은 해당 빈을 정상적으로 등록할 수 없다.
매번 factory 호출을 통해 직접 호출은 싱글톤 유지가 안될 것 같아 일부는 정상, 일부는 비정상으로 나올 수 있다는 결론이었다.
But 위의 Factory 호출로 변경하여 테스트 하는 중 (코드 변환 및 디렉토리 변환 없음)DB와 잘 되어 증상 발현이 되지 않는다. spring bean 생성 주기를 체크해봤는데 잘 생성되는 것으로 확인된다.
위의 원인은 앞으로도 분석해야할 문제이다. 그리고 기초를 좀 더 정확히 다듬을 것
'개발 지식 > Spring Framework' 카테고리의 다른 글
[Spring] Coroutine Suspend Cache Hit 가 되지 않다. (0) | 2023.02.11 |
---|---|
[Spring] Caffeine Cache Config 설정하기 (0) | 2023.02.05 |
[Spring] 구글 smtp 서버를 활용한 메일 보내기 (1) | 2023.01.15 |
[Reactive Mongo] Reactive MongoDB QueryDSL 버전 충돌 (0) | 2022.08.22 |
[Test] MongoDB 단위 테스트(Unit Test) 작성해보기 (4) | 2022.06.06 |
댓글