created at 2023-03-05
INDEX
- AWS RDS 그래프 지표 관찰
- Postgresql Locks
- Lock 관찰 쿼리
- Lock 타입 설명
- 타입에 따른 Conflict 발생 가능 여부
- Conflict 예시
- Conflict로 인해 블록된 쿼리 확인
- 그래서 AWS RDS로 확인한 지표에서 어떤 부분을 개선할 수 있을까? (feat. pgAdmin4)
기존에 저는 Postgres의 pg_stat_activity의 wait event 타입 별 통계를 일일이 찍어서 관찰했었는데요, AWS RDS를 사용하면 그래프화 하여 손쉽게 관찰할 수 있습니다. 그래서 AWS가 제공해주는 DB 매니지먼트 툴을 사용하고자 auth-DB만 Local에서 AWS RDS(Postgres)로 이전하였습니다.
또한 자동으로 백업 스냅샷까지 툴로 제공해주니, 정말 너무 편리했습니다ㅜㅜ… 진작에 AWS RDS 를 써볼껄 그랬네요.
1. AWS RDS 그래프 지표 관찰
- Splice 지표 설명
- LWLock:WALInsert : Checkpointer 프로세스는 WAL 버퍼에 WAL 레코드를 저장합니다. 이 때 걸리는 Lock 입니다.
- LWLock:WALWrite : WAL Writer 는 WAL 버퍼가 가득 찼을 때, WAL 버퍼를 WAL 파일에 옮깁니다. 이 떄 걸리는 Lock 입니다.
LWLock 은 SharedMemory 에 접근할 때 걸리는 Lock입니다. WAL은 변경기록입니다. tx_log입니다.
- IO:WALSync : WAL 파일을 Archive 파일에 옮기는 과정입니다.
- Client:ClientWrite : 클라이언트가 힘들 때 ClientWrite 이벤트가 트리거됩니다. 즉, DB 클러스터는 준비가 되어있지만, 클라이언트가 제 때 받지 못할 때 이 이벤트가 발생하게 됩니다.
- 발생이유
- PostgreSQL DB 클러스터와 클라이언트 간의 네트워크 처리량이 감소하면 이 이벤트가 발생할 수 있습니다.
- 클라이언트에 대한 CPU 압력 및 네트워크 포화 상태시에도 이 이벤트가 발생할 수 있습니다
- 발생이유
더 자세한 설명들은 https://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Reference.Waitevents.html를 참고하시면 됩니다.
2. Postgresql Locks
2-1. Lock 관찰 쿼리
pg_catalog 는 정말 수많은 메타데이터 정보를 여러가지 view로 보여줍니다. 그 중 저는 pg 모니터링의 pg_stat_activity와, pg_locks을 아래와 같이 pid로 join해서 현재 실행중인 트랜젝션의 쿼리/lock 정보들을 확인 할 거에요.
SELECT
locktype,
relation::regclass,
mode,
transactionid tid,
virtualtransaction AS vtid,
l.pid,
query,
granted
FROM
pg_catalog.pg_locks l
LEFT JOIN pg_catalog.pg_stat_activity db ON db.pid = l.pid
WHERE
NOT l.pid = pg_backend_pid();
2-2. 타입 설명
- Row ExclusiveLock : UPDATE, DELETE, INSERT 시에 해당 테이블와 pkey에 Lock을 걸어놓습니다.
- ExclusiveLock : 모든 트랜젝션은 자신의 id에 대해 ExclusiveLock을 걸어놓습니다.
- ShareLock : 동시 데이터를 변경할 때 생기는 문제를 보호하기 위하여 먼저 Lock을 잡은 Transactionid에 공유를 요청하는 Lock입니다.
2-3. 타입에 따른 Conflict 발생 가능 여부
from https://postgrespro.com/blog/pgsql/5967999
2-4. Conflict 예시
유니크한 user_id를 가지는 테이블에 동일 user_id=’A1’ insert 문 두 개를 동시에 날려볼거에요. 그러면 아래와 같이 PID:21789
트랜젝션과 PID:21516
트랜젝션은 Conflict 가 발생합니다. 순서는 다음과 같습니다.
PID:21789
는 user_id=’A1’ 인덱스에 Row ExclusiveLock 을 먼저 걸어놓습니다. 그리고 자신의 TXID에 ExclusiveLock을 걸어놓습니다.PID:21516
는 user_id=’A1’에 Row ExclusiveLock 을 마찬가지로 걸어놓습니다. 해당 인덱스가 사용되는 트랜젝션에 공유 요청을 신청해야합니다.PID:21516
는 ShareLock으로PID:21789
트랜젝션 공유를 요청하지만 ShareLock과 트랜젝션에 걸린 ExclusiveLock은 위의 표와 같이 Conflict가 발생합니다. 따라서 권한획득에 실패하고 block됩니다(granted=False
).
2-5. Conflict로 인해 블록된 쿼리 확인
select pid,
usename,
pg_blocking_pids(pid) as blocked_by,
query as blocked_query
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0;
3. 그래서 AWS RDS로 확인한 지표에서 어떤 부분을 개선할 수 있을까? + pgAdmin4
자세히 보다보니, 아래처럼 쿼리 이외에 DB connection 이 20으로 고정할당되어있는것을 확인할 수 있었습니다.
미쳐 생각하지 못했던 부분이였어요ㅜㅜ. 일단 현재 인증서버에 100의 스레드가 할당되어 있기때문에, 각 스레드 별로 하나의 DB커넥션을 처리할 수 있습니다. DB 이외, Kafka에 메세지를 전달하는 스레드또한 필요하기때문에 DB의 max conenction을 적당히 70으로 맞추었습니다(적절한 개수는 40~50이라고 하네요).
그리고 AWS RDS에 데이터베이스 파라미터 군을 확인하면 최대 800만개의 connection을 생성할 수 있다고 합니다.
t3micro 인스턴스에서 가능한 RDS max conenction
SHOW max_connections;
제가 사용하는 현재의 t3micro 인스턴스에서는 83개 까지만 가질 수 있네요! 이 중 여러 실험에 필요한 13개를 다른 커넥션으로 빼고 나머지 70개를 사용할 예정입니다.
- 일단 DB Idle conenction이 올라갔죠!
test-multiple-http-request | Request url: http://127.0.0.1:8060/auth/user
test-multiple-http-request | The number of HTTP Requests: 10000
test-multiple-http-request | The number of threads: 1000
test-multiple-http-request | Proceeding! Please wait until getting all the responses
test-multiple-http-request | Elapsed Time: 26.283325464 <- 51.3초에서 200% 개선되었어요!
test-multiple-http-request | Response status code: 200 , How many?: 10000
test-multiple-http-request exited with code 0
- RDS 이전 후, 10K RTT에 51.3초가 걸렸지만 200% 향상되서 26.2초로 줄었습니다!
다시 RDS 지표를 관찰해볼까요?
- 활성 세션 수는 다소 올라갔습니다.
- 높은 LWLock:WALInsert. 이제 이 부분을 개선해야겠죠?
추가적으로 CPU 사용률은 크게 변하지 않았습니다. 아마 Postgres 함수와 Select/Join 와 같은 CPU 사용률을 높이는 쿼리가 없었기 때문이겠죠?
reference
- https://www.educba.com/postgresql-wal/
- https://postgrespro.com/blog/pgsql/5967951
- Postgres 정보 : https://blog.ex-em.com/1657
- https://www.postgresql.org/docs/current/explicit-locking.html