개요
현재 카카오에서 대부분의 웹서버는 L3DSR (Direct Server Return)구성의 L7 HealthCheck 방식을 사용 중입니다. L7 HealthCheck 방식은 앞서 블로그에서 기술한적이 있는 것처럼 OSI 7Layer 중 Layer7 계층의 어플리케이션 응답을 체크하는 방식입니다. 카카오에서는 L4장비가 주기적으로 서버와 TCP 세션을 맺고 GET /health_check.html
의 Request로 응답코드를 확인 하는 방식입니다. 그러나 최근 여러개의 서비스에서 HTTP Keep-Alive 를 사용중이고 이에 따라 배포시 의도하지 않은 문제점이 발생할 수 있어 이에 대한 회피에 대해 기술하도록 하겠습니다.
현재 카카오 배포 방식
카카오에서 몇몇 서비스의 서버개발자 분들께서 웹서버 배포, 서비스에서 제외시 L4장비의 GET /health_check.html
Request에 대해 404 응답코드를 내려주려고 health_check.html
파일을 리네임하거나 이동, 삭제 하는등의 방법을 사용중입니다. 쉽게 생각해서 L4 장비의 Request에 대해 404 응답코드를 내려줌으로써 VIP로 묶인 바인딩 서버리스트에서 제거 될것이라 생각하고 위와 같은 과정으로 서비스에서 제외 후 배포하는 경우가 많습니다.
현재 카카오 배포 방식의 문제점
위의 말씀드린 것처럼 health_check.html
파일에 대해서만 작업을 하고 배포를 진행하려고 할 경우에 서비스에서 제외 시킨 서버로 지속적으로 요청이 들어오고 트래픽이 빠지지 않는 경우가 있습니다. 이럴 경우 배포하고자 하는 서버에 지속적으로 사용자 트래픽이 인입되고 있는 상태라서 배포에 영향이 있거나 서버쪽의 문제로 생각을해서 살펴보게 되는 경우가 있습니다. 이는 L4 장비의 동작과 관련이 있는 것으로 L4 장비 동작 방법에 대해 살펴볼 필요가 있습니다.
L4 장비의 구성 및 동작
L3DSR 구성에서 L4장비는 클라이언트로부터 인입되는 요청에 대해서 해당 VIP에 대한 바인딩 서버리스트를 갖고 있고 IP헤더의 IP주소변경 후 리스트의 서버로 패킷을 던져주는 역할을 합니다.
이 때 L4장비에서는 해당 세션에 대한 세션테이블을 장비에 설정된 Idle session timeout (Session table aging time)시간동안 유지하게 됩니다. 이 시간을 카카오에서는 별도 요청이 없을 경우 default 로 600초로 설정해서 서비스하고 있습니다. (120초 ~ 3600초까지 변경 가능) 위와 같은 문제가 이 부분에서 발생을 하게 됩니다. 쉽게 그림으로 표현하면 아래 그림과 같습니다.
즉, 서버측에서 GET /health_check.html
에 대한 응답코드를 404로 내려준다 하더라도 L4장비에서는 설정된 600초라는 시간동안 Session Table을 유지하게 됩니다. 그리고 클라이언트로부터 오는 요청을 Session Table을 보고 서버로 포워딩해주게 됩니다. 이때문에 기존 Keep-Alive 상에서 동작했던 클라이언트는 health_check.html
파일을 제거했다고 하더라도 기존에 접속했던 서버로 요청이 계속 인입되게 되는 것입니다. 이때 기존 서버에 웹서버 프로세스가 유지되고 있는 상태라면 클라이언트-서버는 Keep-Alive 세션상에서 Request, Response가 가능합니다. 그러나 VIP가 설정된 lo:0 인터페이스를 Down 시킨 경우라면 클라이언트는 TCP Timeout 으로 “연결시간초과” 페이지를 보게 됩니다.
또한, L4장비에서는 서버상태의 HealthCheck을 대부분 설정된 10초 간격으로 하도록 되어 있는데 HealthCheck 을 한 바로 직후의 시간이라면 최초 10초정도의 Sleep time이 필요합니다. 그 10초 사이의 시간동안은 서비스에서 제외하고자 health_check.html 파일을 삭제했다 하더라도 L4장비에서는 바인딩리스트에 포함시키고 있기 때문에 클라이언트로부터의 Request가 인입될 수 있습니다.
Real Server Fail 판명 시기
- 최초 1번 응답이 없을 시에는, 해당 리얼 서버를 “Suspect” 상태로 처리.
- 그 다음번 응답이 없을 경우부터 Retry Count가 적용.
- 현재 설정 기준은 Keepalive Interval 이 10초, Retry Count가 1번.
- 매 10초 간격으로 HealthCheck을 시도하기 때문에 리얼서버 Fail를 감지하는데 11초 ~ 최대 20초가 걸릴 수 있음.
Real Server Bring-up 판명 시기
L4장비에서 Session Table이 유지됨으로 인해 발생하는 문제 해결
- L4장비에서는 위에 설명한 바와 같이 설정된 Idle Session Timeout 시간동안 Session Table이 유지되어 발생되는 문제점 해결을 위해 “Reset On Port Fail” 이라는 옵션을 사용할 수 있습니다.
- “Reset On port Fail” 옵션 설명 : L4는 기본적으로 Server application Down시 open된 session에 대해 Reset을 보내지 않음. 하지만 해당 옵션 적용 시 기존에 open된 session 대해 client 및 server side에 Reset 을 보내며 기존 session table 또한 삭제.
- “Reset On port Fail” 옵션을 적용하게 되면
health_check.html
파일삭제하거나 lo:0 인터페이스 Down을 했을 경우에, L4장비에서는 남아있던 Session Table을 Drop, 서버의 바인딩 리스트 제거, 클라이언트로 RST 패킷을 내려주는 등의 역할을 하게 됩니다. (클라이언트로 RST 패킷을 내려줌으로써 클라이언트는 기존서버와의 Session을 정리하고 새롭게 TCP 3웨이 핸드쉐이킹 후 타서버와 Session을 맺게 됩니다.) - 실제 벤더에서 제공하는 “Reset On Port Fail” 의 메뉴얼에는 서버와 클라이언트 양쪽으로 RST 패킷을 내려주는것으로 설명이 되어 있으나 실제 서버단에서의 패킷을 확인해보면 서버쪽으로의 RST 패킷은 발견되지 않습니다. 이로 인해 서버쪽에는 기존 Session이 좀비 Session으로 남아있습니다. (But 이미 해당 서버는 L4 장비의 바인딩 호스트 리스트에서 삭제가 된 상태이므로 해당 서버쪽으로의 Request 인입은 더이상 발생하지 않습니다.) 그로인해 서비스에서 제외하고자 하는 서버로의 지속적인 트래픽 인입을 방지 할 수 있습니다.
“Reset On Port Fail” 옵션의 한계
- “Reset On Port Fail” 옵션을 카카오에서 서비스하고 있는 모든 VIP에 대해서 설정을 하게 되면 위에서 언급된 것처럼 서비스제외 서버로의 트래픽 유입을 방지할 수는 있습니다. 하지만, 이 옵션을 적용 후 트래픽이 큰 서비스의 장애 발생시에 문제 발생의 소지가 있습니다. L4로 묶인 대량의 서버에서 장애가 발생하게 될 경우 L4에서는 클라이언트로부터의 모든 세션에 대해 RST을 내려주어야 하는데, 이때 L4의 장비의 리소스 부하로 인해 장애가 확대 될 수 있습니다. 물론 현재 L4를 기반으로 한 카카오 서비스는 여러대의 L4 장비에 분산이 되어 서비스 되고 있으나 대량서버의 장애시에는 L4장비에 부하가 갈 수 있고 그로인해 장애여파가 다른 서비스로까지 확산 될 수 있는 것입니다. 실제 세계 타사이트에서도 L4장비의 리소스 부하 문제로 곤란을 겪었던 케이스가 있고 이러한 문제점 때문에 “Reset On Port Fail” 옵션 적용 여부를 판단, 결정해야 합니다.
- 카카오에서는 대량 장애시의 L4 장비의 부하를 최소화하기 위해 “Reset On Port Fail” 옵션을 필요한 경우가 아니면 적용하지 않습니다.
결론
위와 같이 L4장비에 Session Table 이 남아있어 서비스에서 제외하고자 하는 서버군으로 지속적인 Request 인입을 방지하기 위해 서버 배포시 아래의 Flow에 따라 진행합니다.
L7 HealthCheck 방식을 사용하는 VIP
GET /health_check.html
404: 우선 health_check.html 파일을 리네임하거나 삭제, 이동등의 방법으로 L4에서 HealthCheck 시 404 응답코드를 내려줄 수 있도록 합니다.- L4장비에서 서비스에서 빼려는 서버군이 HealthCheck Fail 로 완벽하게 떨어질 수 있도록 최대 11초~20초의 Sleep Time이 필요합니다. => Session Table은 아직 남아 있어 기존 Session에 대해서는 서버쪽으로 Request 유입.
- 웹서버 프로세스 Stop: 서버에서 웹서버 프로세스를 Stop 으로 서버쪽 Session 정리. => 서버에서 프로세스를 Stop 해줄 경우 서버에서는 클라이언트로 FIN 패킷을 보내게 되고 L4장비에서는 기존 Session Table을 정리. 그에따라 기존 Session을 통해 서버로 Request가 유입되는것을 방지합니다.
- 배포 및 웹서버 프로세스 Start &
health_check.html
파일을 원복해서 서비스에 재투입 합니다. => 이때 L4장비에서는 GET/health_check.html
에 대한 응답코드를 200 OK 로 내려받게 되면 바로 바인딩을 시작하게 됩니다.
L4 HealthCheck 방식을 사용하는 VIP
- 웹서버 프로세스 Stop : L4 HealthCheck 의 경우는 웹 프로세스를 stop 해서 서버쪽 Session을 정리. => 서버는 클라이트로 FIN 패킷을 보내게 되고 L4장비에서는 기존 Session Table을 정리. 그리고 서버에서 프로세스를 내림으로써 VIP 바인딩 포트가 내려가게 되고 L4에서는 HealthCheck Fail 로 변경, 바인딩 리스트에서 빠지게 됩니다.
- 배포 및 웹서버 프로세스 Start : 웹서버 프로세스를 Start하게 되면 L4 HealthCheck Up 이 되면서 바인딩 리스트 포함. 서비스 투입. 위와 같은 순서로 서버 배포를 하게되면 “Reset On Port Fail” 옵션 적용 없이도 L4 장비 Session Table을 정리할 수 있기 때문에, 기존 서버로 트래픽이 유입되는것을 방지할 수 있습니다.