MySQL Operator 라는 생소한 친구가 있었다.
요즘 모두가 울부짖는 고가용성(HA, High Availability)을 위해 InnoDB Cluster가 나왔고, 이 클러스터를 더 편하게 운영하기 위해 MySQL Operator가 나왔다.
마지막 근무했던 회사는 DB팀이 있어서 DB관리가 개발자의 영역이 아니었기 때문에 테이블 설계, 쿼리 생성할 때 DB팀의 검토를 받고 진행 되었다.
개발자 입장에서 보면 상당히 편하지만 그만큼 DB 기술 발전에 둔감해졌고, 이런 기능이 있다는 것을 이번에 구축하며 처음 알게됐다.
이번에 알게된 내용과 한참을 고생시킨 문제를 기록한다.
InnoDB Cluster
고가용성을 위한 MySQL 서버를 구성하는 방법이다. MySQL 5.7 버전부터 사용 가능하다고 한다. 처음에 나는 이것이 master-slave replication 이라고 생각했는데, 엄연히 다른 개념으로 봐야 맞다.
사용되는 방법은 상당히 유사하지만 가장 큰 차이점은 자동 장애 조치(Failover) 지원 유무이다.
master-slave replication의 경우 master의 장애가 발생 할 경우 사람이 달라 붙어 slave를 master로 사용하도록 하거나, master 노드를 복구해야만 한다. InnoDB Cluster 의 경우 primary 의 장애가 발생했을 때, secondary가 자동으로 primary로 선출되어 장애를 자동으로 극복한다.
물론 primary 에서 장애가 발생 했다는 것은 높은 확률로 많은 트래픽에 의해서 발생한 것일테니, 서버 한대가 빠진 마당에 자동 복구가 되어도 다시 장애가 발생 할 가능성이 높겠지만. 트래픽에 의한 장애가 아닐 경우 이런 자동 복구 기능은 고가용성에 필수적 요소이다.
항목 | Master-Slave Replication | InnoDB Cluster |
---|---|---|
구조 | Master와 다수의 Slave로 구성 | Primary와 다수의 Secondary로 구성 |
복제 방식 | 비동기 복제 (Asynchronous Replication) | 동기 복제 (Synchronous) 또는 반동기 복제 (Semi-Synchronous) |
고가용성 (HA) | 수동 장애 조치 (관리자가 수동으로 처리) | 자동 장애 조치 (Failover) 지원 |
읽기 확장성 | 다수의 Slave를 통해 읽기 확장 가능 | Secondary 노드를 통해 읽기 확장 가능 |
쓰기 확장성 | Master 노드에서만 쓰기 가능 (한계 있음) | 다중 Primary 구성을 통해 쓰기 확장 가능 |
자동 장애 복구 | 없음, 수동으로 Slave를 승격해야 함 | Primary 노드 장애 시 자동으로 새로운 Primary로 승격 |
일관성 | 데이터 일관성이 약함 (복제 지연 발생 가능) | 강한 일관성 보장 (동기화된 데이터 복제) |
데이터 유실 가능성 | Master 장애 시 일부 데이터 유실 가능성 있음 | 동기 복제를 통해 데이터 유실 최소화 |
구성 복잡도 | 비교적 간단 | 다소 복잡 (Group Replication, MySQL Router 등) |
읽기 및 쓰기 처리 | Master(읽기/쓰기), Slave(읽기) | Primary(읽기/쓰기), Secondary(읽기) |
장애 조치 시간 | 관리자가 개입해야 하므로 장애 조치에 시간이 소요됨 | 자동 장애 조치로 신속한 복구 가능 |
데이터 충돌 관리 | 충돌 관리 필요 없음 (Master가 유일한 쓰기 노드) | 다중 Primary 구성 시 충돌 관리 필요 |
MySQL Operator
Kubernetes 내에서 운영되는 MySQL InnoDB Cluster를 운영하기 위해 존재하는 친구이다.
많은 곳에서 설명한 자료를 보면 공통적인 부분은 ‘Operator Pattern 을 따른다’ 는 것.
이놈의 패턴이라는 용어는 전방위로 사용되는데 대략 ‘자주 발생하는 문제에 대한 재사용 가능한 해결 방법’ 정도로 받아 들이면 된다.
문제가 있을 때 대략 이런 파훼법이 있다는 것을 앞선 개발자가 경험하고, 해결하기 위해 범용적으로 적용 가능한 솔루션이라고 봐도 될듯 싶다.
이 패턴이라는 것이 대단히 복잡한 것은 아니고, 아주 후려쳐서 얘기하면
운영자가 설정한 특정 상태를 저장해놓고, 이 상태가 잘 유지되고 있는지 계속 감시하는 놈(Operator)이 있다.
감시하다가 문제가 생겼다고 판단하면 잽싸게 최초 설정된 상태를 유지하기 위해 고용된 이 감시하는 놈이 있는 것 자체를 Operator 패턴이라고 한다.
Kubernetes 자체에서도 컨트롤러, kubelet이 서비스의 상태를 감지하고 문제가 발생하면 파드를 재시작 한다던가, 사용량을 보고 파드의 수를 조절하는 기본적인 관리가 된다.
하지만 우리가 원하는건 좀 더 우아한 기능으로 감시자 하나를 추가로 고용한 것이다.
Primary에 장애가 나면 Secondary를 승격하거나, 데이터 일관성을 유지하거나 하는 좀 더 고급 기능을 수행한다. 마치 기성복과 맞춤복 같은 느낌이랄까.
눈물겨운 설치 과정
정상 동작을 하도록 설치하는데 꼬박 3일이 걸렸다.
설치 방법은 수도 없이 많은 곳에 널려있고, 내 뒤엔 GPT 형님과 클로드 형님도 있거늘. 무엇이 문제였던가?
설치 방법
MySQL 오퍼레이터 설치
# MySQL 오퍼레이터 Helm 저장소 추가
helm repo add mysql-operator <https://mysql.github.io/mysql-operator/>
helm repo update
# MySQL 오퍼레이터 설치
helm install mysql-operator mysql-operator/mysql-operator \\
--namespace mysql-operator --create-namespace
Custom Resource
apiVersion: mysql.oracle.com/v2
kind: InnoDBCluster
metadata:
name: mysql-cluster
namespace: mysql-cluster
spec:
secretName: mypwds
tlsUseSelfSigned: true
instances: 3
version: 9.1.0
router:
instances: 1
version: 9.1.0
datadirVolumeClaimTemplate:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: local-storage
volumeMode: Filesystem
mycnf: |
[mysqld]
authentication_policy=mysql_native_password
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
default-time-zone='+09:00'
innodb_buffer_pool_size=1G
innodb_file_per_table=1
innodb_flush_log_at_trx_commit=1
innodb_flush_method=O_DIRECT
max_connections=100
max_user_connections=40
wait_timeout=600
interactive_timeout=600
위에서 사용 할 mypwds Secret 생성
kubectl create secret -n kwt-dev generic mypwds \\
--from-literal=rootUser=root \\
--from-literal=rootHost=% \\
--from-literal=rootPassword="password"
과도한 형님 의존
너무 믿었다. 형님들이 잘 해결해주리라는 믿음이 과했던 나머지, 처음부터 차근차근 짚고 생각하지 않았다.
2024-11-03T06:16:03.039436Z 1 [Note] [MY-010006] [Server] Using data dictionary with version '90000'.
mysqld: Table 'mysql.plugin' doesn't exist
2024-11-03T06:16:03.043256Z 0 [ERROR] [MY-010735] [Server] Could not open the mysql.plugin table. Please perform the MySQL upgrade procedure.
2024-11-03T06:16:03.046329Z 0 [Warning] [MY-010441] [Server] Failed to open optimizer cost constant tables
2024-11-03T06:16:03.047803Z 0 [Warning] [MY-010441] [Server] Failed to open optimizer cost constant tables
2024-11-03T06:16:03.051836Z 0 [Note] [MY-011332] [Server] Plugin mysqlx reported: 'IPv6 is available'
2024-11-03T06:16:03.054390Z 0 [Note] [MY-011323] [Server] Plugin mysqlx reported: 'X Plugin ready for connections. bind-address: '::' port: 33060'
2024-11-03T06:16:03.054494Z 0 [Note] [MY-011323] [Server] Plugin mysqlx reported: 'X Plugin ready for connections. socket: '/var/run/mysqld/mysqlx.sock''
2024-11-03T06:16:03.082090Z 0 [Note] [MY-010902] [Server] Thread priority attribute setting in Resource Group SQL shall be ignored due to unsupported platform or insufficient privilege.
2024-11-03T06:16:03.085056Z 0 [Note] [MY-010856] [Server] Failed to open the crashed binlog file when source server is recovering it.
2024-11-03T06:16:03.097017Z 0 [Note] [MY-013911] [Server] Crash recovery finished in binlog engine. No attempts to commit, rollback or prepare any transactions.
2024-11-03T06:16:03.097063Z 0 [Note] [MY-013911] [Server] Crash recovery finished in InnoDB engine. No attempts to commit, rollback or prepare any transactions.
2024-11-03T06:16:03.101546Z 0 [Note] [MY-012487] [InnoDB] DDL log recovery : begin
2024-11-03T06:16:03.101858Z 0 [Note] [MY-012488] [InnoDB] DDL log recovery : end
2024-11-03T06:16:03.102062Z 0 [Note] [MY-011946] [InnoDB] Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
2024-11-03T06:16:03.102785Z 0 [Note] [MY-011946] [InnoDB] Buffer pool(s) load completed at 241103 6:16:03
2024-11-03T06:16:03.105014Z 0 [Warning] [MY-010015] [Repl] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
2024-11-03T06:16:03.105331Z 0 [Note] [MY-012922] [InnoDB] Waiting for purge to start
2024-11-03T06:16:03.175308Z 0 [Warning] [MY-010015] [Repl] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
2024-11-03T06:16:03.177100Z 0 [Note] [MY-010182] [Server] Found ca.pem, server-cert.pem and server-key.pem in data directory. Trying to enable SSL support using them.
2024-11-03T06:16:03.179367Z 0 [Note] [MY-010304] [Server] Skipping generation of SSL certificates as certificate files are present in data directory.
2024-11-03T06:16:03.182931Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2024-11-03T06:16:03.182962Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2024-11-03T06:16:03.183324Z 0 [Note] [MY-010308] [Server] Skipping generation of RSA key pair through --sha256_password_auto_generate_rsa_keys as key files are present in data directory.
2024-11-03T06:16:03.183617Z 0 [Note] [MY-010308] [Server] Skipping generation of RSA key pair through --caching_sha2_password_auto_generate_rsa_keys as key files are present in data directory.
2024-11-03T06:16:03.185557Z 0 [Note] [MY-010252] [Server] Server hostname (bind-address): '*'; port: 3306
2024-11-03T06:16:03.185603Z 0 [Note] [MY-010253] [Server] IPv6 is available.
2024-11-03T06:16:03.185613Z 0 [Note] [MY-010264] [Server] - '::' resolves to '::';
2024-11-03T06:16:03.185625Z 0 [Note] [MY-010251] [Server] Server socket created on IP: '::'.
2024-11-03T06:16:03.187716Z 0 [Warning] [MY-010441] [Server] Failed to open optimizer cost constant tables
2024-11-03T06:16:03.187906Z 0 [ERROR] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-001146 - Table 'mysql.component' doesn't exist
2024-11-03T06:16:03.187925Z 0 [Warning] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-003543 - The mysql.component table is missing or has an incorrect definition.
2024-11-03T06:16:03.188047Z 0 [Warning] [MY-000067] [Server] unknown variable 'loose_group_replication_recovery_use_ssl=1'.
2024-11-03T06:16:03.189278Z 0 [ERROR] [MY-010326] [Server] Fatal error: Can't open and lock privilege tables: Table 'mysql.user' doesn't exist
2024-11-03T06:16:03.189328Z 0 [ERROR] [MY-010952] [Server] The privilege system failed to initialize correctly. For complete instructions on how to upgrade MySQL to a new version please see the 'Upgrading MySQL' section from the MySQL manual.
2024-11-03T06:16:03.189418Z 0 [ERROR] [MY-010119] [Server] Aborting
2024-11-03T06:16:03.190571Z 0 [Note] [MY-012330] [InnoDB] FTS optimize thread exiting.
2024-11-03T06:16:04.191663Z 0 [Note] [MY-010120] [Server] Binlog end
2024-11-03T06:16:04.194566Z 0 [Note] [MY-015019] [Server] MySQL Server: Plugins Shutdown - start.
2024-11-03T06:16:04.194620Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'auth_socket'
2024-11-03T06:16:04.194639Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'mysqlx'
2024-11-03T06:16:04.195625Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'mysqlx_cache_cleaner'
2024-11-03T06:16:04.195666Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'ngram'
2024-11-03T06:16:04.195681Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'BLACKHOLE'
2024-11-03T06:16:04.195699Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'ARCHIVE'
2024-11-03T06:16:04.195715Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'TempTable'
2024-11-03T06:16:04.195732Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'PERFORMANCE_SCHEMA'
2024-11-03T06:16:04.195850Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'MRG_MYISAM'
2024-11-03T06:16:04.195881Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'MyISAM'
2024-11-03T06:16:04.195910Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_SESSION_TEMP_TABLESPACES'
2024-11-03T06:16:04.195924Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_CACHED_INDEXES'
2024-11-03T06:16:04.195935Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_VIRTUAL'
2024-11-03T06:16:04.195961Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_COLUMNS'
2024-11-03T06:16:04.195975Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_TABLESPACES'
2024-11-03T06:16:04.195986Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_INDEXES'
2024-11-03T06:16:04.195995Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_TABLESTATS'
2024-11-03T06:16:04.196006Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_TABLES'
2024-11-03T06:16:04.196016Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_FT_INDEX_TABLE'
2024-11-03T06:16:04.196028Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_FT_INDEX_CACHE'
2024-11-03T06:16:04.196039Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_FT_CONFIG'
2024-11-03T06:16:04.196049Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_FT_BEING_DELETED'
2024-11-03T06:16:04.196059Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_FT_DELETED'
2024-11-03T06:16:04.196069Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_FT_DEFAULT_STOPWORD'
2024-11-03T06:16:04.196089Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_METRICS'
2024-11-03T06:16:04.196099Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_TEMP_TABLE_INFO'
2024-11-03T06:16:04.196109Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_BUFFER_POOL_STATS'
2024-11-03T06:16:04.196120Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_BUFFER_PAGE_LRU'
2024-11-03T06:16:04.196139Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_BUFFER_PAGE'
2024-11-03T06:16:04.196150Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_CMP_PER_INDEX_RESET'
2024-11-03T06:16:04.196160Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_CMP_PER_INDEX'
2024-11-03T06:16:04.196170Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_CMPMEM_RESET'
2024-11-03T06:16:04.196180Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_CMPMEM'
2024-11-03T06:16:04.196190Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_CMP_RESET'
2024-11-03T06:16:04.196200Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_CMP'
2024-11-03T06:16:04.196211Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'INNODB_TRX'
2024-11-03T06:16:04.196235Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'InnoDB'
2024-11-03T06:16:04.196316Z 0 [Note] [MY-013072] [InnoDB] Starting shutdown...
2024-11-03T06:16:04.197213Z 0 [Note] [MY-011944] [InnoDB] Dumping buffer pool(s) to /var/lib/mysql/ib_buffer_pool
2024-11-03T06:16:04.197631Z 0 [Note] [MY-011944] [InnoDB] Buffer pool(s) dump completed at 241103 6:16:04
2024-11-03T06:16:04.210337Z 0 [Note] [MY-013084] [InnoDB] Log background threads are being closed...
2024-11-03T06:16:04.751315Z 0 [Note] [MY-013854] [InnoDB] Bytes written to disk by DBLWR (ON): 671744
2024-11-03T06:16:04.751886Z 0 [Note] [MY-012980] [InnoDB] Shutdown completed; log sequence number 9457587
2024-11-03T06:16:04.753934Z 0 [Note] [MY-012255] [InnoDB] Removed temporary tablespace data file: "ibtmp1"
2024-11-03T06:16:04.753973Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'MEMORY'
2024-11-03T06:16:04.753983Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'CSV'
2024-11-03T06:16:04.753991Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'daemon_keyring_proxy_plugin'
2024-11-03T06:16:04.754012Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'sha2_cache_cleaner'
2024-11-03T06:16:04.754019Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'caching_sha2_password'
2024-11-03T06:16:04.754028Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'sha256_password'
2024-11-03T06:16:04.754788Z 0 [Note] [MY-010733] [Server] Shutting down plugin 'binlog'
2024-11-03T06:16:04.754816Z 0 [Note] [MY-015020] [Server] MySQL Server: Plugins Shutdown - end.
2024-11-03T06:16:04.755458Z 0 [Note] [MY-015021] [Server] MySQL Server: Components Shutdown - start.
2024-11-03T06:16:04.756532Z 0 [Note] [MY-015022] [Server] MySQL Server: Components Shutdown - end (with return value = 0).
2024-11-03T06:16:04.756643Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 9.1.0) MySQL Community Server - GPL.
2024-11-03T06:16:04.756651Z 0 [System] [MY-015016] [Server] MySQL Server - end.
나를 지독하게 괴롭혔던 친구.
Q. 형님. 뭐가 문제입니까?
A. 이렇게 바꿔보거라~
무지하게 바꾸고 재설치를 진행했지만 결국 돌고 돌아 같은 오류가 반복되었다. 또는 형님이 알려준 설정 자체가 맞지 않는 경우도 자주 발생했다.
버전이 문제더라
혹시나 하는 마음에 8.0.40 버전의 안정화된 MySQL은 제대로 동작하지 않을까? 싶어 설치해봤다.
여태까지 무슨 일이 있었냐는 듯 설치가 되어버렸다.
형님들이랑 수 없이 떠들고 구글링 했던 시간이 주마등처럼 스처가며 허무함이 몰려왔다.
이걸 쓰는 시점에 버전에 따른 버그인지는 확실하지 않다. 이렇게 쉽게 해결될 문제를 3일간 괴로워하며 똑같은 작업을 반복했던 자신에게 화날 뿐.
고민했던 포인트
- MySQL 별도의 네임스페이스를 만들 것인가?
지금 만드는 서비스는 포트폴리오에 사용될 것이고 나 혼자 관리할 것이기에 네임스페이스를 많이 나눌 필요가 없다고 생각했다.
어플리케이션과 같은 네임스페이스를 공유하자. - Helm 차트를 이용해서 설치 할 것인가?
MySQL Operator 는 Helm차트를 이용해서 설치해도 문제가 없다고 생각했다. 특별히 별도의 설정을 하지 않아도 될 것으로 생각했기 때문.
InnoDB Cluster 는 manifest 설치를 선택했는데, 내가 원하는 설정으로 Stateful Set 을 설치해야 했기 때문이다. - Longhorn Storage Class를 이용할 것인가?
InnoDB Cluster는 이미 복제본을 여러 노드에 생성하기 때문에, 중복된 기능을 제공하는 분산 스토리지 솔루션을 굳이 이용할 필요가 없다고 생각됐다. 각 노드에 저장되는 Local Storage를 선택했다.