
OS Rocky Linux 9 계열이며 RAM 약 1.7GB, Swap 4GB DB 전용 서버를 이용하고 있습니다.
개발 서버 용도로는 해당 사양이면 크게 문제가 되지 않습니다.
설정 최적화의 목표는?
메모리 초과와 스왑 남용 방지와 전원 장애 등 비정상 종료에도 데이터 무결성 유지, 낮은 CPU 부하에서 안정적 TPS 확보, 운영 중 모니터링과 원인 분석이 쉬운 상태 유지를 위해서 입니다. 먼저 설정 파일을 먼저 보여 드리겠습니다.
[mysqld] # 기본 datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock log-error=/var/log/mariadb/mariadb.log pid-file=/run/mariadb/mariadb.pid # 스토리지/디스크 default-storage-engine = InnoDB innodb_file_per_table = 1 innodb_flush_method = O_DIRECT innodb_flush_neighbors = 0 innodb_doublewrite = 1 # 메모리 / 캐시 innodb_buffer_pool_size = 768M innodb_buffer_pool_instances = 1 innodb_log_file_size = 128M innodb_log_buffer_size = 16M innodb_flush_log_at_trx_commit = 2 tmp_table_size = 64M max_heap_table_size = 64M # 커넥션 / 스레드 max_connections = 80 thread_cache_size = 32 table_open_cache = 512 open_files_limit = 65535 skip-name-resolve # Per-connection 버퍼 sort_buffer_size = 2M read_buffer_size = 1M read_rnd_buffer_size = 2M join_buffer_size = 2M # 쿼리 캐시 비활 query_cache_type = 0 query_cache_size = 0 # 느린 쿼리 로그 slow_query_log = 1 slow_query_log_file = /var/log/mariadb/slow.log long_query_time = 2 # 트랜잭션/인덱스 transaction_isolation = READ-COMMITTED innodb_adaptive_hash_index = 0 # 문자셋 character-set-server = utf8mb4 collation-server = utf8mb4_general_ci skip-character-set-client-handshake # 메모리 절약 performance_schema = OFF
왜 이렇게 설정했는가
스토리지와 무결성
- innodb_file_per_table
테이블 단위로 파일을 분리해 공간 회수와 백업 관리가 쉬워진다.
- innodb_flush_method O_DIRECT
OS 페이지 캐시 중복을 줄여 예측 가능한 I O를 확보한다.
- innodb_flush_neighbors 0
SSD 가정, 인접 페이지 동기화 비활로 불필요한 쓰기를 줄인다.
- innodb_doublewrite 1
전원 장애나 커널 패닉 시 데이터 손상 확률을 크게 낮춘다. 작은 서버일수록 필수에 가깝다.
메모리 예산과 캐시
- innodb_buffer_pool_size 768M
전체 RAM 대비 약 45%로 설정. 데이터셋이 커도 OOM을 방지하는 보수적 값이다.
- innodb_buffer_pool_instances 1
버퍼풀이 1GB 미만이면 1개가 잠금 경합과 내부 단편화를 줄인다.
- innodb_log_file_size 128M, log_buffer_size 16M
잦은 체크포인트로 쓰기 폭주를 피하면서 장애 복구 시간도 과하게 늘리지 않는다.
- innodb_flush_log_at_trx_commit 2
성능과 안전성의 절충. 최악의 경우 최근 1초 이내 트랜잭션 손실을 감수하는 대신 TPS가 안정된다.
- tmp_table_size, max_heap_table_size 64M
큰 임시 테이블이 디스크로 떨어지는 것을 완화하면서도 메모리 폭주를 막는다.
연결 수와 per-connection 버퍼
- max_connections 80
per-connection 버퍼 누적으로 인한 메모리 폭탄을 방지. 실제 동접이 낮다면 더 낮춰도 좋다.
- sort, join, read, read_rnd 버퍼를 1~2M로 축소
각 연결마다 필요 시 할당되므로 합계가 중요하다. 보수적으로 잡아 폭주에 대비한다.
- thread_cache_size 32
스레드 재사용으로 연결 빈도가 높아도 CPU 낭비를 줄인다.
- skip-name-resolve
DNS 역조회 제거. 연결 지연 원인을 근본 차단한다.
분석과 유지보수
- query cache 비활성
InnoDB에서는 효과가 낮고 경합을 유발한다.
- slow query log, long_query_time 2s
문제 쿼리를 파일로 남겨 원인 파악 시간을 줄인다.
- performance_schema OFF
아주 작은 서버에서 수십 MB 이상을 아낀다. 상세 계측이 필요할 때만 켠다.
문자셋
- utf8mb4, utf8mb4_general_ci
4바이트 문자를 안전하게 처리. 정렬은 일반적 한국어 서비스에 충분한 general_ci로 선택.
대략적인 메모리 예산
- InnoDB 버퍼풀 768M
InnoDB 기타 구조와 로그 수십 MB
- OS 캐시와 데몬 수백 MB
- per-connection 버퍼
최악 가정치 7M 내외 × 동시 N
동접 40이면 약 280M 수준
- 총합이 1.7GB 내에서 안전하게 움직이도록 구성
적용 절차
변경 후 일반 재 시작으로 충분하다.
단, innodb_log_file_size 값을 바꿨다면 한 번은 정지 후 기존 로그 파일을 지우고 시작한다.
실제 워크로드에서 동접이 급등하면 일시적으로 스왑이 일부 사용될 수 있으나, 버퍼 크기를 보수적으로 잡아 OOM 위험을 낮췄다.
systemctl stop mariadb rm -f /var/lib/mysql/ib_logfile0 /var/lib/mysql/ib_logfile1 systemctl start mariadb
사후 점검 체크리스트
현재 값과 상태를 확인한다.
SHOW VARIABLES WHERE Variable_name IN ( 'innodb_buffer_pool_size','innodb_log_file_size', 'max_connections','tmp_table_size','max_heap_table_size', 'sort_buffer_size','join_buffer_size', 'read_buffer_size','read_rnd_buffer_size', 'innodb_flush_log_at_trx_commit','innodb_doublewrite' ); SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool%'; SHOW GLOBAL STATUS LIKE 'Threads_connected'; SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';
권장 관찰 포인트
- 버퍼풀 히트율
- Created tmp disk tables가 과도하게 늘어나는지
- 스왑 사용량이 지속적으로 증가하는지
- 슬로우 로그에 반복적으로 등장하는 쿼리
운영 팁
- 동접이 낮으면 max_connections을 더 낮춰 메모리 여유를 확보
- 특정 시간대에만 느리면 인덱스 점검과 쿼리 리라이트 우선
- 백업 스케줄과 ANALYZE TABLE, OPTIMIZE TABLE은 피크 시간대를 피한다
롤백과 안전장치
- 성능 문제 발생 시 per-connection 버퍼를 한 단계 더 낮춘다
- 데이터 손상 조짐 또는 비정상 종료가 잦다면 innodb_flush_log_at_trx_commit 1로 상향
- performance_schema는 분석 시에만 일시적으로 켠다