1️⃣ NginX의 특징
✅ 1. 비동기 이벤트 기반 아키텍처
- NginX는 이동기 이벤트 기반(Asynchronous, Event-driven) 모델을 사용하여 높은 성능을 제공
- Apache(쓰레드 기반)와 달리, 하나의 워커 프로세스가 비동기적으로 다수의 요청 처리 가능
- 결과적으로 동시에 많은 요청을 처리할 수 있어 CPU와 메모리 사용량이 적음
✅ 2. 정적 콘텐츠(HTML, CSS, JS) 제공 최적화
- NginX는 정적 파일(HTML, CSS, JS 이미지 등) 제공이 빠름
- 캐싱 기능을 활용하면 서버 부하를 줄이고 응답 속도를 개선 가능
✅ 3. Reverse Proxy & Load Balancing 지원
- 리버스 프록싱(Reverse Proxy) : 클라이언트의 요청을 받아서 백엔드 서버로 전달하고, 응답을 클라이언트에 반환
- 로드 밸런싱(Load Balancing) : 여러 개의 백엔드 서버에 트래픽을 분산하여 부하를 줄이는 역할
✅ 4. 보안 및 HTTPS 지원
- SSL/TLS를 사용하여 HTTPS 적용 가능.
- DDos 공격 방어 및 IP 차단 설정 가능.
✅ 5. 마이크로서비스 & 컨테이너와의 호환성
- Docker, Kubernetes 등의 환경에서 API Gateway 역할 수행
- 마이크로서비스 아키텍처에서 서비스 간 트래픽을 관리하는 역할 수행
위 같은 기능중 로드 밸런싱을 적용해 보겠다.
✅ 로드 밸런싱이란?
- 사용자의 요청을 여러 개의 서버( 백엔드 서버 ) 로 분산하는 기술.
* 장점
- 성능 향상 : 하나의 서버가 감당하는 부하를 줄여 성능 최적화
- 가용성 증가 : 특정 서버가 다운되더라도 다르서버가 서비스 유지
- 확장성 확보 : 트래픽 증가 시 서버 추가 가능
✅ NginX에서 지원하는 로드 밸런싱 방식
1. Round Robin ( 기본 값 ) -> 서버에 순차적으로 요청 분배
2. Least Connections -> 현재 연결이 가장 적은 서버에 요청 전달
3. IP Hash -> 클라이언트의 ip를 해싱하여 해싱 값을 이용해 로드밸런싱하여 항상 같은 서버로 전달
4. Weighted Load Balancing -> 성능이 다른 서버를 이용할 때 특정 서버에 가중치를 두어 더 많은 트래픽 할당 가능
📌 2. 기본적인 NginX 로드 밸런싱 설정
- NginX는 기본적으로 Reverse Proxy 기능을 활용하여 로드 밸런싱을 수행한다.
🔹 1️⃣ NginX 설치
Ubuntu에서 NginX 설치
sudo apt update
sudo apt install nginx -y
설치 후 NginX 상태 확인
sudo systemctl status nginx
🔹 2️⃣ nginx.conf 설정 파일 수정
sudo nano /etc/nginx/nginx.conf
아래와 같이 설정을 추가
✅ 기본 Round Robin 방식 (순차적 요청 분배)
http {
upstream backend_servers {
server 192.168.1.101:8080; # 첫 번째 서버
server 192.168.1.102:8080; # 두 번째 서버
server 192.168.1.103:8080; # 세 번째 서버
}
server {
listen 80;
server_name example.com;
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;
}
}
}
- 배포할 EC2의 PrivateIP를 작성해주면 로드밸런싱이 적용된다.
📌 설명
- upstream backed_servers : 여러 개의 백엔드 서버를 그룹으로 정의.
- server IP:PORT : 특정 IP와 포트를 가진 서버 추가
- proxy_pass http://backed_servers; 클라이언트의 요청을 백엔드 서버 그룹으로 전달
📌 3. 로드 밸런싱 방식 변경
✅ 1) Least Connections (연결이 가장 적은 서버에 배분)
✅ 2) IP Hash (사용자의 IP에 따라 고정 서버 배정)
✅ 3) 가중치 기반 로드 밸런싱 (서버 성능에 따라 트래픽 차등 배분)
📌 4. 헬스 체크 (서버 상태 감지)
upstream backend_servers {
server 192.168.1.101:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.102:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.103:8080 max_fails=3 fail_timeout=30s;
}
📌 설정 설명
• max_fails=3 → 3번 연속 실패하면 해당 서버 제외
• fail_timeout=30s → 30초 동안 서버 응답 확인 후 다시 추가
* 현재 프로젝트에서 적용중인 로드밸런싱 형태이다.
- nginx 인스턴스에 NginX를 적용하여 quiz, quiz2 인스턴스에 로드밸런싱을 적용한 이미지이다.
* 웹 소켓 로드 밸런싱 ( Trouble ... )
✅ 문제 상황
- 사용자( user )는 예시 사진처럼 분산 접속이 되는 상황이다.
- roomlist 경로는 roundrobin 방식 로드 밸런싱 적용.
- room 경로는 roomid 값을 기준으로 iphash 로드 밸런싱을 적용.
- quiz( 인게임 ) 경로도 room 경로와 마찬가지로 roomid 기준으로 iphash 로드 밸런싱 적용.
-> 문제의 상황은 사용자는 iphash 방식으로 로드 밸런싱이 잘 적용되지만, websocket 구독경로가 랜덤으로 로드 밸런싱 됨.
-> 위 시나리오는 WebSocket 로드 밸런싱이 사용자와 일치 하지 않았을때 시나리오다.
-> 즉 사용자의 접속 서버 != websocket 접속 서버.
-> websocket으로 구현된 모든기능 ( Ex. 준비, 시작, 참가자 갱신 ) 이 작동이 안된다.
* 위 상황을 해결하기 위해서 websocket의 연결 경로인 /game을 로드 밸런싱 하기로 했다.
const socket = new SockJS("/game");
- 첫 javascript가 실행될때 연결을 하는 경로이다. "/game".
location /game {
proxy_pass http://roomId_based_servers;
access_log /usr/local/nginx/logs/room_access.log upstream_log;
}
- nginX의 /usr/local/nginx/conf/sites-available 위 경로에 있는 conf 파일에 roomId로 로드 밸런싱을 한번 더 해주었다.
- Controller에서 요청을 보내고 있는 url인 room으로 보내는것이 아닌 websocket 연결 경로인 /game 에 해주었다.
- 결론적으로 대기방은 적용이 되는데, 인게임은 Troble Shooting 중이다... ( 해결 완료. 아래 글 참조 )
#### websocket 로드 밸런싱 문제 해결 과정
* 각각의 js 마다 연결되어있는 websocket의 경로가 /game으로 같았다. ( 위 코드 const socket = new SockJS("/game")' 와 같이. )
* 게임방 프로젝트가 크게 3개의 화면으로 이루어져있다.
1. 방 리스트를 나타내는 room ( js, html ) 의 2개의 파일이 존재한다.
2. 대기방의 상태를 보여주는 game ( js, html ) 마찬가지로 2개의 파일이 존재한다.
3. 인게임 화면을 보여주는 quiz ( js, html ) 2개의 파일이 존재한다.
* 원래는 각각의 소켓이 첫줄에 적혀있는데로 "/game"과 같았다.
* 방 리스트 -> 대기방 -> 인게임 이동할때마다 같은 "/game" 경로로 끊고 재연결해서 로드 밸런싱이 제대로 이루어지지 않은것 같다.
* 현재는 방 리스트 ( "/updateOccupancy" ) , 대기방 ( "/game" ) , 인게임 ( "/ingame" ) + roomId 방 번호를 추가했다.
* roomId를 추가한 이유는 NginX가 roomId 기준으로 같은 EC2 인스턴스로 로드 밸런싱을 하기 때문이다.
* 현재 NginX 디렉터리의 /sistes-available/ 디렉터리 안에있는 dandee.dev 파일의 설정도 js 맞게 변경했다.
1. 방 리스트는 Hash 해줄 필요없이 roundrobin 방식으로 처리하였다.
2. 대기방은 "/game"으로 연결한 만큼 game 경로로 방 번호를 Hash 해서 로드 밸런싱 하였다.
3. 인게임은 "/quiz"경로로 방번호를 Hash 해서 로드 밸런싱 하였다.
* 결과
- 룸리스트, 대기방, 인게임 로드 밸런싱 적용되서 websocket 기능이 정상 작동한다!
'Project > SpringBoot' 카테고리의 다른 글
자바의 동시성 처리 방법 (3) | 2025.05.05 |
---|---|
Java의 동시성 문제를 해결가능한 3가지 방법 (0) | 2025.02.12 |
AWS 프로젝트 배포과정 (0) | 2025.01.31 |
깃허브 액션에 대해서 (0) | 2025.01.30 |
인게임 유저 관리 ( 중복 계정, equals()와 hashcode() 오버라이드 ) (0) | 2025.01.05 |