𝗣𝗼𝘀𝘁𝗴𝗿𝗲𝗦𝗤𝗟 𝗔𝗱𝘃𝗶𝘀𝗼𝗿𝘆 𝗟𝗼𝗰𝗸𝘀 𝗳𝗼𝗿 𝗗𝗶𝘀𝘁𝗿𝗶𝗯𝘂𝘁𝗲𝗱 𝗝𝗼𝗯 𝗦𝗰𝗵𝗲𝗱𝘂𝗹𝗶𝗻𝗴
작업 스케줄링만을 위해 스택에 Redis나 SQS를 추가하지 마세요.
대신 PostgreSQL advisory lock을 사용할 수 있습니다. 이 방식은 새로운 인프라 구축의 필요성을 없애줍니다.
제 테스트 결과, 이 설정은 단일 데이터베이스 인스턴스에서 분당 10,000개의 작업을 처리할 수 있었습니다. 워커가 이미 데이터베이스 연결을 보유하고 있기 때문에 추가적인 네트워크 홉(network hop)을 피할 수 있어, 지연 시간(latency) 측면에서 Redis보다 나은 경우가 많습니다.
구현 방법:
• 작업 점유(claiming)를 위해 pg_try_advisory_xact_lock을 사용하세요.
• 행 경합(row contention)을 처리하기 위해 FOR UPDATE SKIP LOCKED를 사용하세요.
• 락 누수(lock leaks)를 방지하기 위해 트랜잭션 변형(transactional variant)을 사용하세요.
트랜잭션 락이 중요한 이유:
트랜잭션 락은 트랜잭션이 커밋되거나 롤백될 때 자동으로 해제됩니다. 이는 애플리케이션이 충돌하더라도 고아 락(orphaned locks)이 발생하는 것을 방지합니다. 또한 트랜잭션 모드의 PgBouncer와도 안전하게 작동합니다.
PgBouncer를 사용한다면 세션 락(session locks)은 피하세요. PgBouncer는 트랜잭션 사이에 연결을 재할당합니다. 이는 세션 수준의 락을 깨뜨리고 조용한 실패(silent failures)를 유발합니다.
세션 락이 필요하다면 워커를 위한 별도의 커넥션 풀을 만드세요. 웹 트래픽과 작업 워커 트래픽을 동일한 풀에 섞지 마세요.
키를 이용한 스케일링:
Advisory lock은 bigint 또는 두 개의 정수를 사용합니다. 두 개의 정수를 사용하면 자연스러운 네임스페이싱(namespacing)이 가능합니다. 텍스트 키를 bigint로 해싱하는 경우 충돌(collision)에 주의하세요. 충돌은 고유 락 ID가 100,000개에 도달할 때까지는 낮게 유지됩니다. 그 이상이 되면 안전을 위해 두 개의 정수 형식을 사용하세요.
트레이드오프(Tradeoff):
• Advisory lock은 단순함과 낮은 운영 비용 측면에서 유리합니다. • Redis는 순수 처리량(throughput)과 수평적 확장성(horizontal scaling) 측면에서 유리합니다.
대부분의 팀은 분당 10,000개 이상의 작업이 필요하지 않습니다. 이 한도 미만이라면 PostgreSQL을 고수하세요. 아키텍처를 깔끔하게 유지하고 비용을 낮게 유지할 수 있습니다.
출처: https://dev.to/software_mvp-factory/postgresql-advisory-locks-for-distributed-job-scheduling-15kp