Tomcat & nginx 운영 · 커넥터와 스레드풀 튜닝 · 실습
스레드풀·힙·GC 로그를 근거 있게 설정하기
목표
공유 Executor·acceptCount·Keep-Alive·힙·GC 로그를 직접 설정하고,
리틀의 법칙으로 maxThreads 를 계산해 근거 문서를 남길 수 있게 됩니다.
왜 중요한가
성능 이슈가 생기면 늘 "maxThreads 를 올리자"는 말이 나옵니다. 그런데 그 값이
어느 지점에서 동작하는지 모르면 대부분 아무것도 바뀌지 않거나 더 나빠집니다.
maxThreads 는 '동시에 처리 중인 요청', maxConnections 는 '들고 있는 소켓',
acceptCount 는 '그마저 넘쳤을 때의 OS 백로그'이고, 백로그까지 넘치면 클라이언트는
503 이 아니라 Connection refused 를 받습니다. 이 차이를 아는 사람이 장애를 빨리 끝냅니다.
단계
1. Tomcat 을 기동한 뒤 server.xml 의 <Service> 안에 공유 Executor 를 추가합니다.name="tomcatThreadPool", namePrefix="labhub-exec-",maxThreads="150", minSpareThreads="20".
2. 8080 커넥터가 이 Executor 를 쓰도록 executor="tomcatThreadPool" 속성을 주고
재기동합니다. 요청을 몇 번 보낸 뒤 스레드 덤프를 떠서/root/tc/threads.txt 에 저장하세요. 덤프에 labhub-exec- 스레드가 보여야 합니다.
3. 8080 커넥터에 acceptCount="50", maxConnections="2000",connectionTimeout="20000" 을 설정합니다.
4. 8080 커넥터에 keepAliveTimeout="5000", maxKeepAliveRequests="100" 을 설정하고
재기동한 뒤, 한 번의 curl 로 같은 커넥션에 두 요청을 보내
그 상세 출력(-v)을 /root/tc/keepalive.txt 에 저장합니다.
파일에 Re-using existing connection 또는 Connection #0 to host 재사용 흔적이 있어야 합니다.
5. /opt/tomcat/bin/setenv.sh 의 CATALINA_OPTS 에 -Xms512m -Xmx512m 을 넣고
재기동합니다. 실행 중인 프로세스 인자에 두 값이 모두 보여야 합니다.
6. 같은 CATALINA_OPTS 에 GC 로그 옵션을 추가하고 재기동합니다.
로그 파일은 /root/tc/gc.log, 파일 회전은 5개 · 각 10MB 로 설정합니다.
재기동 후 /root/tc/gc.log 가 생성되고 비어 있지 않아야 합니다.
7. /root/tc/load.sh 를 만듭니다. 인자 두 개(URL 동시요청수)를 받아
동시에 요청을 보내고 마지막 줄에 ok=<성공수> fail=<실패수> 를 출력합니다.
HTTP 200 이면 성공, 그 외(404 포함)는 실패로 셉니다.
8. /root/tc/sizing.md 를 작성합니다. 아래 시나리오로 리틀의 법칙을 적용해
maxThreads 값을 계산하고, 계산 과정과 결과를 남깁니다.
- 목표 처리량: 300 TPS
- 평균 응답시간: 200ms
- 피크 여유율: 30%
문서에는 maxThreads=<계산값> 형태의 줄이 정확히 있어야 하고,TPS, ms, 여유율 세 단어가 모두 등장해야 합니다.
참고
- 스레드 덤프:
jcmd <PID> Thread.print또는jstack <PID> - 한 커넥션으로 두 요청:
curl -v http://127.0.0.1:8080/ http://127.0.0.1:8080/ - GC 로그 옵션 형식:
-Xlog:gc*:file=<경로>:time,uptime:filecount=<n>,filesize=<크기> - 흔한 실수 1:
Executor를Connector뒤에 선언하는 것. 참조되기 전에 정의돼야 합니다. - 흔한 실수 2:
executor를 준 커넥터에maxThreads도 같이 남겨 두고 - 흔한 실수 3: 리틀의 법칙에서 응답시간을 밀리초 그대로 곱하는 것. 초 단위로 바꿔야 합니다.
그 값이 적용된다고 믿는 것. Executor 를 쓰면 커넥터의 maxThreads 는 무시됩니다.
단계 8개
- 공유 Executor 정의
- 커넥터를 Executor 에 연결
- 커넥션 수용 파라미터
- Keep-Alive 설정과 확인
- 힙 고정
- GC 로그 활성화
- 동시 부하 스크립트
- 스레드풀 산정 근거 작성