문제
서버 2개, 라우터(Load balancer (회로로 동작)) 1개 라고 가정
1번 서버에서 로그인을 하면 1번서버의 세션에 값을 저장하고 클라이언트에게 jsessionId를 전달한다
이후 클라이언트는 전달 받은 JsessionId를 이용하여 인가를 하려고 할 때 1번 서버에 부하가 심해 2번서버로 접근할 수도 있고
이런 경우 2번서버는 세션에 값이 없기 때문에 유저는 인가를 받을 수 없다.
이를 해결할 수 있는 전략?
세션 공유 전략 :
세션 클러스터링
서버 간에 세션 정보를 공유하도록 설정합니다. 이를 통해 각 서버는 모든 세션에 접근할 수 있게 됩니다. 일반적으로 다음과 같은 방법으로 구현할 수 있습니다.
- 데이터베이스 기반 세션 저장: 세션 정보를 데이터베이스에 저장하고 모든 서버가 동일한 데이터베이스에 접근하도록 합니다. 이를 통해 모든 서버가 동일한 세션 정보를 갖게 됩니다.
- 메모리 기반 세션 저장: Redis나 Memcached와 같은 메모리 데이터 저장소를 사용하여 세션 정보를 중앙에서 관리합니다. 모든 서버는 이 저장소에 접근하여 세션 정보를 읽고 씁니다.
세션 스티키네스 (Session Stickiness)
로드 밸런서를 설정하여 특정 클라이언트가 항상 동일한 서버에 연결되도록 합니다. 이를 통해 세션 정보를 공유하지 않고도 동일한 서버에서 세션을 유지할 수 있습니다.
- IP 해싱: 클라이언트의 IP 주소를 해싱하여 특정 서버에 항상 연결되도록 합니다.
- 쿠키 기반: 로드 밸런서가 클라이언트 쿠키를 기반으로 요청을 동일한 서버로 라우팅하도록 합니다.
세션을 공유하지 않는 전략 :
JWT (JSON Web Token) 사용
세션 대신 JWT를 사용하여 인증을 처리할 수 있습니다. JWT는 클라이언트 측에 저장되며, 각 요청 시마다 서버로 전송됩니다. 서버는 JWT를 검증하여 사용자를 인증합니다.
- 장점: 중앙 저장소가 필요 없으며, 서버 간에 세션 정보를 공유할 필요가 없습니다.
- 단점: JWT 자체가 클라이언트 측에서 안전하게 저장되어야 하며, 만료 기한과 같은 보안 설정을 신중하게 다루어야 합니다.
예제: 데이터베이스 기반 세션 저장
import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;
@EnableJdbcHttpSession
public class HttpSessionConfig {
// 데이터베이스 연결 설정
}
예제: Redis 기반 세션 저장
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
@EnableRedisHttpSession
public class HttpSessionConfig {
// Redis 연결 설정
}
Share article