DB Connection Storm
1. DB Connection
일반적으로 DB 서버와 애플리케이션 서버는 물리적으로 분리해 운영한다. 그래서 네트워크 통신을 해야하고 서로 Connection을 맺어야 한다.
2. DB Connection Pool
TCP 기반 네트워크 통신으로 Connection을 맺어야 하는데 연결을 맺을때는 3 way handshake, 연결을 끊을 때는 4 way handshake 가 필요하다. 즉 연결을 맺고 끊는데 시간이 걸린다. 사용자 요청마다 Connection 을 맺고 끊는 작업을 하게 되면 비효율적이다.
그래서 DB Connection Pool 을 이용해 애플리케이션 서버가 배포될 때 미리 DB 서버와 통신할 때 사용할 Connection 들을 만들어 놓는다. 그리고 사용자 요청이 오면 Pool 에 있는 Connection 을 가져다 쓰고 다 쓰면 다시 Pool 에 반납하는 프로세스다.
3. Failover
Failover 는 장애가 발생할 경우, 자동으로 미리 준비한 시스템으로 전환하는 프로세스다. Failover 목표는 장애시간을 최소화하고 서비스 가용성을 보장하는 것이다. 이 글에서 설명하는 DB 서버 뿐만아니라 애플리케이션 서버, IDC 화재 등 모든 장애 상황을 빠르게 해결하기 위해 준비해놓는 프로세스라고 보면 된다. DR(Disaster Recovery) 시스템을 구축하면 Failover 가 가능해진다.
만약 아래 그림처럼 갑자기 DB 서버가 죽으면
이중화 조치로 미리 준비된 2번 DB 로 바로 전환해 빠른 시간내에 정상화 시킬 수 있다.
물론 이게 가능하기 위해선 크게 두가지 작업이 선행되야 한다. 먼저 애플리케이션 서버는 DB 연결에 필요한 host 를 1번서버나 2번서버로 고정시키면 장애 발생 시 자동으로 전환될 수 없다. 애플리케이션 코드를 수정하고 서버를 재배포해야 하기 때문이다. 그래서 애플리케이션 서버에 단일 endpoint 를 제공하고 동적으로(dynamic) 전환할 수 있게 구축해야 한다. 두번째는 2번 DB로 전환했을 때 문제없이 동작하기 위해선 data 들이 똑같이 있어야 한다. 즉 평상시에도 실시간 복제가 계속 이뤄져야 한다.
4. DB Connection Storm
하지만 이렇게 DB layer 에서 DR(Disaster Recovery) 시스템을 구축해도 Failover 에 실패할 수 있다.
DB Connection Storm 은 여러 Client가 동시에 DB 연결을 시도하여 과도한 수의 connection 이 설정되고 그에 따라 리소스 고갈, 성능 저하 또는 DB 시스템의 전면 장애로 이어지는 상황을 말한다.
애플리케이션 서버들은 세션을 더 생성하려고 하는데 DB CPU 는 요청을 즉시 처리할 수가 없는 경합 상태다. 이 문제는 짧은 시간에 너무 많은 Connection 이 생성되는 경우에 발생할 수 있다.
Connection 관리는 DB 입장에서도 가장 큰 비용이다. 과도한 Connection 요청으로 DB Max process 가 초과되면 DBA 가 로그인도 못해 모니터링도 어려울 수 있다.
애플리케이션 서버 환경이 기존 PM 이나 VM 이 아니라 K8S 기반으로 바뀌면서 확실히 DB Connection 수가 많이 증가했다. 또한 서비스 안정성 확보를 위해 이중화 작업을 하면서 2배로 늘어날수밖에 없었다.
5. 해결방법
명확하게 해결방법이 나오긴 어렵다. 바뀐 설정에 대해 문제가 없다는것을 증명해야 하는데 테스트 환경에서는 실제 트래픽만큼의 부하를 주기 어렵기 때문이다. 몇몇 API 를 선정해 부하 테스트를 줄 수 있는게 전부지만 운영 환경과 동일하게 검증됐다고 보기 어렵다.
디데이 정하고 실제 운영 환경에서 테스트하는 카오스 엔지니어링 기법도 있지만, 테스트하다 잘 안되면 실사용자들이 피해보는거라 리스크가 크다. 경영진이 허락 해줄지 모르겠다.
일단 testonborrow 옵션을 false 로 설정했다.
testOnBorrow true 면 Connection Pool 에서 Connection 을 얻어올 때 실제 DB 서버로 valid query를 보내 테스트한다.
testOnBorrow true 로 한 이유가, DB Failover 되었을때 애플리케이션 서버에서 2번서버로 잘 접속되도록하기 위한 것인데, 너무 많은 Connection 이 한번에 몰리는게 문제가 되니 정책을 바꿨다.
testOnBorrow 옵션을 false 로 하면 사용자는 실패를 경험하겠지만, 실패처리되는 시간만큼 DB 로 Connection 이 몰리는 것을 낮출 수 있다. Connection Storm 으로 전면장애 되는것 보다는 낫다는 판단이다.