ecsimsw
자주 사용하는 미들웨어의 통신 방법 2 - 웹 서버와 DBMS 본문
미들웨어
미들웨어는 애플리케이션 사이에서 데이터 흐름을 중계하거나 처리하기 위한 소프트웨어를 말한다. 사실 단순히 큐나 메시지 브로커만을 말하는 줄 알았는데, 정의에 따르면 WAS, GW, MQ, DBMS 등 내가 기존에 생각하고 있던 것보다 더 넓은 범위의 키워드로 생각된다.
요즘 이벤트 서버 성능 개선에 머리를 쓰고 있고, 서버를 구성하는 각 요소들의 성능 개선을 위해선 지금 어떻게 통신하고 있는지부터 알아야겠다는 생각이었다. 특히 톰캣에 요청이 너무 많이 유입이 돼서 에러가 날 때, 에러를 읽고 튜닝할 수 있는 눈이 필요했다. 자주 사용하고 있는 미들웨어들의 기본 설정이나 통신 방식들을 정리한다.
# 메시지 브로커와 큐
1. Kafka
2. RabbitMQ
3. Redis pub/sub
4. AWS SQS
5. Mosquitto와 MQTT
# 웹 서버
6. Tomcat
7. Nginx
8. ALB
# DBMS
9. Mysql
10. MongoDB
HTTP
1. TCP, Handshake
- HTTP는 TCP 위에서 동작한다.
- 연결을 시작하면 3 way handshake를 시작한다.
1. 클라이언트 → 서버 : SYN 패킷 전송 (연결 요청)
2. 서버 → 클라이언트 : SYN-ACK 패킷 응답 (요청 수락)
3. 클라이언트 → 서버 : ACK 전송 (확인)
- 연결을 마칠 땐 4 way handshake로 종료한다.
1. 클라이언트 → 서버 : FIN 패킷 전송 (연결 종료 요청)
2. 서버 → 클라이언트 : ACK 패킷 응답 (종료 요청 승인)
3. 서버 → 클라이언트 : FIN 패킷 전송 (서버도 종료 요청)
4. 클라이언트 → 서버 : ACK 패킷 응답 (서버 종료 승인)
2. 버전별 주요 특징
- Http 1.0 : 요청마다 새로운 TCP 연결
- Http 1.1 : 연결 유지, 파이프라이닝 (HOL Blocking)
- Http 2.0 : 멀티 플렉싱, Header 압축
- (주요 브라우저는 Http 1.1에서 동일 도메인으로 최대 6개까지 TCP 연결을 표준으로 한다.)
3. 연결 유지
- TCP Handshake는 비용이 크고, 요청마다 이를 반복하긴 아깝다.
- Http 1.1부터는 Keep alive를 지원하여 하나의 커넥션을 재사용하여 Handshake 비용을 피한다.
- Keep alive로 연결이 지속되는 커넥션은 서버(프로세스)가 열어둔 소켓을 차지하고, 소켓은 OS의 FD를 사용한다.
- 즉 최대 연결 개수는 프로세스가 허용한 최대 연결 개수와 해당 프로세스가 점유할 수 있는 FD 개수의 MIN 값이 된다.
- WAS의 최대 스레드와 헷갈려선 안된다.
- 스레드는 요청이 처리될 때 사용되고, 커넥션 개수는 OS의 FD의 문제이다.
- 톰캣 스레드가 200개라고, 200개의 커넥션만을 갖을 수 있는 것이 아니다.
- "ulimit -n" 으로 OS의 프로세스 별 최대 FD 개수를 확인한다.
4. 연결 상태 확인 커멘드
- lsof -i -n -P | grep $PID : 프로세스가 소유한 연결 정보 목록
- netstat -ant : 전체 TCP 연결 상태 확인
LISTEN : 서버가 접속 대기중
ESTABLISHED : 연결 성립, 데이터 송수신 가능
TIME_WAIT : 종료 후 남아있는 소켓
CLOSE_WAIT : 상대가 연결 종료, 내 쪽은 연결 유지 중
- *:42855 : 해당 프로세스는 42855로 외부 접속을 대기하고 있다.
- 10.0.0.9:60940처럼 서로 다른 시작 포트를 갖는 것은, 해당 프로세스가 클라이언트로 참여한 연결을 의심해 볼 수 있다.
멀티플렉싱 기반 서버
1. 스레드 기반
- 스레드 기반의 서버는 요청 당 1개의 스레드가 할당되어야 한다.
- 연결 과정의 비용을 아끼기 위해 미리 연결을 맺어둔 커넥션 풀에서 연결을 재사용한다.
- 해당 스레드가 로직과 쿼리를 모두 담당하여, 요청 후 대기(블록킹)가 필요하다.
- 스레드 전환 비용이 발생한다.
- (ex, Tomcat, Mysql, Apache)
2. 멀티 플렉싱 기반
- 소수의 스레드가 여러 커넥션을 이벤트 단위로 관리한다.
- 커널 단의 epoll, kqueue를 이용하여, 요청 후 대기 없이 다른 로직을 처리하다가, 데이터가 오면 콜백으로 처리한다.
- 길어진 몇 안 되는 이벤트 블록킹으로도 전체 서버에 큰 영향이 미칠 수 있어, 꼼꼼한 설계가 필요하다.
- (ex, Netty, Nginx, Redis, MongoDB, Node.Js)
Mysql과 HikariCP
1. 주요 설정과 기본 값
- Mysql 최대 커넥션 수 : 151
- Mysql 유휴 커넥션 타임아웃 : 8시간
- HikariCP 최대 풀 크기 : 10
- HikariCP 커넥션 요청 대기 시간 : 30s
- HikariCP Max life time : 30m
- HikariCP Idle timeout : 10m
- HikariCP Validation timeout : 5s
2. HikariCP에서 커넥션을 얻는 과정
- ThreadLocal에서 기존에 대여했던 커넥션이 있는지와 해당 커넥션이 사용 가능한지 여부 확인
- 사용 가능하다면 이를 다시 사용하고, 없다면 ConcurrentBag에서 대여 가능한 커넥션 검색
- 현재 대여 가능한 커넥션이 없다면 HandOffQueue에서 커넥션 할당 대기
- connectionTimeout 시간 동안 커넥션을 얻지 못하면 SQLException 반환
- 커넥션을 얻어서 사용 후에는 다시 커넥션 풀에 반납
3. 커넥션 검증 (HouseKeeper)
- HouseKeeper가 스케줄링되며 커넥션 풀의 연결 상태 검증
- 현재 사용 중인 연결을 제외하고, Validation query 또는 JDBC Driver의 isValid 등으로 정상 여부 검증
- Max life time / Idle timeout 을 넘은 연결 제거
- 커넥션 풀의 연결 사이즈가 Min 값보다 작을 시 재연결
MongoDB
1. 주요 설정과 기본 값
- 최대 연결 커넥션 : 65536 (OS의 FD 개수 제한이 더 결정적)
- MongoDB Java 드라이버의 기본 커넥션 풀을 활용 (Spring data MongoDB)
- 최대 풀 커넥션 수 : 100
- 최소 유휴 커넥션 수 : 0
- 유휴 커넥션 최대 유지 시간 : 비활성 (유휴 커넥션 폐기하지 않음)
톰캣
1. 주요 설정과 기본 값 (스프링부트 내장 톰캣)
- 최대 스레드 수 : 200
- 최대 큐 사이즈 : 100
- 최대 커넥션 수 : 8192
- 기본 프로토콜 : HTTP/1.1
- Keep Alive timeout : 20s (연결 후 다음 요청까지 대기 시간)
- Connection timeout : 20s (최초 Handshake - 연결 후, 요청까지 대기 시간)
Nginx
1. 주요 설정과 기본 값
- 워커 프로세스 수 : Auto (동시 처리 프로세스 개수, 코어 수에 따라 자동 할당)
- 워커 커넥션 수 : 1024 (워커 프로세스 당 차지할 수 있는 커넥션/소켓 수)
- Proxy read timeout : 60s (백엔드로 요청을 전달하고 응답 대기 시간)
- Proxy connect timeout : 60s (백엔드에 연결을 시도하고, 연결까지의 최대 대기 시간)
AWS Loadbalancer
1. ALB vs NLB
'Architecture > Infrastructure' 카테고리의 다른 글
자주 사용하는 미들웨어의 통신 방법 1 - 메시지 브로커와 큐 (4) | 2025.08.13 |
---|---|
Vault kubernetes injector 소개 (0) | 2024.05.31 |
CDN URL 암호화, CloudFront signed url (1) | 2024.04.10 |
Nginx 엑세스 로그로 응답 시간 모니터링 (0) | 2024.03.20 |
AWS S3 의 비용이 부담된다면? Vultr Object storage 소개 (1) | 2023.12.31 |