
이번 포스트에서는 서버를 확장할 때 고려할 수 있는 전략으로
스케일 업, 스케일 아웃에 대해 자세히 다뤄보려고 합니다.
각각의 전략이 무엇인지, 언제 사용하면 좋은지 그리고 실전에서 어떻게 적용할 수 있는지 코드 예시와 함께 공부해보겠습니다.
스케일 업은 서버 한 대의 성능을 높이는 방식입니다.
즉, CPU나 메모리(RAM)를 업그레이드해서 서버가 더 많은 요청을 처리를 할 수 있습니다.
간단하게 하드웨어 성능을 개선하면 되기 때문에 적용이 쉬운 편이지만, 물리적인 한계에 도달하면 더 이상 확장이 불가능하다는 천장이 존재합니다.
1. 단일 애플리케이션에서 성능 병목이 발생할 때
2. 데이터베이스 서버나 캐시 서버처럼 복잡한 로드밸런싱이 어려운 경우
3. 성능 향상이 즉시 필요할 때 (빠른 성능 개선이 가능)
Java 애플리케이션의 메모리 관리를 최적화하기 위해 JVM 힙 크기를 조정할 수 있습니다.
이를 통해 서버의 메모리 용량이 늘어났을 때 더 효율적으로 리소스를 활용할 수 있습니다.
# 메모리 설정 예시
java -Xms1024m -Xmx4096m -jar app.jar
위 코드에서 -Xms는 초기 힙 크기, -Xmx는 최대 힙 크기를 설정하는 옵션입니다.
여기서는 1GB의 초기 힙 메모리와 4GB의 최대 힙 메모리를 설정하여 서버 메모리 리소스를 효율적으로 사용할 수 있도록 했습니다.
Scale-Up 주의사항
JVM 메모리 설정은 무조건 많이 할당한다고 좋은 게 아닙니다.
충분한 메모리 모니터링 후 적절한 크기로 설정하는 것이 성능에 더 긍정적입니다.
스케일 아웃은 서버 대수를 늘리는 방법입니다.
즉, 여러 대의 서버가 동일한 애플리케이션을 실행하여 트래픽을 분산시켜주는 전략입니다.
이 방법은 특히 무한에 가까운 확장성을 제공하기 때문에, 대규모 트래픽을 처리해야 하는 서비스에 적합합니다.
한 서버에 모든 요청이 집중되지 않도록, 여러 서버가 동일한 애플리케이션을 실행하고 로드밸런싱을 통해 트래픽을 분산시켜 줍니다.
1. 트래픽이 계속해서 증가하는 경우
2. 다중 서버를 이용해 안정성을 강화하고자 할 때
3. 장기적인 확장성을 고려할 때 (성능의 물리적 한계가 없기 때문에 확장 가능성이 크다)
스케일 아웃에서 중요한 점은 애플리케이션 간의 세션 관리와 데이터 동기화입니다.
이를 해결하는 일반적인 방법으로는 세션을 외부에 저장하는 방식과, 로드밸런서를 사용한 트래픽 분산이 있습니다.
서버 간의 세션을 공유하기 위해서는 Redis와 같은 외부 세션 저장소를 사용할 수 있습니다. 이렇게 하면, 각 서버가 독립적으로 세션을 저장하지 않고도 세션 상태를 유지할 수 있어요.
이번엔 Redis는 간략하게 알아보고, 다음에 자세히 알아보도록 합시다.
<!-- build.gradle 또는 pom.xml에 Redis 의존성 추가 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
# application.yml
spring:
session:
store-type: redis
redis:
host: localhost
port: 6379
@RestController
@RequestMapping("/session")
public class SessionController {
@GetMapping("/set")
public String setSession(HttpSession session) {
session.setAttribute("user", "dakcoh");
return "Session data set!";
}
@GetMapping("/get")
public String getSession(HttpSession session) {
return "Hello, " + session.getAttribute("user");
}
}
Redis는 매우 빠른 속도로 세션을 처리할 수 있습니다.
떄문에 여러 대의 서버가 동일한 세션 상태를 유지해야 하는 환경에 매우 적합합니다.
스케일 아웃 시 로드밸런싱을 통해 트래픽을 여러 서버에 고르게 분배하는 것이 핵심입니다.
스프링 클라우드에서는 RestTemplate에 @LoadBalanced 애너테이션을 사용해 클라이언트 측 로드밸런싱을 쉽게 구현할 수 있습니다.
# application.yml
spring:
cloud:
loadbalancer:
ribbon:
enabled: true
@RestController
public class MyController {
@Autowired
@LoadBalanced
private RestTemplate restTemplate;
@GetMapping("/invoke")
public String invokeService() {
return restTemplate.getForObject("http://my-service/endpoint", String.class);
}
}
위 코드는 my-service라는 이름의 서비스에 요청을 보낼 때, 여러 서버 중 하나로 분배해주는 로드밸런싱 로직을 구현한 예시입니다.
클라우드 환경에서는
AWS Elastic Load Balancer(ELB)나 GCP Load Balancer 같은 서비스를 사용하면, 서버 추가 및 관리가 더 쉬워집니다.
또한 클라우드 로드밸런서와 함께 오토스케일링(Auto Scaling)을 설정하면 트래픽 증가에 따라 서버 인스턴스가 자동으로 추가되며 스케일 아웃이 유연하게 가능합니다.
서버 확장 전략에서 스케일 업과 스케일 아웃은 각각의 강점과 한계를 가지고 있습니다.
Java 애플리케이션에서 스케일 업은 성능 병목을 하드웨어 업그레이드로 빠르게 해결할 수 있는 반면, 스케일 아웃은 더 큰 확장성과 고가용성을 제공합니다.
다음은 스케일 아웃을 통한 트래픽 분산과 대용량 데이터 처리에 대해서 공부해보려고 합니다.
또, 스케일 아웃을 공부하며 로드밸런싱에 대해 같이 진행해보겠습니다.
감사합니다.