ecsimsw

자주 사용하는 미들웨어의 통신 방법 2 - 웹 서버와 DBMS 본문

자주 사용하는 미들웨어의 통신 방법 2 - 웹 서버와 DBMS

JinHwan Kim 2025. 8. 24. 17:44

미들웨어

미들웨어는 애플리케이션 사이에서 데이터 흐름을 중계하거나 처리하기 위한 소프트웨어를 말한다. 사실 단순히 큐나 메시지 브로커만을 말하는 줄 알았는데, 정의에 따르면 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

 

Comments