NGINX Plus를 사용한 MySQL Load Balancing

이 포스트에서는 NGINX Plus 및 NGINX Open Source의 일부 고급 기능을 사용하여 Galera 클러스터에서 MySQL 데이터베이스 서버의 Load Balancing 하는 방법을 설명합니다. 클러스터에서 복제 문제를 제거하는 한 가지 접근 방식, Load Balancing 데이터베이스 서버 간에 읽기 및 쓰기 분할의 이점, 데이터베이스 서버가 실제로 쿼리에 응답하는지 확인하기 위해 애플리케이션 Health Check를 구성하는 방법을 살펴봅니다.

Note: NGINX와 NGINX Plus 모두 사용 가능한 기능을 논의하지만 읽기 쉽게 하기 위해 전체적으로 NGINX Plus를 참조합니다.

목차

1. MySQL 데이터베이스 서버의 Galera 클러스터 설정
2. Load Balancing 구성
3. 읽기 및 쓰기 분할
4. 애플리케이션 Health Check 구성
5. 결론

1. MySQL 데이터베이스 서버의 Galera 클러스터 설정

DigitalOcean 가이드에 따라 3개의 MariaDB 데이터베이스 서버를 Galera 클러스터로 설정했지만 원하는 대로 동일한 클러스터를 설정하고 MySQL 을 MariaDB로 대체할 수 있습니다.

또한 애플리케이션에서 데이터베이스 클러스터로 들어오는 요청을 Proxy 하도록 NGINX Plus를 구성했습니다.

2. Load Balancing 구성

간단한 Load Balancing을 위해 NGINX Plus는 모든 쿼리를 클러스터의 지정된 Primary로 전달합니다. 우리는 TCP Load Balancing을 수행하고 있으므로 stream 컨텍스트에 지시문을 넣습니다.

stream {
    upstream galera {
        # default to primary, fallback to secondary when unavailable
        server db-node01.example.com:3306;
        server db-node02.example.com:3306 backup;
        server db-node03.example.com:3306 down;
    }

    server {
        listen 3306;
        proxy_pass galera;
        proxy_connect_timeout 1s;
    }
}

여기서는 하나가 Primary로 지정된 세 개의 서버 클러스터를 사용하고 있지만 기본 기술은 매우 큰 클러스터로 확장될 수 있습니다.

이 구성은 클러스터에서 작업할 때 여러 가지 이점을 제공합니다.

  • 클러스터를 개발할 목적으로 클러스터를 단일 데이터베이스로 간주하고 클러스터를 보유함으로써 얻을 수 있는 복제 이점을 활용할 수 있습니다.
  • 클러스터의 여러 Primary 시스템 간에 발생하는 병렬 쓰기 및 충돌에 대해 더 이상 걱정할 필요가 없습니다. 이전 포스트에서 모든 서버가 Primary 서버로 작동했으며 서로 다른 서버에 대한 병렬 업데이트로 인해 잠재적으로 잘못된 데이터가 발생하는 문제가 있었습니다. 클러스터가 지시된 대로 작동하더라도 클라이언트가 여러 서버에 여러 값을 한 번에 삽입하려고 하면 결과가 직관적이지 않습니다.
  • 서버 간 네트워크 속도에 비해 트래픽 양이 많아 한 서버에서 데이터를 쓰는 것과 복제 서버에서 데이터를 읽을 수 있는 것 사이에 상당한 지연이 발생하는 복제 지연을 제거했습니다. 즉, 다른 서버가 데이터베이스에 기록한 직후에 한 서버에서 데이터를 읽을 경우 업데이트가 표시되지 않을 수 있습니다. Load Balancer가 모든 트래픽을 단일 Primary MySQL 서버로 유도하기 때문에 설정에서 이 문제를 방지합니다.

3. 읽기 및 쓰기 분할

쓰기는 클러스터의 Primary 서버로 전달되는 것이 가장 좋지만 읽기 쿼리는 클러스터의 보조 구성원으로 전달하는 것이 바람직합니다. 이를 설정하는 것은 조금 더 복잡합니다. NGINX Plus Load Balancer는 들어오는 SQL 쿼리를 구문 분석하지 않으므로 대신 애플리케이션 계층에서 읽기와 쓰기를 구분해야 합니다.

읽기 및 쓰기를 분할하는 가장 쉬운 방법은 각각 다른 포트에서 수신하는 별도의 Load Balancer를 설정하는 것입니다. 애플리케이션은 SELECT 쿼리만 포함된 모든 트랜잭션을 읽기 Load Balancer로 보내고 INSERT, UPDATE 또는 DELETE 쿼리가 있는 모든 트랜잭션은 쓰기 Load Balancer로 보냅니다. 다음은 이 설정에 대한 샘플 구성 파일입니다.

stream {
    # Separate TCP load balancers for reads and writes
    upstream galera_read {
        #zone is necessary for health checks later
        zone backend 64k;
        server db-node02.example.com:3306;
        server db-node03.example.com:3306;
    }

    upstream galera_write {
        zone backend;
        server db-node01.example.com:3306;
        server db-node02.example.com:3306 backup;
        server db-node03.example.com:3306 down;
    }

    server {
        listen 3308;
        status_zone tcp_server;
        proxy_pass galera_read;
        proxy_connect_timeout 1s;
    }

    server {
        listen 3309;
        status_zone tcp_server;
        proxy_pass galera_write;
        proxy_connect_timeout 1s;
    }
}

그런 다음 요청을 읽기 포트(여기서는 3308) 또는 쓰기 포트(3309)로 적절하게 전송하도록 애플리케이션 코드를 재작업해야 합니다. 이것은 상당한 양의 작업이 될 수 있지만 많은 일반 데이터베이스 라이브러리(예: Django 및 Hibernate)는 여러 데이터베이스의 컨텍스트에서 애플리케이션이 데이터베이스를 더 잘 인식하도록 하는 기능을 제공합니다.

애플리케이션 아키텍처의 목적은 읽기가 읽기 Load Balancer를 통과하고 쓰기 Load Balancer를 통해 쓰기를 수행하는 것이지만, 그 어떤 것도 쓰기 포트의 읽기를 방해하지 않으며 그 반대의 경우도 마찬가지입니다. 이를 방지하기 위해 서로 다른 호스트의 Load Balancer를 분리하고 서로 다른 권한을 부여하여 읽기 Load Balancer가 데이터베이스에 의해 읽기만 하도록 제한할 수 있지만 여기에서는 해당 구성을 표시하지 않습니다.

4. 애플리케이션 Health Check 구성

SQL 서버 Load Balancing을 통한 애플리케이션 Health Check에는 다양한 옵션이 있습니다. 가장 간단한 것은 NGINX Plus가 Upstream 데이터베이스 서버에 연결을 전달할 때 데이터베이스 연결 시도에 응답하는지 확인하는 것입니다. 이는 NGINX Plus와 NGINX 모두의 기본 동작입니다. Proxy는 기본적으로 데이터베이스와 통신할 수 있는 기능이 없지만, 서버가 여전히 존재한다는 것을 알려주는 빠른 응답을 받습니다.

이러한 간단한 종류의 Health Check은 경우에 따라 충분하지만 불편한 단점이 있습니다. NGINX Plus Load Balancer는 실제로 요청을 처리할 수 없는 경우에도 새 연결을 수락하는 Upstream 데이터베이스 서버에 요청을 계속 보냅니다(예: , 데이터베이스 서버 간의 복제 문제로 인해 서버가 쓰기를 수행할 수 없는 경우).

Production에서는 NGINX의 Health Check 기능을 보다 완벽하게 활용하기 위해 데이터베이스 응답을 의미 있는 것으로 구문 분석할 방법이 필요합니다. 이는 일반적으로 데이터베이스의 상태를 확인하고 데이터베이스 상태와 함께 Load Balancer의 HTTP 요청에 응답하는 열린 포트의 데이터베이스 서버에서 프로세스를 실행하여 수행됩니다. 상태 요청 ping이 들어올 때마다 간단한 SELECT 쿼리(또는 선택한 데이터베이스 Health Check)를 실행하는 자체 스크립트를 작성하거나 데이터베이스 노드에서 간단한 데이터베이스 표시 쿼리를 수행하는 이 기존 Health Check 스크립트를 사용할 수 있습니다.

테스트 클러스터의 경우 GitHub에서 연결된 Health Check 스크립트를 설치하고 포트 9200(기본 포트)에서 실행되는 서비스로 설정했습니다. 스크립트는 HTTP를 사용하여 Ping의 Health Check에 응답하므로 노드가 정상일 때 HTTP 응답의 헤드를 확인하고 다운되었을 때 다시 확인하여 제대로 작동하는지 확인합니다(상태 코드와 함께 curl 출력의 첫 번째 줄만 표시)

user@dbnode-03:# curl -i http://localhost:9200
HTTP/1.1 200 OK
     ...

user@dbnode-03:# sudo service mysql stop
 * Stopping MariaDB database server mysqld                    [ OK ]

user@dbnode-03:# curl -i http://localhost:9200
HTTP/1.1 503 Service Unavailable
     ...

마지막 단계는 애플리케이션 Health Check을 위해 포트 9200을 사용하도록 NGINX Plus를 설정하는 것입니다. Health Check을 특정 포트로 지정하는 기능은 NGINX Plus 릴리스 8의 새로운 기능입니다. server 블록의 health_check 지시문에 포트 매개변수를 추가하는 것만큼 간단합니다.

stream {
    upstream galera {
        # ...
    }

    server {
        listen 3306;
        proxy_pass galera;
        proxy_connect_timeout 1s;
        health_check port=9200;
    }
}

NGINX Plus가 아닌 NGINX를 사용하는 경우 서버를 사용할 수 없을 때마다 외부 트래픽에 대해 MySQL 포트를 닫는 해결 방법을 사용할 수 있습니다. 이를 통해 NGINX Plus와 동일한 심층적인 Health Check를 받을 수 있지만 이 경우 Health Check는 서비스에 대한 일반 요청과 동일한 포트로 전송됩니다.

어떤 방법을 사용하든 Health Check에서 오류 응답을 반환하면 NGINX Plus Load Balancer는 서버가 복구될 때까지 Pool에서 데이터베이스 서버를 자동으로 제거합니다. 데이터베이스 Downtime의 일반적인 원인은 예기치 않은 대규모 Join 또는 쿼리가 갑자기 느려지는 등 무의식적으로 너무 많은 작업을 사용하는 것입니다. 이 경우 서버는 자체적으로 복구하여 점차 더 많은 비율의 Health Check을 통과하지만 과도한 로드에서 복구할 기회가 있는 경우 복구가 더 빠릅니다. 이 시나리오에서 NGINX Plus는 Health Check에 실패한 후 일정 기간 동안 서버에 대한 트래픽을 천천히 증가시키는 방법을 제공합니다.

5. MySQL Load Balancing 결론

간단한 Galera 클러스터 설정을 사용하여 MySQL Load Balancing의 일부 개념을 검토하고 확장했습니다. NGINX Plus를 Load Balancer로 사용하여 리소스를 최대화하기 위해 읽기 및 쓰기에 대해 분산 로드를 다르게 분할했습니다. 또한 NGINX Plus가 Load Balancing 중인 Upstream 리소스를 더 잘 관리할 수 있도록 클러스터에 대한 심층적인 Health Check을 수행하는 몇 가지 방법을 살펴보았습니다. NGINX Plus와 Galera의 조합을 통해 안정성을 유지하면서 하드웨어 리소스를 최대화할 수 있습니다.

NGINX Plus를 사용하여 MySQL Load Balancing을 사용해 보려면 지금 무료 30일 평가판을 시작하거나 당사에 연락하여 사용 사례에 대해 문의하거나 관련 최신 소식을 빠르게 전달받고 싶으시면 아래 뉴스레터를 구독하세요.