시냅스

MariaDB 설치부터 Galera Cluster 구성까지 본문

데이터베이스/MySQL

MariaDB 설치부터 Galera Cluster 구성까지

ted k 2024. 1. 17. 23:06

이 글에서는 Cent OS 를 기준으로 MariaDB 설치부터 Galera Cluster 구성까지 살펴봅니다.
실제로 운영하며 겪었던 TroubleShooting 및 중요사항에 대해 설명합니다.

 

MariaDB 설치

  • /etc/yum.repos.d/MariaDB.repo 를 등록합니다.
  • MariaDB 공식 repo 링크
    • 위 링크에서 현재 환경에 맞는 OS, MariaDB Version 을 선택합니다.
  • yum install MariaDB 명령어로 MariaDB 를 설치합니다.
  • mariadb --version 명령어로 설치를 확인합니다.
  • systemctl start mariadb 로 실행 후 mysql -uroot -p 로 접속합니다.
    • 이 때 root 는 아직 password 가 설정되지 않은 상태이므로 password 를 설정해야 합니다.
      • OS cli 로 나와 mysql_secure_installation 명령어를 실행하여 각 설정을 해줍니다.
      • 혹은 alter user 'root'@'localhost' identified by '{NEW_PASSWORD}'; 로 설정합니다.

 

Galera Cluster 설치

  • yum install galera rsync 로 galera 와 rsync 를 설치합니다.
    • rsync 는 상태 전송 (데이터를 동기화) 하는 도구입니다.
    • galera 와 rsync 는 MariaDB 패키지에 포함되어 있으므로 이미 설치되어 있을 수도 있습니다.
  • 이후 galera 실행을 위한 설정 파일을 작성합니다.
galera 설정파일
    [mysqld]
    
    # (This must be substituted by wsrep_format)
    binlog_format=ROW
    
    # Currently only InnoDB storage engine is supported
    default-storage-engine=innodb
    
    # to avoid issues with 'bulk mode inserts' using autoinc
    innodb_autoinc_lock_mode=2
    
    # Override bind-address
    # In some systems bind-address defaults to 127.0.0.1, and with mysqldump SST
    # it will have (most likely) disastrous consequences on donor node
    bind-address=0.0.0.0
    
    ##
    ## WSREP options
    ##
    
    # Enable wsrep
    wsrep_on=1
    
    # Full path to wsrep provider library or 'none'
    wsrep_provider=/usr/lib64/galera/libgalera_smm.so
    
    # Provider specific configuration options
    #wsrep_provider_options=
    
    # Logical cluster name. Should be the same for all nodes.
    wsrep_cluster_name="galera_cluster"
    
    # Group communication system handle
    wsrep_cluster_address="gcomm://192.168.10.10, 192.168.10.11, 192.168.10.12"
    
    #wsrep_cluster_address="gcomm://"
    # Human-readable node name (non-unique). Hostname by default.
    wsrep_node_name="node1"
    
    # Base replication <address|hostname>[:port] of the node.
    # The values supplied will be used as defaults for state transfer receiving,
    # listening ports and so on. Default: address of the first network interface.
    wsrep_node_address="192.168.10.10"
    
    # Address for incoming client connections. Autodetect by default.
    #wsrep_node_incoming_address=
    
    # How many threads will process writesets from other nodes
    wsrep_slave_threads=1
    
    # DBUG options for wsrep provider
    #wsrep_dbug_option
    
    # Generate fake primary keys for non-PK tables (required for multi-master
    # and parallel applying operation)
    wsrep_certify_nonPK=1
    
    # Maximum number of rows in write set
    wsrep_max_ws_rows=0
    
    # Maximum size of write set
    wsrep_max_ws_size=2147483647
    
    # to enable debug level logging, set this to 1
    wsrep_debug=0
    
    # convert locking sessions into transactions
    wsrep_convert_LOCK_to_trx=0
    
    # how many times to retry deadlocked autocommits
    wsrep_retry_autocommit=1
    
    # change auto_increment_increment and auto_increment_offset automatically
    wsrep_auto_increment_control=1
    
    # retry autoinc insert, which failed for duplicate key error
    wsrep_drupal_282555_workaround=0
    
    # enable "strictly synchronous" semantics for read operations
    wsrep_causal_reads=0
    
    # Command to call when node status or cluster membership changes.
    # Will be passed all or some of the following options:
    # --status  - new status of this node
    # --uuid    - UUID of the cluster
    # --primary - whether the component is primary or not ("yes"/"no")
    # --members - comma-separated list of members
    # --index   - index of this node in the list
    wsrep_notify_cmd=
    
    ##
    ## WSREP State Transfer options
    ##
    
    # State Snapshot Transfer method
    wsrep_sst_method=rsync
    
    # Address which donor should send State Snapshot to.
    # Should be the address of THIS node. DON'T SET IT TO DONOR ADDRESS!!!
    # (SST method dependent. Defaults to the first IP of the first interface)
    #wsrep_sst_receive_address=
    
    # SST authentication string. This will be used to send SST to joining nodes.
    # Depends on SST method. For mysqldump method it is root:<root password>
    wsrep_sst_auth=root:
    
    # Desired SST donor name.
    #wsrep_sst_donor=
    
    # Reject client queries when donating SST (false)
    #wsrep_sst_donor_rejects_queries=0
    
    # Protocol version to use
    # wsrep_protocol_version=
  • 첨부한 파일은 galera cluster 의 실행을 돕기위한 설정파일입니다.
    • 위 파일의 위치는 /etc/my.cnf.d/galera.cnf 혹은 다른 cnf 파일에 추가하여도 무관합니다.
  • wsrep_cluster_address, wsrep_node_name, wsrep_node_address 를 현재 환경에 맞게 변경해야합니다.
    • wsrep_cluster_address 에 가장 먼저 위치한 node 가 donor 입니다.
    • donor 는 특별한 명령어로 실행되므로 아래에서 설명합니다.
  • wsrep_providerfind / -name libgalera_smm.so 명령어를 통해 dir 를 찾아 기입합니다.
  • 참고
    • galera 는 상태 전송을 위해 Maria / MySQL DB default 3306 포트 이외 추가 3개를 사용합니다.
    • 4444, 4567, 4568
    • 따라서, 해당 포트에 방화벽 설정을 해제해야 합니다.

 

Galera Cluster 실행

  • wsrep_cluster_address 에 가장 먼저 위치한 node 를 galera_new_cluster 명령어로 실행합니다.
    • 위처럼 실행된 node 는 Donor 입니다.
      • Donor 는 Cluster 에 상태를 전파하는 node 입니다.
      • 데이터의 전송은 각 노드가 노드에게로 이뤄지지만 SST 즉, 새로운 노드가 참여하거나 큰 데이터를 전송해야 할 필요가 있을 때에는 Donor 가 수행합니다.
      • 다만 Donor 는 운영 중에 가변적으로 변경되며 show status like 'wsrep_local_index'; 로 검색했을 때 가장 낮은 index 를 갖는 node 가 Donor 입니다.
    • 다른 노드들(Joiner) 는 systemctl start mariadb.service 로 실행합니다.
  • show status like 'wsrep_%size'; 로 clustering 이 잘 되었는지 확인합니다.
    • 만약 wsrep_cluster_size 가 연결한 노드의 수만큼 보여진다면, 정상적으로 clustering 이 완료된 것입니다.
    • 혹은 database, table 등을 만들어 함께 연동되는지 확인할 수 있습니다.

 

Galera Cluster 중지

  • galera cluster 는 구성이 쉬운 만큼 관리하기 까다롭습니다.
  • 항상 graceful 하게 종료해야 되나 (systemctl stop mariadb.service), 동일한 명령어를 기입했음에도 그렇지 못한 경우들이 있습니다.
    • graceful 하지 못하게 종료된 경우를 판단하는 방법은 다음과 같습니다.
    • 아래는 /var/lib/mysql/grastate.dat 파일입니다.
      # GALERA saved state
      version: 2.1
      uuid:    00000000-0000-0000-0000-000000000000
      seqno:   -1
      safe_to_bootstrap: 0
    • /var/lib/mysql/grastate.dat 파일은 현재 node 의 clustering 현황을 보여줍니다.
    • galera cluster 는 uuid 를 통해 각 node 를 특정하고, seqno 를 사용하여 진행된 transaction 을 판단합니다.
    • 이때 seqno 가 -1 이라는 것은 실행중인 경우이나, 실제로 node가 종료된 상황이라면 에러가 난 상황이라고 판단할 수 있습니다.
    • 위와같이 에러가 난 상황에는 galera_recovery 를 사용하여 에러 핸들링을 시도할 수 있습니다.
      • 위 명령어는 마지막으로 실행했다고 판단하는 위치로 seqno를 되돌려 줍니다.
      • 만약 이 방법으로도 되돌려지지 않는다면 mysql 을 새로 설치하여 clustering 을 하는 방법이 빠릅니다.

 

Galera Cluster 재기동

  • galera cluster 는 전체를 down 시킨 후 전체를 재기동 시키는 것을 권장하지 않습니다.
    • Active / Active 구조이기 때문에 어떤 것이든 master / donor 가 될 수 있습니다.
    • 따라서 재기동을 할 때에는 단순히 systemctl start mariadb.service 로 기존 cluster 에 편입시키면 됩니다.
    • 다만, 이때 galera.cnfwsrep_cluster_address 의 맨 앞에 자신의 host 가 와서는 안됩니다.
    • 위에서 설명했듯, donor 가 가장 맨 앞에 위치하지만 뒤늦게 편입되는 node 는 donor 가 될 수 없기 때문입니다.
    • 따라서 재기동을 위해서 맨 앞에 위치한 해당 node 의 host 순서를 무작위로 위치시키기만 하면 됩니다.
  • 그럼에도 불구하고 전체 cluster 를 down 시킨 후 재기동 해야 한다면
    • 각 노드의 grastate.dat 파일의 seqno 를 확인합니다.
    • 여기에서 확인된 seqno 가 가장 높은 node 가 donor 가 되어야 합니다.
    • 따라서 확인된 노드 중 가장 높은 seqno 를 가지고 있는 노드를 wsrep_cluster_address 의 맨 앞에 위치시킵니다.
    • 이후 앞서 살펴봤듯이 donor 는 galera_new_cluster 로, joiner 는 systemctl start mariadb.service 로 실행시킵니다.

 

참고 - 성능을 위한 설정

[mysqld]
# 백업 서버를 위해 설정한 옵션, 백업하며 최대 네트워크 송수신할 수 있는 크기 정의
# 최대값 1GB, 필요에 따라 줄일 수 있음
max_allowed_packet = 1GB

# Transaction이 Commit 되었을 때 redo log 를 어떻게 flush 할지 결정 
# buffer pool - log buffer - OS buffer - Disk (redo log)
# 0 : 1초 주기로 log 를 디크스로 flush
# 1 : transaction 이 커밋될 때마다 로그를 디스크로 flush
# 2 : transaction 이 커밋될 때마다 OS Buffer 로 flush (OS Buffer 가 1초 주기로 Disk 에 flush)
# 우리 서버는 Galera cluster 로 Multi Master 이기 때문에 0으로 설정
innodb_flush_log_at_trx_commit=0

[galera]
# write set을 쓰는 back ground thread 설정
# 물리적 코어의 1 또는 2배수 권장
# 우리 서버는 api 서버들과 함께 돌기 때문에 절반으로 설정
wsrep_slave_thread=7

# SST -> IST를 위한 galera cache 설정
wsrep_provider_options="gcache.size=2G;gcache.recover=yes"

# sync 방식을 rsync -> mariabackup 으로 변경
wsrep_sst_method=mariabackup
  • galera cluster 는 데이터를 동기화할 때 실제로는 반동기식으로 작동합니다.
    • 인증 이라는 절차를 통해 우선 데이터들을 PK를 사용해서 확인하고 commit 을 background thread에 요청한 후 다른 MariaDB Server 에 데이터 복제 요청을 합니다.
      • 따라서 데이터만 확인하여 sync 가 됐다고 판단하고 실제 data flush 는 비동기적으로 이뤄지게 됩니다.
    • 또한 이 데이터를 확인할 때에는 first committer wins 이라는 규칙을 따릅니다.
      • 같은 PK 로 들어온 데이터에 대해 X 락을 설정하면서, 먼저 commit 한 node 의 데이터를 받아들이겠다는 정책입니다.
      • 먼저 commit 한 node 의 데이터는 받아들이면서, 나중에 들어온 데이터에 대해서는 deadlock 을 발생시킵니다.
      • 만약 PK 를 A.I. 로 사용하고 있다면 Insert 시에는 발생 확률이 낮지만 여전히 Udate, Delete 시 deadlock 발생 확률이 있습니다.
      • 이를 회피하고 성능을 위해 IST 방식을 적극적으로 사용해야 합니다..
  • 상태 전송 방식
    • SST
      • 파일 (.idb, .frm) 을 직접 주고 받는 방식입니다.
        • 파일을 받아 db 에 적용하는 방식으로 진행합니다.
      • 다만 성능을 위해 회사에서는 mariabackup 을 사용하고 있는데, mariabackup 의 경우 GCache 를 적극적으로 사용하며 SST 를 하므로 운용상 유의가 필요합니다.
    • IST
      • GCache 라는 galera 특유의 cache 에 Write-Set(데이터를 동기화할 때 주고받는 형식)을 저장하면서 동기화를 수행합니다.
      • 차후 GCache 에 저장된 ws 에 대해서는 데이터 동기화가 필요한 시점에 local 에 있는 GCache 를 먼저 조회해 변경된 사항이 있는지 판단합니다.
      • 변경된 사항이 있다면 파일 자체를 주고 받지 않고, 변경된 데이터에 대해서만 동기화를 진행합니다.

 

끝!

Comments