오늘 일하는 곳에서 갑자기 DB Connection
이 안 잡히는 현상이 발생했습니다.
에러 로그를 보니 아래와 같은 로그가 남아있더군요.
org.postgresql.util.PSQLException: FATAL: sorry, too many clients already.
로그에 쓰인 말 그대로,
PostgreSQL DBMS
의 최대 Connection
의 수에 도달했는데, 또 다시 Connection 이
요청되서 에러가 난 겁니다. 대체적으로 이런 상황을 해결하는 방법은 크게 2가지입니다.
Max Connection
의 수의 늘린다.Connection/Session
을 강제로 끊어버린다.자, 여러분들은 어떤 방법을 선택하시겠습니까?
아마 바로 판단하기 힘들겁니다. 최종적인 판단을 위해서는 일단
현재 Connection Pool
이 꽉 찬 이유가 뭔지, 즉 현재 상황에 대한 파악이 먼접니다.
먼저 Connection Pool
이 꽉 차면 아래 2개의 System table
을 통해서
다음의 내용을 파악해야 합니다.
pg_settings
: 현재 최대 연결 가능한 세션 수는 몇인가? pg_stat_activity
: 현재 어떤 세션들이 Connection 을 물고 있는가?위처럼 먼저 상황을 파악하고 DB Connection
을 강제로 죽이든,
최대세션을 늘리든 결정해야 합니다.
이 글에서는 DB Connection
을 죽이는 방법을 기록합니다.
최대세션을 늘리는 방법은 이 링크를 참조하시기 바랍니다.
select * from pg_settings
where name = 'max_connections';
SELECT * FROM pg_stat_activity;
pg_stat_activity
를 조회하면 위그림 처럼 현재 어떤 client ip
에서 세션을
사용 중인지 확인을 할 수 있습니다. 추가적으로 pg_stat_activity.query
컬럼을
통해서 각 세션별로 어떤 query
를 수행했는지도 확인 가능합니다. (아래 그림 참고)
이런 정보가 있으면 좀 더 상황 파악하기가 좋겠죠?
어느정도 상황이 파악되면 DB 연결을 끊고 싶은 Session 과 실제 연결된
DB Server Process pid
를 지정합니다.
pg_stat_activity.pid
컬럼을 참조하면 됩니다. (아래 그림 참고)
Lock 또는 Blocking 을 유발하는 PID 를 정확히 뽑아내려면 아래 쿼리를 돌리고...
select pid, usename, application_name, pg_blocking_pids(pid) as blocked_by, query as blocked_query, backend_start, query_start, backend_type from pg_stat_activity where cardinality(pg_blocking_pids(pid)) > 0;
blocked_by
에 나오는 숫자값으로 blocking 을 유도하는 pid 를 뽑아낼 수 있습니다.
위에서 선택한 pid 를 아래 쿼리에 넣어서 돌리면 강제로 해당
connection 을 끊을 수 있습니다.
SELECT
pg_cancel_backend(pid), -- 해당 PID만 중지
pg_terminate_backend(pid) -- PID와 연계된 모든 상위 쿼리 프로세스도 종료
FROM pg_stat_activity
where
pid <> pg_backend_pid() -- (필수) 현재 이 쿼리르 돌리는 session 의 pid 는 끊지 않음
and backend_type = 'client backend' -- (필수) 클라이언트 전용 session 만 끊기, DB 내부 사용 세션은 X
-- and pid in (1826,5123,5132,61112) -- (선택) 특정 session 만 끊기
-- and datname = 'fantastic_db'; -- (선택) 특정 DB 접속 session 만 끊기