문제 상황
현재 진행 중인 프로젝트에서, Redis를 세션 서버로 사용해 세션을 관리하고 있습니다.
테스트시에는 Redis를 이용한 세션관리가 아닌, spring 에서 기본으로 제공해주는 세션 관리 방법을 통해 세션 관리를 진행하려 했으나, 지속적으로 세션 관리 시, Redis가 사용되는 문제가 발생했습니다.
org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis
at
그로 인해 위와 같은 예외가 발생하게 되었습니다. 해당 예외는 레디스 연결에 실패했다는 예외 입니다.(테스트 시에는, 레디스가 구동중이지 않기 때문에 예외가 발생하는게 당연합니다.)
원인 분석
테스트 시에, 레디스 커넥션 관련 예외가 발생해 테스트가 실패함으로써 스프링에서 기본으로 제공해주는 세션 관리 방법이 아닌, 레디스를 사용해 세션 관리를 하고 있어서 발생한 문제임을 파악했습니다.
해결 과정
스프링부트 에서 제공하는 AutoConfiguration 기능 중 하나인, application.yml 과 같은 설정파일에
spring.session.store-type=redis # 세션을 저장하는 저장소의 타입을 레디스로 설정
다음과 같은 설정을 통해 세션 저장소를 레디스로 설정할 수있습니다. 위와 같이 설정을 하게되면 내부적으로 Spring Boot는 @EnableRedisHttpSession 어노테이션을 수동으로 추가하는 것과 동일한 구성을 자동으로 생성해줍니다. 이렇게 하면 FIlter를 구현하는 springSessionRepositoryFilter 라는 이름의 Spring 빈이 생성됩니다. (이 필터는 스프링이 세션을 지원하도록 HttpSession 구현을 대체하는 역할을 담당합니다.)
org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis
...// 불필요한 스택 트레이스는 편의상 제거 했습니다
at org.springframework.session.data.redis.RedisSessionRepository.save(RedisSessionRepository.java:42) ~[spring-session-data-redis-3.0.0.jar:3.0.0]
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:228) ~[spring-session-core-3.0.0.jar:3.0.0]
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:146) ~[spring-session-core-3.0.0.jar:3.0.0]
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:82) ~[spring-session-core-3.0.0.jar:3.0.0]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.4.jar:10.1.4]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.4.jar:10.1.4]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.0.3.jar:6.0.3]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.3.jar:6.0.3]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.4.jar:10.1.4]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.4.jar:10.1.4]
at com.aorri2.goodsforyou.common.filter.MDCLoggingFilter.doFilter(MDCLoggingFilter.java:26) ~[main/:?]
앞서 설명한 내용과 위 로그 트레이스 정보를 토대로, 문제를 파악 하고 있었습니다. 먼저 MDCLoggingFilter 라는 로깅을 위해 작성한 필터에서의 doFilter() 메서드의 필터 체인을 통해,
**SessionRepositoryFilter**.this.sessionRepository.save(***session***); 의 호출을 통해, sessionRepository를 호출할 때, 기본 SessionRepository가 아닌, RedisSessionRepository가 호출이 된다는 사실을 알게 되었습니다.
따라서 SessionRepository 의 구현체가 무엇이 있는지 먼저 찾아 봤습니다.
MapSessionRepository (org.springframework.session)
FindByIndexNameSessionRepository (org.springframework.session)
RedisIndexedSessionRepository (org.springframework.session.data.redis)
RedisSessionRepository (org.springframework.session.data.redis)
ㅇ찾아본 구현체들 중, MapSessionRepository를 테스트 시에 적용해야겠다 라고 생각했습니다.
MapSessionRepository는 MapSession을 사용하는 세션 저장소 객체 입니다. (MapSession은 이름 처럼 세션을 자바의 Map 자료구조에 담아서 저장합니다)
그렇다면 문제 해결 방법으로는 테스트 시에는, SessionRepositoryFilter를 MapSessionRepository로 변경해주면 RedisSessionRepository를 사용하지 않게 되니, 문제가 해결될 것이라고 예상했습니다.
따라서, 테스트 시에, 테스트 폴더에 있는 @Import 어노테이션이 선언되어 있는 테스트 클래스에서만, SessionRepository로 MapSessionRepository를 사용하도록 변경 함으로써, 해당 문제를 해결할 수 있었습니다.
@TestConfiguration
public class DefaultSessionConfig {
@Bean
public SessionRepositoryFilter<MapSession> sessionRepositoryFilter(
SessionRepository<MapSession> sessionRepository) {
SessionRepositoryFilter<MapSession> sessionRepositoryFilter = new SessionRepositoryFilter<>(sessionRepository);
return sessionRepositoryFilter;
}
@Bean
public SessionRepository<MapSession> sessionRepository() {
MapSessionRepository sessionRepository = new MapSessionRepository(new ConcurrentHashMap<>());
return sessionRepository;
}
}
위 내용과 관련한, 구현 내용이 궁금하신 분은 PR 해당 링크를 참고해주세요
참고 자료
https://docs.spring.io/spring-session/reference/guides/boot-redis.html
https://www.logicbig.com/tutorials/spring-framework/spring-boot/test-configuration.html
https://docs.spring.io/spring-session/docs/current/api/org/springframework/session/MapSession.html
'프로그래밍 > 프로젝트' 카테고리의 다른 글
상품 목록 조회 시, 페이징 처리 성능 개선 (2) | 2023.06.11 |
---|---|
JMeter를 통한 부하테스트 (1) | 2023.06.03 |
SQL Injection (0) | 2023.04.05 |
Builder 패턴? (0) | 2023.04.05 |
테스트 커버리지를 70% 이상 유지하면서 느낀점 (0) | 2023.03.21 |