ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • PostgreSQL 데드락 발생시키기
    CS/데이터베이스 2023. 8. 23. 00:01

    데드락이란?

    Dead Lock 다른 말로는 교착상태를 뜻합니다.

    동일한 자원을 공유하고 있는 두 개 이상의 작업이 자신들의 작업을 수행하기 위해 사용해야 하는 리소스를 서로 미리 선점함으로써 상대방이 자원에 접근하지 못하도록 막습니다.

     

    컴퓨터 사이언스에서 많이 나오는 용어로 데이터베이스에서는 여러 개의 트랜잭션이 실행을 하지 못하고 서로 무한정 기다리는 상태를 말합니다.

     

    조금 더 학문적으로 보면 데드락이 발생하기 위한 조건 4가지가 있습니다. (동시에 성립해야 함)

    • 상호 배제 - 자원은 한 번에 하나씩만 사용
    • 점유 대기 - 자원을 점유하기 위해 대기하는 시간이 존재
    • 비선점 - 자원을 강제로 빼앗을 수 없음
    • 순환대기 - P0은 P1가 점유한 자원을 대기하고, P1은 P0가 점유한 자원을 대기

     

    데이터베이스의 Lock Mode

    데이터베이스에서는 Shared Lock과 Exclusive Lock이 존재합니다.

     

    Shared Lock : 내가 보고 있는 데이터는 다른 사용자가 볼 수는 있지만 변경할 순 없다.

    유사하게 PostgreSQL에서는 AccessShareLock이라고 부릅니다.

     

    Exclusive Lock : 내가 점유한 자원은 누구도 읽거나 변경할 수 없다.

    유사하게 PostgreSQL에서는 RowExclusiveLock이라고 부릅니다.

     

    Update에서 발생하는 DeadLock 발생시켜 보기

    -- Transaction 1
    BEGIN;
    UPDATE customer SET id=2 WHERE id = 1
    
    
    -- Transaction 2
    BEGIN;
    UPDATE customer SET id=1 WHERE id = 2
    
    -- Transaction 1
    UPDATE customer SET id=1 WHERE id = 2
    
    -- Transaction 2
    UPDATE customer SET id=2 WHERE id = 1
    
    -- Transaction 1
    COMMIT;
    -- Transaction 2
    COMMIT;

    트랜잭션 범위에서 update query에 적용되는 영향도가 행 하나가 아닌 경우에는 DeadLock이 발생할 수 있습니다.

     

    발생한 예외

    ERROR:  deadlock detected
    DETAIL:  Process 59 waits for ShareLock on transaction 739; blocked by process 43.
    Process 43 waits for ShareLock on transaction 740; blocked by process 59.
    HINT:  See server log for query details.
    CONTEXT:  while updating tuple (0,3) in relation "users"

    이런 경우 Exclusive Lock과 Exclusive Lock이 충돌되어 deadLock이 발생했습니다.

     

     

    비슷하게 다음과 같은 경우에도 dead lock이 발생할 수 있습니다.

    -- Transaction 1
    UPDATE customer SET ... WHERE id IN (1, 2)
    
    -- Transaction 2
    UPDATE customer SET ... WHERE id IN (1, 2)

     

     

     

    데드락 분석을 위해 탐지시간 지연

    postgresdb=# show deadlock_timeout;
     deadlock_timeout 
    ------------------
     1s
    (1 row)
    
    
    -- Set the deadlock_timeout to 10 seconds (10000 milliseconds)
    ALTER SYSTEM SET deadlock_timeout = '10s';
    
    
    SELECT pg_reload_conf();
    
    SHOW deadlock_timeout;
    
     deadlock_timeout 
    ------------------
     10s
    (1 row)

    deadlock_timeout의 기본값을 1초입니다.

    deadlock_tiemout이란 교착 상태가 있는지 확인하기 전 잠금을 기다리는 시간입니다.

    10초로 증가시켜 보겠습니다.

     

     

    다음 쿼리를 통해 lock 정보를 확인할 수 있습니다.

    select locktype, relation::regclass, mode, transactionid tid, pid, granted 
    from pg_catalog.pg_locks 
    where not pid=pg_backend_pid();

     

     

    -- T1
    BEGIN; UPDATE users SET name = '1' WHERE name = '2';
    -- T2
    BEGIN; UPDATE users SET name = '2' WHERE name = '1';

     

    lock 정보

       locktype    | relation |       mode       | tid | pid | granted 
    ---------------+----------+------------------+-----+-----+---------
     relation      | users    | RowExclusiveLock |     |  59 | t
     virtualxid    |          | ExclusiveLock    |     |  59 | t
     relation      | users    | RowExclusiveLock |     | 196 | t
     virtualxid    |          | ExclusiveLock    |     | 196 | t
     transactionid |          | ExclusiveLock    | 749 |  59 | t
     transactionid |          | ExclusiveLock    | 748 | 196 | t

    두 트랜잭션 모두 update가 발생했기 때문에 transactionid를 획득하였습니다.

     

    lock 정보

    where not pid=pg_backend_pid();
       locktype    | relation |       mode       | tid | pid | granted 
    ---------------+----------+------------------+-----+-----+---------
     relation      | users    | RowExclusiveLock |     |  59 | t
     virtualxid    |          | ExclusiveLock    |     |  59 | t
     relation      | users    | RowExclusiveLock |     | 196 | t
     virtualxid    |          | ExclusiveLock    |     | 196 | t
     tuple         | users    | ExclusiveLock    |     |  59 | t
     transactionid |          | ExclusiveLock    | 749 |  59 | t
     transactionid |          | ExclusiveLock    | 748 | 196 | t
     tuple         | users    | ExclusiveLock    |     | 196 | t
     transactionid |          | ShareLock        | 749 | 196 | f
     transactionid |          | ShareLock        | 748 |  59 | f

    이후 T1에서 name은 1인 쿼리를 업데이트하려고 하고, T2에서는 name 2인 쿼리를 업데이트하려고 하면 sharedLock이 추가되고 granted는 f로 대기가 발생합니다.

     

    10초 이후엔 데드락이 감지되었고 모든 lock정보가 사라졌습니다.

     

    공존할 수 있는 Lock Mode

     

    추가로..

    AWS Aurora 환경에서 성능 개선 도우미를 활용하면 Lock 쿼리를 쉽게 파악할 수 있습니다.

    갓항로님..

    https://jojoldu.tistory.com/591

     

    (AWS Aurora) PostgreSQL에서 Lock 쿼리 확인하고 원인 종료하기

    RDBMS를 사용하다보면 Lock 쿼리를 종종 만나게 되는데요. (AWS Aurora) PostgreSQL에서는 어떻게 Lock 쿼리를 모니터링하고, 처리하는지 알아보겠습니다. 기존의 온프레미스 환경에 익숙하시다면 그 방식

    jojoldu.tistory.com

     

     

     

    참고자료

    https://medium.com/humanscape-tech/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-deadlock-%ED%95%B4%EA%B2%B0-%ED%9B%84%EA%B8%B0-ad45eb6f6ad8

    https://mysqldba.tistory.com/54

    https://stackoverflow.com/questions/10245560/deadlocks-in-postgresql-when-running-update/10246052#10246052

    https://chrisjune-13837.medium.com/db-postgresql-lock-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0-57d37ebe057

    https://pankajconnect.medium.com/modify-deadlock-timeout-parameters-in-postgresql-2d5fb1801f99

     

    'CS > 데이터베이스' 카테고리의 다른 글

    Deferred Join이란? - 실습편  (0) 2023.11.01
    Deferred Join이란? - 이론편  (0) 2023.10.28
    Hard Delete와 Soft Delete  (2) 2023.07.17
    캐시 전략  (0) 2023.07.10
    Redis Intellij DataGrip 적용  (0) 2023.07.02

    댓글

Designed by Tistory.