2019년 6월 3일 월요일

MySQL InnoDB Cluster 8.0 설치 가이드



Created by 박혜선 (huishan.piao@oracle.com), 류수미 (sumi.ryu@oracle.com), May 2019



https://mysqlserverteam.com/wp-content/uploads/2018/04/innodb_cluster_overview.png본 문서는 mysql 팀에서 작성된 MySQL InnoDB Cluster 8.0 – A Hands-on Tutorial  원문을 참고하여 작성된 것입니다.
문서는 일반적인 InnoDB Cluster설정을 어떻게 하는지, 그리고 전보다 얼마나 간단하고 효과적으로 설치할 수 있는지를 보여주기 위한 것입니다. InnoDB Cluster 익숙하지 않은 분들을 위한 좋은 출발점이며, 시작하는 도움이 것입니다.
여기서는 3 개의 MySQL Server 인스턴스 를 관리하고, InnoDB Cluster (Group Replication)3개의 멤버를 생성하기 위해 새로운 MySQL Shell  사용할 겁니다. 그런 다음 하나의 TCP 포트 뒤에 여러 MySQL 인스턴스를 숨기기 위해  새로운  MySQL Router  설정할 겁니다. 클라이언트 애플리케이션은 InnoDB Cluster의 토폴로지를 알 필요없이 MySQL Router가 제공하는 포트에 접속하면 됩니다. 예기치 않은 오류가 발생하면 InnoDB Cluster가 자동으로 조정되고 MySQL Router는 변경 사항을 감지하게 됩니다. 때문에 클라이언트 애플리케이션에서 장애 조치를 처리 할 필요가 없습니다.
일반적인 InnoDB Cluster 구성은 아래와 같습니다.
필수 패키지 다운로드 설치
MySQL Shell 8.0.16 GA

MySQL패키지 설치 전 해야할 일
/etc/hosts 파일을 열어서 VMIP에 대한 호스트 명을 명시해줍니다. VM마다 해당작업을 완료합니다.
그리고 각 VMhostname 확인 후 localhsot인 경우, hostname반드시 아래의 명령어를 이용해서 변경합니다.

# hostname
localhost.localdomain

# hostname ic-1

InnoDB Cluster 인스턴스 준비
한 인스턴스의 장애에 대해 내결함성(Group Replication fault-tolerance) 유지하려면 클러스터에 최소 3 개의 MySQL 인스턴스가 필요합니다인스턴스를 추가 하면(최대 9) 인스턴스 실패에 대한 허용치가 증가하지만 이 문서에서는 세개의 인스턴스 사용할 것입니다.

주의!
1.    개의 인스턴스가 각각 다른 호스트에서 실행되어야 합니다.
2.    InnoDB Cluster설정시 자동 재시작하기 위해서 MySQL서버를 시작할 mysqld_safe 서버를 시작해야 합니다.
3.     각 인스턴스의 서버ID가 유일해야 합니다.
4.    이 가이드에서는 remote root계정(root@%)으로 각 인스턴스에 접속하여 설정작업을 수행함으로 해당계정을 만들어야 합니다. 각 서버에서 mysql client 를 실행 후 아래 명령어를 수행합니다.

CREATE USER 'root'@'%' IDENTIFIED BY 'welcome1';
GRANT ALL on *.* to 'root'@'%' WITH GRANT OPTION;

mysql> show grants for 'root'@'%'\G
MySQL Shell을 이용하기 위해 MySQL Shell을 설치합니다. 이 가이드에서는 generic tar를 이용해서 설치하는 방법에 대해 설명합니다. 자세한 사항은 설치 가이드를 참고하시기 바랍니다. Trial 설치 파일은edelivery.oracle.com에서 MySQL Enterprise Package 내의 shell 설치파일을 다운받습니다. 다운받은 설치 파일을 원하시는 위치에 복사합니다.
mysql-shell-commercial-8.0.16-linux-glibc2.12-x86-64bit.tar.gz
설치 파일을 원하시는 위치에서 다음의 명령어를 이용해 압축을 해제합니다.
# tar xvf mysql-shell-commercial-8.0.16-linux-glibc2.12-x86-64bit.tar.gz
디렉토리명이 길기때문에 접근 편의를 위해 소프트링크를 걸어줍니다. 이 단계는 선택사항으로 원하지 않을 경우 건너뛰시면 됩니다.
# ln -s /mysql-shell-commercial-8.0.16-linux-glibc2.12-x86-64bit myshell

MySQL Shell 시작합니다. 일반적으로 root계정이 아닌 사용자로 시작하고 쉬운 디버깅을 위하여 mysqlsh --log-level=DEBUG3 옵션으로으로 MySQL Shell을 시작합니다. 그리고 logging 레벨은 변경할 수 있습니다.
# ./mysqlsh root@localhost --log-level=DEBUG3
그리고 dba.checkInstanceConfiguration() 함수를 사용하여 서버 설정을 확인합니다. 이는 MySQL 서버 인스턴스에 대한 연결이 필요하고 연결 정보는 다음과 같이 주실 수 있습니다.
  • A URI string
  • A dictionary  with the connection options
가이드에서는 URI 문자열을 사용합니다.
dba.checkInstanceConfiguration("root@ic-1:3306")
위의 결과는 일부 설정이 유효하지 않기 때문에 인스턴스가 InnoDB Cluster사용할  준비되지 않았다고 알려줍니다.
AdminAPI InnoDB Cluster 사용을 위해 인스턴스를 자동 및 원격으로 설정하는 dba.configureInstance() 명령을 제공합니다. 이 함수를 이용해 각 대상 인스턴스에 대한 서버 설정을 변경합니다.
dba.configureInstance("root@ic-1:3306")
인스턴스 ‘IC-1:3306’ 현재 mysql 서버를 재시작한 다음InnoDB Cluster 사용될 준비가 되었습니다!
참고 : dba.configureInstance()는 각 인스턴스에서 로컬로 실행하지 않아도됩니다원격으로 실행할 있으며 필요한 경우 해당 인스턴스의 원격 재시작이 지원(MySQL8.0 이상)됩니다.

주의 : 각 서버(또는VM)에서 각 MySQL 인스턴스를 위한 IP 3306 포트를 열어줘야 리모트 실행이 가능합니다. 이 문서는 InnoDB Cluster에 대한 설치 및 테스트 가이드를 제공하기 위한 목적이므로 리눅스의 방화벽 서비스을 해지하고 진행합니다. 이를 위해 아래 명령어를 수행합니다.
#  systemctl stop firewalld.service

클러스터를 초기화하기 전에 모든 인스턴스에서 위의 단계를 반복하십시오.
dba.checkInstanceConfiguration(“root@IC-2:3306”)
dba.configureInstance(“root@IC-2:3306”)
dba.checkInstanceConfiguration(“root@IC-3:3306”)
dba.configureInstance(“root@IC-3:3306”)

참고 :  인스턴스를 관리하는 사용되는 사용자 계정은 루트 계정 필요는 없지만 InnoDB Cluster 관리를 위한 특정 권한을 가진 계정이어야 합니다클러스터를 관리 할 사용자를 생성하는 기본 방법은dba.configureInstance()    함수에서 clusterAdmin 옵션을 사용할 수 있습니다.  본 문서에서는 루트계정을 이용해서 진행하므로 해당부분은 예시이며, 수행하지 않습니다.
) dba.configureInstance("root@ic-1:3306", {clusterAdmin: "myAdmin", clusterAdminPassword: "myAdminPwd"})

InnoDB Cluster초기화하기
위에서 설정완료된 인스턴스 하나에 연결합니다. 인스턴스는 Seed인스턴스 입니다Seed인스턴스는 데이터베이스의 초기 상태를 보유한 인스턴스로, 클러스터에 멤버가 추가되면 다른 인스턴스에 데이타를 복제해주는 역할을 하게 됩니다.
다음 단계는 InnoDB Cluster 생성합니다.
cluster = dba.createCluster("myCluster")
dba.createCluster() 함수는 InnoDB Cluster 이름을 한개의 파라미터로 받아들입니다이 과정은 다음과 같은 Step을 포함합니다.
§  Deploy the metadata schema in that instance (mysql_innodb_cluster_metadata)
§  Verify that its configuration is correct for Group Replication
§  Register it as the seed instance of the new cluster
§  Create necessary internal accounts, such as the replication user account
§  Start Group Replication
cluster.status();

InnoDB Cluster 인스턴스 추가하기
다음 단계는  InnoDB Cluster에 남은 두 멤버를 추가해야 합니다. 보통 인스턴스가 클러스터의 복제 세트에 추가되면 다른 기존ONLINE 멤버보다 데이타 측면에서 뒤쳐져있기 때문에 seed인스턴스의 현재 상태까지 따라 잡아야 합니다
seed인스턴스에 있는 기존 데이터의 양이 매우 경우 사전에 빠른 방법(백업본 복구) 통해 해당 데이터를 복사하거나 clone 하는게 좋을 수 있습니다그렇지 않으면 그룹 복제가 자동으로 동기화를 수행하여 ( 단계를 복구라고 ) seed서버의 MySQL 바이너리 로그에 존재하는 모든 트랜잭션을 다시 실행하게 됩니다.   가이드의 seed 인스턴스에는 데이터가 거의 없기 때문에 (, 메타 데이터 스키마와 내부 계정 ) 바이너리 로깅을 처음부터 활성화 했으므로 새로운 복제본이 데이타를 따라 잡을 필요가 거의 없습니다.
혹시 진행도 중 Server UUID 가 동일해서 진행할 수 없다는 에러가 발생하면 해당 서버의 데이타 디렉토리 아래의 auto.cnf를 삭제 후 mysql 서버를 재기동시켜주면 자동으로 새로운 UUID를 생성합니다.
Mysql-data-directory/auto.cnf

두번째 인스턴스를 InnoDB Cluster 추가합니다.
cluster.addInstance("root@ic-2:3306")

세번째 인스턴스를 InnoDB Cluster에 추가합니다.
cluster.addInstance("root@ic-3:3306")
마지막으로 클러스터의 상태를 확인해 보겠습니다.

명령으로 InnoDB Cluster 현재 상태를 조회하고 확인할 수 있습니다.  인스턴스의 상태 필드는 ONLINE 또는 RECOVERING 이 될 수 있고RECOVERING 인스턴스가 seed 인스턴스에서 업데이트를 수신 중이며 결국에는 ONLINE으로 전환될 것이라는 것을 의미합니다.
그리고 인스턴스 중 하나가 R/W (읽기/쓰기) 표시되고 다른 멤버는 R/O (읽기 전용) 표시됩니다. R/W 표시된 인스턴스(PRIMARY) 데이터베이스를 업데이트하는 트랜잭션을 실행할 있습니다만약, PRIMARY 인스턴스가 어떤 이유로 접근할 수 없게 되면 나머지 인스턴스 하나(선택 가능함) 자동으로 PRIMARY로 변경됩니다.
생성된 InnDB Cluster에 대한 변경 작업 및 관리 작업을 수행하려면 다음의 사용자 메뉴얼을 참고하십시오.
InnoDB Cluster가 생성되면 디폴트로 Single-Primary모드 입니다. R/W서버가 한대만 존재합니다. 이 기본모드를 온라인으로 Multi-Primary모드로 변경할 수 있습니다. , 모든 서버가 R/W 가능하게 변경할 수 있습니다.
InnoDB Cluster의 상태를 다시 확인해 보겠습니다.

MySQL Router 배포
애플리케이션이 페일 오버를 처리하려면 InnoDB Cluster 토폴로지를 알아야 합니다. 특히 어느 인스턴스가 PRIMARY인지를 알아야 합니다애플리케이션에서 자체적으로 이 로직을 구현할 수는 있지만 MySQL Router는 최소한의 작업으로 애클리케이션에서 코드 변경없이 그것을 가능하게 해줍니다.
MySQL Router에 대한 권장 배포방식은 애플리케이션과 동일한 호스트에 설치하는 것입니다. bootstrap하는 동안 MySQL 라우터는 클러스터에 연결하여 performance_schema, mysql_innodb_cluster_metadata를 조회하고 정상적인 작업중에 자체적으로 사용되는 최소한의 권한을 가진 읽기 전용 계정을 생성 합니다.
본 문서에서 generic tar를 이용해서 MySQL Router를 설치합니다. 패키지 다운로드 및 Yum 또는 APT 등을 이용한 설치 방법은 아래 사용자 메뉴얼을 참고하십시오.
먼저 tar를 설치를 원하는 디렉토리에 풀어줍니다.
 # tar -xvf mysql-router-commercial-8.0.16-linux-glibc2.12-x86_64.tar.xz
이 문서에서는 접근 편의를 위해서 소프트링크를 걸어서 사용하겠습니다. 선택사항이니 원하지 않는다면 해당 스탭은 건너뛰셔도 됩니다.
# ln -s /mysql-router-commercial-8.0.16-linux-glibc2.12-x86_64 /myrouter
MySQL Router IC-1서버에 이제 설치되었습니다. 메타 데이터 서버로 bootstrap하고 시스템 쉘스크립트로 다음 명령으로 mysqlrouter 호출하면 됩니다.
# ./mysqlrouter --bootstrap root@ic-1:3306 --user=mysql -d /myrouter/routerconf
MySQL Router InnoDB Cluster 연결하고 메타 데이터를 가져와서 자체로 설정합니다자체 디렉토리에서 실행되도록 구성되기때문에 동일한 호스트에서 여러개의 router인스턴스를 배포 있습니다.
생성 설정은 4 개의 TCP 포트를 제공합니다. 하나는 read-write 세션 (PRIMARY 연결)이고 다른 하나는 read-only 세션, 연결은 기본적으로 round-robin 방식으로 SECONDARY 인스턴스 하나로 연결됩니다. 그리고 한 세트는 Classic MySQL 연결 방식이고 다른 하나는 X 프로토콜을 이용한 연결(MySQL8.0)입니다.
bootstrap 설정이 끝나면 MySQL Router 시작하십시오. (또는 시스템 부팅시 자동으로 서비스가 시작되도록 설정하십시오)
bootstrap -d 옵션 뒤에 준 디렉토리를 자동으로 생성하며 설정파일 및 로그 등을 저장합니다. 해당 디렉토리 아래 실행파일인 start.sh가 있습니다.
# ./start.sh
MySQL 클라이언트에 접속하여 MySQL 라우터의 포트 하나에 연결하고 우리가 실제로 연결되어 있는 인스턴스를 보려면 'port' 'hostname' 상태 변수를 조회하기만 하면 됩니다.
# ./mysqlsh  --uri  root@localhost:6446
여기서 우리는 read-write 포트 (6446) 연결 하였고 라우터는 IC-1서버의 3306포트에 연결했습니다. 다음으로Single-Primary모드로 변경한 뒤 read-only 포트 (6447) 연결한 결과를 확인해 보겠습니다.
# ./mysqlsh  --uri  root@localhost:6447
select @@port, @@hostname;
현재 MySQL Router 6447포트로 접속하면 Read-Only서버인 Secondary서버 ‘IC-2:3306’에 접속하게 된 것을 확인할 수 있습니다.
InnoDB Cluster 상태 확인하기
InnoDB Cluster 상태를 확인하려면 Router 통해 클러스터에 연결하거나 인스턴스 하나에 직접 연결하여 InnoDB Cluster 오브젝트에 대한 정보를 조회할 수 있습니다. 클러스터 설정을 변경하려면 Router Read-Write 포트에 연결해야 합니다.
InnoDB Cluster에 대한 테스트
다음으로, 우리는 InnoDB Cluster failover 실제로 작동하는지 테스트해 보겠습니다.  PRIMARY 인스턴스를 kill하고 다른 인스턴스가 자동으로 PRIAMRY로 승격할 것인지 확인하기 위해 다시 테스트 세션 (MySQL 라우터)에서 현재 연결된 인스턴스를 확인합니다
1.    IC-3에서 IC-1서버에 설치된 Router에 접속합니다.
# ./mysqlsh --uri  root@ic-1:6446
2.    ‘IC-1:3306’ MySQL인스턴스를 kill합니다.
# kill -9 [mysql 프로세스ID]
3.    그리고 1번의 테스트 세션에서 바로 다시 조회합니다. 원래의 PRIMARY와의 연결이 끊어지기 때문에 번째 SELECT 실패하고 MySQL Shell 자동으로 다시 연결하기 때문에 다시 조회해 보면 현재 접속된 서버는 ‘IC-3:3306’로 변경된 것을 확인할 수 있습니다.
4.     그리고 이 클러스트의 상태를 다시 확인해 보면kill당한 ‘IC-1:3306’ 인스턴스는 “MISSING”상태로 나타내고 현재의 Read-Write서버 즉 PRIMARY‘IC-3:3306’ 이라는 것을 확인할 수 있겠습니다.
이것은 InnoDB Cluster 자동 페일 오버를 제공하고, MySQL Router 자동으로 새로운 PRIMARY 인스턴스 'IC-3:3306' 다시 연결함으로 HA 제공한다는 것을 보여줍니다.


cluster = dba.getCluster()
cluster.status()

5.     다음은  'IC-1:3306' 다시 온라인 상태로 만들고 이 클러스터의 상태를 확인해 보면 ‘IC-1:3306’ 는 자동으로 클러스터에 다시 Join하게 되여 상태가 ‘ONLINE’ 으로 변경된 것을 확인할 수 있습니다.
여기까지 보여드린 바와 같이 MySQL InnoDB Cluster 이용하여 최소한의 노력으로 고가용성을 구현할 있습니다.
MySQL을 사용하고 관심을 가져다 주셔서 감사합니다!