Skip to main content Link Menu Expand (external link) Document Search Copy Copied

created at 2023-03-05

INDEX

  1. AWS RDS 그래프 지표 관찰
  2. Postgresql Locks
    1. Lock 관찰 쿼리
    2. Lock 타입 설명
    3. 타입에 따른 Conflict 발생 가능 여부
    4. Conflict 예시
    5. Conflict로 인해 블록된 쿼리 확인
  3. 그래서 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 그래프 지표 관찰

img img img

  • 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();

img

2-2. 타입 설명

  • Row ExclusiveLock : UPDATE, DELETE, INSERT 시에 해당 테이블와 pkey에 Lock을 걸어놓습니다.
  • ExclusiveLock : 모든 트랜젝션은 자신의 id에 대해 ExclusiveLock을 걸어놓습니다.
  • ShareLock : 동시 데이터를 변경할 때 생기는 문제를 보호하기 위하여 먼저 Lock을 잡은 Transactionid에 공유를 요청하는 Lock입니다.

2-3. 타입에 따른 Conflict 발생 가능 여부

img from https://postgrespro.com/blog/pgsql/5967999

2-4. Conflict 예시

유니크한 user_id를 가지는 테이블에 동일 user_id=’A1’ insert 문 두 개를 동시에 날려볼거에요. 그러면 아래와 같이 PID:21789 트랜젝션과 PID:21516 트랜젝션은 Conflict 가 발생합니다. 순서는 다음과 같습니다.

  1. PID:21789는 user_id=’A1’ 인덱스에 Row ExclusiveLock 을 먼저 걸어놓습니다. 그리고 자신의 TXID에 ExclusiveLock을 걸어놓습니다.
  2. PID:21516는 user_id=’A1’에 Row ExclusiveLock 을 마찬가지로 걸어놓습니다. 해당 인덱스가 사용되는 트랜젝션에 공유 요청을 신청해야합니다.
  3. PID:21516는 ShareLock으로 PID:21789 트랜젝션 공유를 요청하지만 ShareLock과 트랜젝션에 걸린 ExclusiveLock은 위의 표와 같이 Conflict가 발생합니다. 따라서 권한획득에 실패하고 block됩니다(granted=False).

img

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;

img

3. 그래서 AWS RDS로 확인한 지표에서 어떤 부분을 개선할 수 있을까? + pgAdmin4

자세히 보다보니, 아래처럼 쿼리 이외에 DB connection 이 20으로 고정할당되어있는것을 확인할 수 있었습니다.

img

미쳐 생각하지 못했던 부분이였어요ㅜㅜ. 일단 현재 인증서버에 100의 스레드가 할당되어 있기때문에, 각 스레드 별로 하나의 DB커넥션을 처리할 수 있습니다. DB 이외, Kafka에 메세지를 전달하는 스레드또한 필요하기때문에 DB의 max conenction을 적당히 70으로 맞추었습니다(적절한 개수는 40~50이라고 하네요).

그리고 AWS RDS에 데이터베이스 파라미터 군을 확인하면 최대 800만개의 connection을 생성할 수 있다고 합니다.

img

  • t3micro 인스턴스에서 가능한 RDS max conenction

      SHOW max_connections;
    

    img 제가 사용하는 현재의 t3micro 인스턴스에서는 83개 까지만 가질 수 있네요! 이 중 여러 실험에 필요한 13개를 다른 커넥션으로 빼고 나머지 70개를 사용할 예정입니다.

img

  • 일단 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 지표를 관찰해볼까요?

img img

  • 활성 세션 수는 다소 올라갔습니다.
  • 높은 LWLock:WALInsert. 이제 이 부분을 개선해야겠죠?

추가적으로 CPU 사용률은 크게 변하지 않았습니다. 아마 Postgres 함수와 Select/Join 와 같은 CPU 사용률을 높이는 쿼리가 없었기 때문이겠죠? img

reference