-
Notifications
You must be signed in to change notification settings - Fork 3
Pgbouncer
#docker-compose.yml
pgbouncer:
image: edoburu/pgbouncer
container_name: pgbouncer
depends_on:
- oj-postgres
environment:
- DB_USER=onlinejudge
- DB_PASSWORD=onlinejudge
- DB_HOST=oj-postgres
- DB_NAME=onlinejudge
- ADMIN_USERS=onlinejudge
- DB_PORT=5432
- LISTEN_PORT=6543
- POOL_MODE=transaction
- SERVER_CHECK_DELAY=3000
- MAX_CLIENT_CONN=3000
- MIN_POOL_SIZE=100
- DEFAULT_POOL_SIZE=100
Pgbouncer란?
직접적으로 Postgres DB에 접속하는 것을 막고, request와 DB 사이에서 connection pool을 관리하며 pgbouncer를 통해서만 DB에 접속하게 해줍니다.
=> 따라서 DB에 과도한 connection이 생성돼서 DB 터지는 일을 방지해줍니다.
기존 oj-postgres 컨테이너에서는 볼 수 없었던 파라미터들에 대해서만 간략하게 설명하겠습니다.
ADMIN_USERS: pgbouncer 관련 각종 자료(통계)를 볼 수 있는 계정입니다. psql 명령어로 ADMIN_USER로 등록되어 있는 계정으로 접속한 후에, SHOW 명령어를 통해서 각종 통계자료를 볼 수 있습니다.
psql 'postgres://onlinejudge:onlinejudge@localhost/pgbouncer' -p 6543
SHOW STATS
STATS 외에도 SERVERS, CLIENTS 등의 파라미터도 있으며 https://www.pgbouncer.org/usage.html에서 확인 가능합니다.
POOL_MODE: default가 session이지만 transaction을 권장한다고 해서 transaction으로 사용했습니다. 대부분의 경우에서 transaction으로 둔다고 합니다.
SERVER_CHECK_DELAY: (단위: 초) 지정한 시간 이후에 SV_IDLE이 SV_USED로 바뀝니다.
cf. SV_IDLE, USED는 pool의 state를 나타내는 것. SV_IDLE은 쿼리가 다 끝난 상태. 이후 SERVER_CHECK_DELAY 만큼의 시간이 흐르면 SV_USED로 바뀜. Connection 요청이 들어오면 SV_IDLE먼저 사용. 즉 SV_IDLE이 충분하면 SV_USED는 거의 사용할 일이 없음. 따라서 이 파라미터를 통해서 적절히 조절. 0으로 설정하면 계속 SV_IDLE 상태로 되어서 효율적이지만 에러가 발생할 수 있는 위험. 그래서 일단은 충분히 긴 시간(10분)으로 설정했습니다.
MIN_POOL_SIZE: SV_IDLE + SV_USED의 값으로 DEFAULT POOL SIZE 내에서 미리 확보하는 pool의 수. 이 개수 보다 pool 개수가 적어지면 추가적으로 형성합니다. DEFAULT_POOL_SIZE 보다는 작아야 해서 100으로 설정했습니다(최대의 pool 개수를 유지).
미리 확보하는 pool의 개수(= 미리 DB와 커넥션을 맺어놓은 개수)이므로 이 값이 0이면 클라이언트 측에서 요청이 올 때마다 connection을 생성하는 것이므로 결국 실질적인 connection pooling이 작동 안하게 되는 것입니다.
DEFAULT_POOL_SIZE: max_connection / DB개수 로 설정하거나 코어 수로 설정하는데 전자의 방식을 따랐습니다. DEFAULT_POOL_SIZE 값 변화에 대한 성능 분석을 한 통계가 있던데 큰 차이가 없었습니다. max_connection이 100이고 사용하는 DB는 1개이기 때문에 100으로 설정했습니다.
MAX_CLIENT_CONN: 대기하는 client를 포함하여 DB와 최대로 연결할 수 있는 client의 수. 3000으로 설정을 했습니다. 현재 설정 값에 따르면, DEFAULT_POOL_SIZE 값이 100이므로 최대 100명의 client가 DB와 연결을 유지할 수 있고 2900명이 connection을 위해 대기할 수 있습니다.
추가적으로, utils/throttling.py도 수정을 했습니다.
한 사람이 과도하게 request를 보내는 것을 방지하기 위해 fill_rate를 0.2로 늘려줬습니다. fill_rate은 쉽게 말해서 1초당 처리하는 쿼리의 개수입니다. 0.2로 설정을 했으므로 5초당 쿼리를 하나 처리할 수 있습니다. 이는 한 유저가 여러 번 이어서 제출하는 것을 방지해줍니다.(제출하고 5초 내로 재제출 시도시 제출이 되지 않음)
백준에서도 5초를 기준으로 둬서 5초로 설정을 해놨습니다.
관련이슈:
- 초반에 pool을 형성하는 오버헤드 등으로 인하여 response time이 비교적 높습니다. 이 설정값으로 돌렸을 때 서버에서는 500명을 대상으로는 문제가 없었습니다.
하지만 로컬에서는 같은 설정값으로 해도 사양 문제로 인하여 response time이 60초가 넘어가면서 커넥션이 끊겨 submission이 실패하는 에러가 발생했습니다.
따라서 추후에 전교생 대상으로 서비스를 확장하면서 다른 파라미터를 수정해서 생성해야하는 pool size가 커질 때 이 점을 고려해야할 것 같습니다.
참고자료:
https://www.compose.com/articles/how-to-pool-postgresql-connections-with-pgbouncer/
https://medium.com/deliverytechkorea/tagged/pgbouncer