InfoGrab DocsInfoGrab Docs

데이터베이스 로드 밸런싱

요약

데이터베이스 로드 밸런싱을 사용하면 읽기 쿼리가 여러 PostgreSQL 노드로 분산되어 성능이 향상되고 기본 데이터베이스의 부하가 줄어듭니다. 데이터베이스 로드 밸런싱을 활성화하려면 다음 조건을 충족해야 합니다. 외부 데이터베이스 서비스에는 db_load_balancing 구성만 있으면 됩니다.

데이터베이스 로드 밸런싱을 사용하면 읽기 쿼리가 여러 PostgreSQL 노드로 분산되어 성능이 향상되고 기본 데이터베이스의 부하가 줄어듭니다. 쓰기 작업은 항상 기본 노드에서 실행됩니다. GitLab 이 쿼리 라우팅을 자동으로 처리하므로 외부 로드 밸런서가 필요하지 않습니다.

요구 사항#

데이터베이스 로드 밸런싱을 활성화하려면 다음 조건을 충족해야 합니다.

  • PostgreSQL에 기본 노드를 복제하는 보조 노드가 하나 이상 있어야 합니다.
  • 각 노드는 동일한 포트와 동일한 자격 증명으로 접근할 수 있어야 합니다.

외부 데이터베이스 서비스에는 db_load_balancing 구성만 있으면 됩니다. 연결 풀링은 규모가 커질 때 연결 수를 관리하는 데 도움이 되지만, 적절한 방식은 공급자에 따라 다르며 이 가이드의 범위를 벗어납니다. 연결 관리 지침은 연결 풀링을 참고합니다.

Note

AWS RDS Proxy는 GitLab과 함께 사용하도록 검증되지 않았습니다.

Linux 패키지 설치에서는 데이터베이스 로드 밸런싱을 활성화하기 전에 다중 노드 HA PostgreSQL을 구성해야 합니다. 자세한 내용은 다중 노드 구성을 참고합니다.

복제본 수#

복제본 수에는 제한이 없습니다. 실무에서는 세 개로 시작하는 경우가 많으며, 특히 가용 영역 세 곳에 분산된 환경에서 그렇습니다. Consul과 Redis Sentinel을 비롯한 여러 GitLab 구성 요소는 쿼럼에 의존하며 홀수 개의 노드를 요구합니다. 데이터베이스 복제본 수를 이 패턴에 맞추면 아키텍처가 더 일관되고 재해 복구 범위가 넓어지며, 단일 가용 영역 장애의 영향이 줄어듭니다. 규모가 작은 환경은 복제본 두 개로 시작한 뒤 부하가 늘면 추가할 수 있습니다.

규모별 지침은 레퍼런스 아키텍처 문서를 참고합니다.

데이터베이스 로드 밸런싱 구성#

데이터베이스 로드 밸런싱은 다음 두 가지 방식 중 하나로 구성할 수 있습니다.

  • 호스트: PostgreSQL 호스트의 정적 목록입니다. 구성이 더 단순하며 대부분의 환경에 적합합니다.
  • 서비스 디스커버리: PostgreSQL 호스트 목록을 반환하는 DNS 레코드입니다. Consul을 사용하는 Linux 패키지 HA 구성처럼 복제본 목록이 동적으로 바뀔 때 사용합니다.

호스트#

호스트 목록에 기본 노드를 포함할지는 선택 사항입니다. 포함하면 복제본과 함께 읽기 쿼리 대상이 되어 보조 노드의 전체 부하가 줄어듭니다. 기본 노드가 이미 지속적으로 높은 부하를 받고 있다면, 목록에서 빼서 쓰기 처리 용량을 확보합니다. 기본 노드는 이 목록에 포함되는지와 무관하게 언제나 쓰기 쿼리를 처리합니다.

호스트 목록을 구성하려면 분산 대상 환경의 모든 GitLab Rails 및 Sidekiq 노드에서 다음 단계를 수행합니다.

  1. /etc/gitlab/gitlab.rb 파일을 편집합니다.

  2. gitlab_rails['db_load_balancing']에 분산할 데이터베이스 호스트 배열을 만듭니다. 예를 들어 PostgreSQL 이 primary.example.com, secondary1.example.com, secondary2.example.com에서 실행되는 환경이라면 다음과 같이 작성합니다.

    gitlab_rails['db_load_balancing'] = { 'hosts' => ['primary.example.com', 'secondary1.example.com', 'secondary2.example.com'] }
    

    이 호스트들은 gitlab_rails['db_port']로 구성한 동일한 포트로 접근할 수 있어야 합니다.

  3. 파일을 저장하고 GitLab을 재구성합니다.

서비스 디스커버리#

서비스 디스커버리를 사용하면 GitLab 이 PostgreSQL 호스트 목록을 자동으로 가져옵니다. GitLab은 DNS A 레코드를 주기적으로 확인하고 반환된 IP 주소를 복제본 주소로 사용합니다. 서비스 디스커버리를 사용하려면 DNS 서버와 보조 노드의 IP 주소가 담긴 A 레코드가 필요합니다.

Linux 패키지 설치에서는 함께 제공되는 Consul 서비스가 DNS 서버 역할을 하며 postgresql-ha.service.consul 레코드로 PostgreSQL 주소를 반환합니다. 다음 다이어그램은 이 배포 모델을 보여 줍니다.

PlantUML 다이어그램 (38줄)
소스 코드 보기
@startuml
!theme plain
card "**Internal Load Balancer**" as ilb
skinparam linetype ortho

together { collections "GitLab Rails x3" as gitlab collections "Sidekiq x4" as sidekiq }

collections "Consul x3" as consul

card "Database" as database { collections "PGBouncer x3\n//Consul//" as pgbouncer

card "PostgreSQL //Primary//\n//Patroni//\n//PgBouncer//\n//Consul//" as postgres_primary collections "PostgreSQL //Secondary// x2\n//Patroni//\n//PgBouncer//\n//Consul//" as postgres_secondary

pgbouncer --> postgres_primary postgres_primary .r-> postgres_secondary }

gitlab --> ilb gitlab -[hidden]-> pgbouncer gitlab .[norank]-> postgres_primary gitlab .[norank]-> postgres_secondary

sidekiq --> ilb sidekiq -[hidden]-> pgbouncer sidekiq .[norank]-> postgres_primary sidekiq .[norank]-> postgres_secondary

ilb --> pgbouncer

consul -r-> pgbouncer consul .[norank]r-> postgres_primary consul .[norank]r-> postgres_secondary @enduml

Consul로 서비스 디스커버리를 구성하려면 다음 단계를 따릅니다.

  1. 각 GitLab Rails / Sidekiq 노드에서 /etc/gitlab/gitlab.rb를 편집해 다음을 추가합니다.

    gitlab_rails['db_load_balancing'] = { 'discover' => {
        'nameserver' => 'localhost'
        'record' => 'postgresql-ha.service.consul'
        'record_type' => 'A'
        'port' => '8600'
        'interval' => '60'
        'disconnect_timeout' => '120'
      }
    }
    
  2. 파일을 저장하고 변경 사항을 적용하려면 GitLab을 재구성합니다.

옵션 설명 기본값
nameserver DNS 레코드 조회에 사용할 네임서버입니다. localhost
record 조회할 레코드입니다. 서비스 디스커버리가 동작하려면 이 옵션이 필요합니다.
record_type 조회할 레코드 유형이며 선택 사항입니다. A 또는 SRV를 지정할 수 있습니다. A
port 네임서버의 포트입니다. 8600
interval DNS 레코드 확인 사이의 최소 시간(초)입니다. 60
disconnect_timeout 호스트 목록이 업데이트된 뒤 이전 연결이 닫히기까지의 시간(초)입니다. 120
use_tcp UDP 대신 TCP로 DNS 리소스를 조회합니다. false
max_replica_pools 각 GitLab 프로세스가 연결하는 최대 복제본 수입니다. 서비스 디스커버리를 사용할 때만 적용됩니다. 이 한도가 없으면 모든 프로세스가 모든 복제본에 연결합니다. 복제본과 GitLab 노드가 모두 많을 때 사용합니다. nil

record_type을 SRV로 설정하면 GitLab은 라운드 로빈을 사용하고 레코드의 weight와 priority는 무시합니다. SRV 레코드는 대개 IP가 아니라 호스트명을 반환하므로, GitLab은 SRV 응답의 additional 섹션에서 IP 주소를 찾습니다. 호스트명에 대한 IP를 찾지 못하면 GitLab은 구성된 nameserver에 해당 호스트명의 ANY 레코드를 조회해 A 또는 AAAA 레코드를 찾습니다. IP를 확인하지 못하면 GitLab은 그 호스트명을 로테이션에서 제외합니다.

interval 값은 확인 사이의 최소 시간을 지정합니다. A 레코드의 TTL 이 이 값보다 크면 서비스 디스커버리는 그 TTL을 따릅니다. 예를 들어 TTL 이 90초라면 서비스 디스커버리는 최소 90초를 기다린 뒤 다시 확인합니다.

호스트 목록이 업데이트되면 이전 연결이 종료되기까지 시간이 걸릴 수 있습니다. disconnect_timeout으로 이 시간의 상한을 설정합니다.

오래된 읽기#

히스토리
  • 14.0에서 GitLab Premium에서 GitLab Free로 이동되었습니다.

GitLab은 읽기를 라우팅하기 전에 각 보조 노드의 복제 상태를 확인합니다. 보조 노드가 기본 노드보다 너무 많이 뒤처져 있으면 따라잡을 때까지 건너뜁니다.

옵션 설명 기본값
max_replication_difference 보조 노드가 최근에 데이터를 복제하지 않은 경우 허용되는 지연 데이터 양(바이트)입니다. 8 MB
max_replication_lag_time 보조 노드를 건너뛰기 전까지 허용되는 최대 지연 시간(초)입니다. 60초
replica_check_interval 보조 노드 상태 확인 사이의 최소 시간(초)입니다. 60초

기본값은 대부분의 환경에 충분합니다.

호스트 목록과 함께 이 옵션을 구성하려면 다음과 같이 작성합니다.

gitlab_rails['db_load_balancing'] = {
  'hosts' => ['primary.example.com', 'secondary1.example.com', 'secondary2.example.com'],
  'max_replication_difference' => 16777216, # 16 MB
  'max_replication_lag_time' => 30,
  'replica_check_interval' => 30
}

로깅#

로드 밸런서는 다음과 같은 여러 이벤트를 database_load_balancing.log에 기록합니다.

  • 호스트가 오프라인으로 표시될 때.
  • 호스트가 다시 온라인이 될 때.
  • 모든 보조 노드가 오프라인일 때.
  • 쿼리 충돌로 다른 호스트에서 읽기를 재시도할 때.

로그는 구조화되어 있으며 각 항목은 최소한 다음을 포함하는 JSON 오브젝트입니다.

  • 필터링에 유용한 event 필드.
  • 사람이 읽을 수 있는 message 필드.
  • db_host 같은 이벤트별 메타데이터.
  • severity와 time처럼 항상 기록되는 컨텍스트 정보.

예를 들면 다음과 같습니다.

{"severity":"INFO","time":"2019-09-02T12:12:01.728Z","correlation_id":"abcdefg","event":"host_online","message":"Host came back online","db_host":"111.222.333.444","db_port":null,"tag":"rails.database_load_balancing","environment":"production","hostname":"web-example-1","fqdn":"gitlab.example.com","path":null,"params":null}

데이터베이스 로드 밸런싱 동작 방식#

쿼리 분산#

읽기 쿼리는 구성된 모든 데이터베이스 호스트로 분산됩니다. 쓰기 작업은 복제본 수와 무관하게 항상 기본 노드에서 실행됩니다.

기본 노드 고정#

쓰기가 일어난 뒤 GitLab은 해당 사용자의 읽기를 최대 30초 동안 기본 노드로 라우팅합니다. GitLab은 30초를 모두 기다리지 않고 복제본이 따라잡는 즉시 복제본 사용으로 되돌립니다. 백그라운드 job도 오래된 데이터를 읽지 않도록, 쓰기 이후 복제본이 따라잡기를 기다린 뒤 읽습니다.

장애 조치 처리#

보조 노드를 사용할 수 없게 되면 로드 밸런서는 다음으로 사용 가능한 호스트로 라우팅합니다. 사용할 수 있는 보조 노드가 없으면 읽기는 기본 노드로 대체됩니다.

쓰기가 실패하면 해당 작업을 최대 3회 재시도합니다. 데이터베이스 서버를 재시작해도 사용자에게 즉시 오류가 발생하지는 않습니다.

데이터베이스 로드 밸런싱

GitLab v19.5
Tier: Free, Premium, Ultimate
Offering: GitLab Self-Managed
원문 보기

요약

데이터베이스 로드 밸런싱을 사용하면 읽기 쿼리가 여러 PostgreSQL 노드로 분산되어 성능이 향상되고 기본 데이터베이스의 부하가 줄어듭니다. 데이터베이스 로드 밸런싱을 활성화하려면 다음 조건을 충족해야 합니다. 외부 데이터베이스 서비스에는 db_load_balancing 구성만 있으면 됩니다.

데이터베이스 로드 밸런싱을 사용하면 읽기 쿼리가 여러 PostgreSQL 노드로 분산되어 성능이 향상되고 기본 데이터베이스의 부하가 줄어듭니다. 쓰기 작업은 항상 기본 노드에서 실행됩니다. GitLab 이 쿼리 라우팅을 자동으로 처리하므로 외부 로드 밸런서가 필요하지 않습니다.

요구 사항#

데이터베이스 로드 밸런싱을 활성화하려면 다음 조건을 충족해야 합니다.

  • PostgreSQL에 기본 노드를 복제하는 보조 노드가 하나 이상 있어야 합니다.
  • 각 노드는 동일한 포트와 동일한 자격 증명으로 접근할 수 있어야 합니다.

외부 데이터베이스 서비스에는 db_load_balancing 구성만 있으면 됩니다. 연결 풀링은 규모가 커질 때 연결 수를 관리하는 데 도움이 되지만, 적절한 방식은 공급자에 따라 다르며 이 가이드의 범위를 벗어납니다. 연결 관리 지침은 연결 풀링을 참고합니다.

Note

AWS RDS Proxy는 GitLab과 함께 사용하도록 검증되지 않았습니다.

Linux 패키지 설치에서는 데이터베이스 로드 밸런싱을 활성화하기 전에 다중 노드 HA PostgreSQL을 구성해야 합니다. 자세한 내용은 다중 노드 구성을 참고합니다.

복제본 수#

복제본 수에는 제한이 없습니다. 실무에서는 세 개로 시작하는 경우가 많으며, 특히 가용 영역 세 곳에 분산된 환경에서 그렇습니다. Consul과 Redis Sentinel을 비롯한 여러 GitLab 구성 요소는 쿼럼에 의존하며 홀수 개의 노드를 요구합니다. 데이터베이스 복제본 수를 이 패턴에 맞추면 아키텍처가 더 일관되고 재해 복구 범위가 넓어지며, 단일 가용 영역 장애의 영향이 줄어듭니다. 규모가 작은 환경은 복제본 두 개로 시작한 뒤 부하가 늘면 추가할 수 있습니다.

규모별 지침은 레퍼런스 아키텍처 문서를 참고합니다.

데이터베이스 로드 밸런싱 구성#

데이터베이스 로드 밸런싱은 다음 두 가지 방식 중 하나로 구성할 수 있습니다.

  • 호스트: PostgreSQL 호스트의 정적 목록입니다. 구성이 더 단순하며 대부분의 환경에 적합합니다.
  • 서비스 디스커버리: PostgreSQL 호스트 목록을 반환하는 DNS 레코드입니다. Consul을 사용하는 Linux 패키지 HA 구성처럼 복제본 목록이 동적으로 바뀔 때 사용합니다.

호스트#

호스트 목록에 기본 노드를 포함할지는 선택 사항입니다. 포함하면 복제본과 함께 읽기 쿼리 대상이 되어 보조 노드의 전체 부하가 줄어듭니다. 기본 노드가 이미 지속적으로 높은 부하를 받고 있다면, 목록에서 빼서 쓰기 처리 용량을 확보합니다. 기본 노드는 이 목록에 포함되는지와 무관하게 언제나 쓰기 쿼리를 처리합니다.

호스트 목록을 구성하려면 분산 대상 환경의 모든 GitLab Rails 및 Sidekiq 노드에서 다음 단계를 수행합니다.

  1. /etc/gitlab/gitlab.rb 파일을 편집합니다.

  2. gitlab_rails['db_load_balancing']에 분산할 데이터베이스 호스트 배열을 만듭니다. 예를 들어 PostgreSQL 이 primary.example.com, secondary1.example.com, secondary2.example.com에서 실행되는 환경이라면 다음과 같이 작성합니다.

    gitlab_rails['db_load_balancing'] = { 'hosts' => ['primary.example.com', 'secondary1.example.com', 'secondary2.example.com'] }
    

    이 호스트들은 gitlab_rails['db_port']로 구성한 동일한 포트로 접근할 수 있어야 합니다.

  3. 파일을 저장하고 GitLab을 재구성합니다.

서비스 디스커버리#

서비스 디스커버리를 사용하면 GitLab 이 PostgreSQL 호스트 목록을 자동으로 가져옵니다. GitLab은 DNS A 레코드를 주기적으로 확인하고 반환된 IP 주소를 복제본 주소로 사용합니다. 서비스 디스커버리를 사용하려면 DNS 서버와 보조 노드의 IP 주소가 담긴 A 레코드가 필요합니다.

Linux 패키지 설치에서는 함께 제공되는 Consul 서비스가 DNS 서버 역할을 하며 postgresql-ha.service.consul 레코드로 PostgreSQL 주소를 반환합니다. 다음 다이어그램은 이 배포 모델을 보여 줍니다.

PlantUML 다이어그램 (38줄)
소스 코드 보기
@startuml
!theme plain
card "**Internal Load Balancer**" as ilb
skinparam linetype ortho

together { collections "GitLab Rails x3" as gitlab collections "Sidekiq x4" as sidekiq }

collections "Consul x3" as consul

card "Database" as database { collections "PGBouncer x3\n//Consul//" as pgbouncer

card "PostgreSQL //Primary//\n//Patroni//\n//PgBouncer//\n//Consul//" as postgres_primary collections "PostgreSQL //Secondary// x2\n//Patroni//\n//PgBouncer//\n//Consul//" as postgres_secondary

pgbouncer --> postgres_primary postgres_primary .r-> postgres_secondary }

gitlab --> ilb gitlab -[hidden]-> pgbouncer gitlab .[norank]-> postgres_primary gitlab .[norank]-> postgres_secondary

sidekiq --> ilb sidekiq -[hidden]-> pgbouncer sidekiq .[norank]-> postgres_primary sidekiq .[norank]-> postgres_secondary

ilb --> pgbouncer

consul -r-> pgbouncer consul .[norank]r-> postgres_primary consul .[norank]r-> postgres_secondary @enduml

Consul로 서비스 디스커버리를 구성하려면 다음 단계를 따릅니다.

  1. 각 GitLab Rails / Sidekiq 노드에서 /etc/gitlab/gitlab.rb를 편집해 다음을 추가합니다.

    gitlab_rails['db_load_balancing'] = { 'discover' => {
        'nameserver' => 'localhost'
        'record' => 'postgresql-ha.service.consul'
        'record_type' => 'A'
        'port' => '8600'
        'interval' => '60'
        'disconnect_timeout' => '120'
      }
    }
    
  2. 파일을 저장하고 변경 사항을 적용하려면 GitLab을 재구성합니다.

옵션 설명 기본값
nameserver DNS 레코드 조회에 사용할 네임서버입니다. localhost
record 조회할 레코드입니다. 서비스 디스커버리가 동작하려면 이 옵션이 필요합니다.
record_type 조회할 레코드 유형이며 선택 사항입니다. A 또는 SRV를 지정할 수 있습니다. A
port 네임서버의 포트입니다. 8600
interval DNS 레코드 확인 사이의 최소 시간(초)입니다. 60
disconnect_timeout 호스트 목록이 업데이트된 뒤 이전 연결이 닫히기까지의 시간(초)입니다. 120
use_tcp UDP 대신 TCP로 DNS 리소스를 조회합니다. false
max_replica_pools 각 GitLab 프로세스가 연결하는 최대 복제본 수입니다. 서비스 디스커버리를 사용할 때만 적용됩니다. 이 한도가 없으면 모든 프로세스가 모든 복제본에 연결합니다. 복제본과 GitLab 노드가 모두 많을 때 사용합니다. nil

record_type을 SRV로 설정하면 GitLab은 라운드 로빈을 사용하고 레코드의 weight와 priority는 무시합니다. SRV 레코드는 대개 IP가 아니라 호스트명을 반환하므로, GitLab은 SRV 응답의 additional 섹션에서 IP 주소를 찾습니다. 호스트명에 대한 IP를 찾지 못하면 GitLab은 구성된 nameserver에 해당 호스트명의 ANY 레코드를 조회해 A 또는 AAAA 레코드를 찾습니다. IP를 확인하지 못하면 GitLab은 그 호스트명을 로테이션에서 제외합니다.

interval 값은 확인 사이의 최소 시간을 지정합니다. A 레코드의 TTL 이 이 값보다 크면 서비스 디스커버리는 그 TTL을 따릅니다. 예를 들어 TTL 이 90초라면 서비스 디스커버리는 최소 90초를 기다린 뒤 다시 확인합니다.

호스트 목록이 업데이트되면 이전 연결이 종료되기까지 시간이 걸릴 수 있습니다. disconnect_timeout으로 이 시간의 상한을 설정합니다.

오래된 읽기#

히스토리
  • 14.0에서 GitLab Premium에서 GitLab Free로 이동되었습니다.

GitLab은 읽기를 라우팅하기 전에 각 보조 노드의 복제 상태를 확인합니다. 보조 노드가 기본 노드보다 너무 많이 뒤처져 있으면 따라잡을 때까지 건너뜁니다.

옵션 설명 기본값
max_replication_difference 보조 노드가 최근에 데이터를 복제하지 않은 경우 허용되는 지연 데이터 양(바이트)입니다. 8 MB
max_replication_lag_time 보조 노드를 건너뛰기 전까지 허용되는 최대 지연 시간(초)입니다. 60초
replica_check_interval 보조 노드 상태 확인 사이의 최소 시간(초)입니다. 60초

기본값은 대부분의 환경에 충분합니다.

호스트 목록과 함께 이 옵션을 구성하려면 다음과 같이 작성합니다.

gitlab_rails['db_load_balancing'] = {
  'hosts' => ['primary.example.com', 'secondary1.example.com', 'secondary2.example.com'],
  'max_replication_difference' => 16777216, # 16 MB
  'max_replication_lag_time' => 30,
  'replica_check_interval' => 30
}

로깅#

로드 밸런서는 다음과 같은 여러 이벤트를 database_load_balancing.log에 기록합니다.

  • 호스트가 오프라인으로 표시될 때.
  • 호스트가 다시 온라인이 될 때.
  • 모든 보조 노드가 오프라인일 때.
  • 쿼리 충돌로 다른 호스트에서 읽기를 재시도할 때.

로그는 구조화되어 있으며 각 항목은 최소한 다음을 포함하는 JSON 오브젝트입니다.

  • 필터링에 유용한 event 필드.
  • 사람이 읽을 수 있는 message 필드.
  • db_host 같은 이벤트별 메타데이터.
  • severity와 time처럼 항상 기록되는 컨텍스트 정보.

예를 들면 다음과 같습니다.

{"severity":"INFO","time":"2019-09-02T12:12:01.728Z","correlation_id":"abcdefg","event":"host_online","message":"Host came back online","db_host":"111.222.333.444","db_port":null,"tag":"rails.database_load_balancing","environment":"production","hostname":"web-example-1","fqdn":"gitlab.example.com","path":null,"params":null}

데이터베이스 로드 밸런싱 동작 방식#

쿼리 분산#

읽기 쿼리는 구성된 모든 데이터베이스 호스트로 분산됩니다. 쓰기 작업은 복제본 수와 무관하게 항상 기본 노드에서 실행됩니다.

기본 노드 고정#

쓰기가 일어난 뒤 GitLab은 해당 사용자의 읽기를 최대 30초 동안 기본 노드로 라우팅합니다. GitLab은 30초를 모두 기다리지 않고 복제본이 따라잡는 즉시 복제본 사용으로 되돌립니다. 백그라운드 job도 오래된 데이터를 읽지 않도록, 쓰기 이후 복제본이 따라잡기를 기다린 뒤 읽습니다.

장애 조치 처리#

보조 노드를 사용할 수 없게 되면 로드 밸런서는 다음으로 사용 가능한 호스트로 라우팅합니다. 사용할 수 있는 보조 노드가 없으면 읽기는 기본 노드로 대체됩니다.

쓰기가 실패하면 해당 작업을 최대 3회 재시도합니다. 데이터베이스 서버를 재시작해도 사용자에게 즉시 오류가 발생하지는 않습니다.