[인프라] 로드밸런싱: NGINX와 Spring을 활용한 서버 확장 전략

dakcoh·2024년 8월 30일


이번 포스트에서는 로드밸런싱 (Load Balancing)에 대해 공부해보겠습니다.
Spring BootNGINX를 연동하여 다중 서버 환경에서 트래픽을 효과적으로 분산시키는 방법을 소개하려고 합니다.

로드밸런싱은 서버 간 트래픽을 효율적으로 분배하여 고가용성과 안정성을 제공하는 중요한 기술입니다.

특히, 스케일 아웃을 통해 서버를 수평으로 확장할 때 필수적으로 사용됩니다.

이 글에서는 다양한 로드밸런싱 방식과 함께, NGINXSpring을 연동한 예시를 코드로 작성하며 공부해보겠습니다.


로드밸런싱이란?

로드밸런싱은 여러 대의 서버에 클라이언트 요청을 고르게 분배하여 서버 간의 부하를 최소화하고 성능을 최적화하는 방법입니다.

이를 통해 트래픽이 특정 서버에 몰리는 상황을 방지할 수 있으며, 서버 하나에 문제가 생기더라도 다른 서버가 트래픽을 처리하여 서비스 장애를 예방할 수 있습니다.

로드밸런싱 방식

로드밸런서는 다양한 분배 방식을 지원하며, 상황에 따라 적절한 방식을 선택할 수 있습니다.

  • Round Robin: 서버에 순차적으로 트래픽을 분배하는 방식. 간단하고 균등한 분배가 가능합니다.

  • Least Connections: 현재 연결된 클라이언트 수가 가장 적은 서버에 트래픽을 보내는 방식. 동적 트래픽 처리에 유용합니다.

  • IP Hash: 클라이언트의 IP 주소를 기반으로 트래픽을 분배하여 동일한 IP에서 오는 요청을 항상 같은 서버로 전달하는 방식. 세션 유지를 위한 서비스에 적합합니다.

로드밸런싱 방식을 선택할 때는
애플리케이션의 특성트래픽 패턴을 고려하여 가장 적합한 방식을 선택하는 것이 중요합니다.


Spring Boot 로드밸런싱 구현

Spring Cloud를 사용하면 클라이언트 측 로드밸런싱을 적용할 수 있습니다.
이때, RestTemplate@LoadBalanced 어노테이션을 사용하여 요청을 다중 서버로 분배할 수 있습니다.

RestTemplate 로드밸런싱 설정

1. 의존성 추가 (pom.xml)

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

2. RestTemplate 설정

@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

3. 클라이언트 요청 분배

@RestController
public class MyController {

    @Autowired
    @LoadBalanced
    private RestTemplate restTemplate;

    @GetMapping("/invoke")
    public String invokeService() {
        // 서비스 이름을 통해 여러 인스턴스에 요청 분배
        return restTemplate.getForObject("http://my-service/data", String.class);
    }
}

이 코드는 my-service라는 서비스의 여러 인스턴스에 트래픽을 자동으로 분배하여, 클라이언트의 요청을 효율적으로 처리할 수 있게 합니다.

서비스 디스커버리 도구인 Eureka와 함께 사용하면, 서비스 인스턴스를 동적으로 등록하고 관리할 수 있어 로드밸런싱의 유연성이 더욱 향상됩니다.


NGINX 로드밸런서 설정

NGINX는 서버 간 트래픽 분산을 위해 사용되는 역방향 프록시로드밸런서입니다.
NGINX를 설정하면 쉽게 여러 서버에 트래픽을 분배하고, 서버 상태에 따라 유연하게 대응할 수 있습니다.

NGINX 로드밸런서 설정 예제

1. Round Robin 방식 분배

upstream backend_servers {
    server 192.168.1.101;  # 백엔드 서버 1
    server 192.168.1.102;  # 백엔드 서버 2
    server 192.168.1.103;  # 백엔드 서버 3
}

server {
    listen 80;

    location / {
        proxy_pass http://backend_servers;  # 요청을 백엔드 서버로 전달
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

이 설정은 NGINX가 클라이언트로부터 요청을 받아서 백엔드 서버로 전달하고, 순차적으로 트래픽을 분배하는 Round Robin 방식입니다.

2. Least Connections 방식

upstream backend_servers {
    least_conn;  # 현재 연결이 적은 서버로 트래픽을 분배
    server 192.168.1.101;
    server 192.168.1.102;
    server 192.168.1.103;
}

이 방식은 서버의 현재 연결 상태를 기반으로 트래픽을 분배하여, 상대적으로 여유가 있는 서버가 더 많은 트래픽을 처리하게 합니다.

Least Connections 방식은 동적으로 변화하는 트래픽에 더 효과적으로 대응할 수 있습니다.

3. IP Hash 방식(세션유지)

upstream backend_servers {
    ip_hash;  # 클라이언트 IP를 기반으로 트래픽을 분배
    server 192.168.1.101;
    server 192.168.1.102;
    server 192.168.1.103;
}

클라이언트가 동일한 서버에 지속적으로 연결되도록, IP 주소를 해싱해 요청을 처리합니다. 세션을 유지해야 하는 서비스에 적합합니다.

IP Hash 방식은 특정 클라이언트가 항상 같은 서버로 연결되기 때문에, 세션 유지가 중요한 애플리케이션에서 유용합니다.

4. 헬스 체크(Health Check)

백엔드 서버의 상태를 체크하여, 장애가 발생한 서버로 트래픽을 보내지 않도록 설정할 수 있습니다.

upstream backend_servers {
    server 192.168.1.101;
    server 192.168.1.102;
    server 192.168.1.103;
}

server {
    listen 80;

    location / {
        proxy_pass http://backend_servers;
        health_check;  # 헬스 체크 활성화
    }
}

health_check 옵션은 NGINX가 백엔드 서버의 상태를 주기적으로 확인하여, 문제가 있는 서버에 트래픽을 보내지 않도록 도와줍니다.

헬스 체크 기능을 활성화하면,
서버 장애 시 자동으로 트래픽 분배가 조정되어 서비스의 신뢰성을 높일 수 있습니다.


NGINX와 Spring Boot 연동

NGINX와 Spring Boot를 함께 사용하여 다중 서버로 트래픽을 분배하는 방법을 알아보겠습니다.

NGINX와 Spring Boot 연동

1. NGINX 로드밸런서 설정

upstream spring_backend {
    server 192.168.1.101:8080;  # Spring Boot 애플리케이션 1
    server 192.168.1.102:8080;  # Spring Boot 애플리케이션 2
    server 192.168.1.103:8080;  # Spring Boot 애플리케이션 3
}

server {
    listen 80;

    location / {
        proxy_pass http://spring_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

이 설정은 NGINX가 3대의 Spring Boot 서버에 트래픽 분배의 예시입니다.
클라이언트는 NGINX만 바라보고 요청을 보내면, NGINX가 내부적으로 트래픽을 다수의 Spring Boot 인스턴스로 분배합니다.

클라우드 환경에서 AWS ELB, GCP Load Balancer와 같은 로드밸런싱 서비스를 활용하면 설정이 더 간단해지며, 자동 확장 기능을 통해 유동적인 트래픽 증가에도 유연하게 대응할 수 있습니다.

2. Spring Boot 설정

각 Spring Boot 애플리케이션은 동일한 설정으로 배포되어야 하며, 포트는 각각 다르게 설정할 수 있습니다.

# application.yml
server:
  port: 8080

모든 Spring Boot 인스턴스가 동일한 설정을 사용하도록 하여, 로드밸런서가 트래픽을 분배할 때 일관된 응답을 받을 수 있도록 합니다.


NGINX와 Spring Boot 연동

실제 환경에서 NGINX와 Spring Boot를 연동하여 로드밸런싱을 적용하는 방법을 예제로 살펴보겠습니다.

1. NGINX 설정 파일 작성

upstream spring_backend {
    server 192.168.1.101:8080;
    server 192.168.1.102:8080;
    server 192.168.1.103:8080;
}

server {
    listen 80;

    location / {
        proxy_pass http://spring_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

이 설정은 클라이언트의 요청을 spring_backend 풀에 정의된 Spring Boot 서버들로 분배합니다.

2. Spring Boot 실행

각 서버에서 Spring Boot 애플리케이션을 다음과 같이 실행합니다.

java -jar -Dserver.port=8080 app.jar

각 인스턴스의 포트를 다르게 설정하여 동일한 포트 충돌을 방지할 수 있습니다.

3. NGINX 재시작

설정 파일을 수정한 후 NGINX를 재시작하여 변경 사항을 적용합니다.

sudo systemctl restart nginx

설정 파일에 오류가 없는지 확인하기 위해 NGINX 설정 테스트를 먼저 수행하는 것이 좋습니다. [아래]

sudo nginx -t

마무리

로드밸런싱은 서버 확장에서 필수적인 기술입니다.
특히 스케일 아웃을 통한 다중 서버 환경에서 트래픽을 효과적으로 분산시키는 방법을 이해해야합니다.

다음으로는 로드밸런싱 알고리즘인 라운드 로빈(Round Robin)에 대해서 공부해보겠습니다.

감사합니다!


관련글 > [인프라] 최적의 서버 확장 전략: 스케일 아웃 & 스케일 업

profile
포기하기 금지

0개의 댓글