Delivery 프로젝트는 대용량 트래픽을 대비해 Scale-out 환경으로 구축했습니다.
Scale-out 환경엔 session 로그인 구현 시 아래 그림과 같은 문제가 생길 수 있는데
로그인을 했음에도 세션이 저장되어 있지 않은 서버가 요청을 받는다면 다시 로그인을 해야 하는 문제입니다.
저는 session storage 방식으로 해결했습니다. 세션을 관리하는 Redis 서버를 별도로 두어 어느 애플리케이션 서버에 요청이 들어와도 로그인은 한 번만 하면 됩니다.
UserLoginService
@Service
@AllArgsConstructor
public class UserLoginService {
private final HttpSession httpSession;
private final UserRepository userRepository;
private final String USER_ID = "USERID";
public void login(String email, String password) {
User user = userRepository.findByEmailAndPassword(email, password);
httpSession.setAttribute(USER_ID, user.getId());
}
public void logout() {
httpSession.removeAttribute(USER_ID);
}
}
Httpsession 객체를 통해 로그인과 로그아웃을 구현하였습니다. 아직까진 로컬에 있는 세션 스토리지를 통해 관리가 됩니다.
Redis에 세션을 관리하기 위해선 아래의 의존성을 추가하고, Redis config 클래스를 작성하면 됩니다.
implementation 'org.springframework.session:spring-session-data-redis'
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory());
return redisTemplate;
}
}
아래는 로그인 후 Redis에 저장된 session 데이터 입니다. sessionAttr:USERID 실제 유저의 id 값 입니다.
참고로 값이 복잡하게 되어있는데 redis config 클래스에서 직렬화 설정에 따라 저장하는 방식이 달라집니다.
'project > Delivery' 카테고리의 다른 글
[Delivery] 여러 명의 Rider가 동시에 동일한 주문 배달을 접수할 때 이슈 (0) | 2022.01.07 |
---|---|
[Delivery] 반복되는 로직을 AOP로 분리하기 (0) | 2021.12.31 |
[Delivery] 프로젝트 구조 (0) | 2021.12.28 |
댓글