Ruby on Rails에서 데이터베이스 Advisory Locks 비활성화하기

문제: PgBouncer 트랜젝션 모드와 레일스 마이그레이션 충돌

루비 온 레일스Ruby on Rails에서는 마이그레이션 작업을 실행할 때 기본적으로 데이터베이스의 Advisory Locks 기능을 사용하고 있습니다.* 이는 마이그레이션이 동시에 일어나는 것을 방지하고 위한 목적으로 사용되며, 잠금이 되어있는 상태에서 마이그레이션을 실행할 경우 ActiveRecord::ConcurrentMigrationError가 발생합니다.

* PostgreSQL의 Advisory Locks 기능에 대한 더 자세한 정보는 PostgreSQL의 문서를 참고해주세요: PostgreSQL: Documentation: 11: 13.3. Explicit Locking - Advisory Locks

원래는 마이그레이션의 동시 실행을 방지하기 위한 목적으로 사용됩니다만, PostgreSQL의 커넥션 풀링 용도로 PgBouncer의 트랜젝션 모드를 사용하는 경우 마찬가지로 ActiveRecord::ConcurrentMigrationError이 발생할 수 있습니다. 이는 PgBouncer 내부 로직에서 Advisory Locks 기능이 사용되고 있기 때문이며, 이 문제는 레일스 쪽에도 이미 알려져있습니다(#31190). 이 문제를 해결하기 위해서는 마이그레이션 이전에 Advisory Locks을 해제해주거나, 마이그레이션에서 사용되는 잠금을 비활성화해야합니다. 잠금을 해제하려면 pg_advisory_unlock와 같은 PostgreSQL의 함수를 사용하면 됩니다만, 커넥션 풀 관리를 위해 PgBouncer를 사용하는 경우 내부 로직에서 Advisory Locks이 사용되기 때문에 타이밍 이슈나 다른 문제가 발생할 수 있습니다.

이 글에서는 Advisory Locks를 사용하지 않도록 하는 방법을 소개합니다. 단, 이는 데이터베이스 어댑터 자체에 적용이되는 설정이므로 부작용이 생길 수 있고 프로덕션 환경에서는 상황에 맞춰 사용해야 합니다.

44BITS 소식과 클라우드 뉴스를 전해드립니다. 지금 5,000명 이상의 구독자와 함께 하고 있습니다 📮

Ruby on Rails 6 이상의 경우

레일스 6 버전 이상의 버전에는 데이터베이스 설정에서 Advisory Locks를 사용하지 않도록 설정하는 기능이 추가되었습니다. 다음 내용을 database.yml에서 적절한 위치에 추가해주면됩니다.

production:
  adapter: postgresql
  advisory_locks: false

자세한 내용은 다음 블로그의 내용을 참고해주세요.

Ruby on Rails 5의 경우

레일스 5에서는 advisory_locks: false이 동작하지 않습니다. 하지만 Advisory Locks를 처리하는 PR(#33691)과 마이그레이션 관련 레일스 코드를 쫓아가 보면 Advisory Locks를 사용하지 않도록 하는 부분은 레일스 5에도 이미 구현이 되어있는 것을 확인할 수 있습니다. 단 supports_advisory_locks? 함수가 true 고정값으로 설정되어있어서 이 설정을 끄는 것이 불가능합니다. 이를 해결하기 위해서 해당 부분을 몽키패칭할 수 있습니다.

config/initializers/disable_advisory_locks.rb 파일을 생성하고 다음 내용을 추가해줍니다.

module ActiveRecord
  module ConnectionAdapters
    class PostgreSQLAdapter
      def supports_advisory_locks?
        false
      end
    end
  end
end

이는 레일스에서 사용하는 PostgeSQLAdapter 클래스를 몽키패치하는 내용으로 Advisory Locks 기능을 비활성화하도록 강제합니다. 이는 true를 반환하도록 되어있는 supports_advisory_locks? 메서드가 false를 반환하도록 직접 수정하는 방법입니다. 마이그레이션 코드 상에는 이 부분을 처리하는 내용이 이미 포함되어있기 때문에 에러 없이 마이그레이션이 실행됩니다.

PostGIS를 사용하는 경우 아래와 같이 추가해줍니다.

module ActiveRecord
  module ConnectionAdapters
    class PostGISAdapter
      def supports_advisory_locks?
        false
      end
    end
  end
end

Advisory Locks을 마이그레이션에서만 사용한다는 가정 하에서는 큰 문제가 될 부분은 없어 보입니다만, 혹시 모를 부작용이 생길 수 있으니 레일스 쪽의 이슈나 PR을 참고해주시기 바랍니다.

'좋은 기술 블로그를 만들어 나가기 위한 8가지 제언' 대표 이미지

좋은 기술 블로그를 만들어 나가기 위한 8가지 제언

🗒 기사, 2019-01-17 - 좋은 블로그를 정의하는 것은 간단하지 않습니다. 그럼에도 불구하고 분명히 좋은 블로그가 존재하고 다른 블로그와는 다른 무언가가 있습니다. 이 글에서는 기술 블로그를 중심으로, 좋은 블로그를 만들어나가기 위한 8가지 방법을 제언합니다.

패커(Packer)를 사용한 도커 이미지와 AMI 만들기(feat. Ansible)

🗒 기사, 2015-09-30 - 패커는 하시코프에서 만든 범용 가상머신, 컨테이니 이미지 생성 도구입니다. 패커는 시스템의 특정 상태를 저장하는 대신 복원 가능한 방식으로 이미지 생성을 자동화할 수 있게 도와줍니다. 이 글에서는 패커를 사용해 도커 이미지와 AMI 이미지를 빌드하는 방법을 소개합니다.

AWS 솔루션 아키텍트 어소시에이트 자격증 취득 후기 - AWS 공인 자격증 준비와 합격자 혜택

🗒 기사, 2019-10-21 - 2019년 10월 AWS 솔루션 아키텍트 어소시에이트 자격증 취득했습니다. AWS 공인 자격증의 종류와 시험 준비에 대해서 소개하고, 합격자 혜택에 대해서도 알아봅니다.