4. MySQL 아키텍처
4.1 MySQL 엔진 아키텍처
MySQL 서버는 크게 두 부분으로 나눌 수 있다.
- MySQL 엔진
- SQL 파싱, 최적화, 실행 계획 수립, 캐시 등 “쿼리 처리 로직” 담당
- 스토리지 엔진
- 실제 데이터를 디스크/메모리에서 읽고 쓰는 “저수준 데이터 처리” 담당
이 둘은 느슨하게 결합되어 있어서, 스토리지 엔진만 교체해도 특정 기능이나 특성을 바꿀 수 있다는 점이 MySQL의 큰 특징이다.
4.1.1 MySQL의 전체 구조
- 클라이언트 → MySQL 엔진 (파싱, 최적화, 실행) → 핸들러 API → 스토리지 엔진(InnoDB 등)
핵심 포인트
- 같은 SQL이라도 사용되는 스토리지 엔진에 따라 실제 데이터 처리 방식이 달라질 수 있다.
- MySQL 엔진은 스토리지 엔진의 존재를 “핸들러 인터페이스” 수준에서만 알고, 내부 구조는 알지 못한다.
4.1.2 MySQL 스레딩 구조
MySQL은 다중 프로세스가 아니라 단일 프로세스 + 다중 스레드 구조이다.
1) 포그라운드 스레드 (클라이언트 스레드)
- 클라이언트 커넥션당 최소 1개 스레드가 할당되는 구조
- 주요 역할
- 클라이언트로부터 SQL 요청 수신
- 요청된 쿼리 실행
- 결과를 클라이언트로 전송
- 스레드 캐시(Thread Cache)
- 커넥션이 종료될 때 스레드를 바로 종료하지 않고, 재사용을 위해 캐시에 보관
- 다음 접속이 들어오면 새로 스레드를 생성하는 대신 캐시에서 꺼내서 사용
- 스레드 생성/종료 비용 감소 → 성능 향상
2) 백그라운드 스레드
주로 InnoDB 스토리지 엔진에서 사용되며, 다음과 같은 작업을 담당한다.
- Insert Buffer(=Change Buffer) 병합
- 리두 로그를 디스크에 기록
- 버퍼 풀의 더티 페이지를 디스크로 플러시
- 디스크에서 데이터 페이지 읽어오기 (read thread)
- 잠금/데드락 감지
특히 중요한 스레드
- 로그 스레드: 리두 로그 버퍼 내용을 디스크의 리두 로그 파일로 기록
- 쓰기(write) 스레드: 버퍼 풀의 더티 페이지를 데이터 파일로 기록
스레드 수 조정 시 고려사항
- 너무 적게 잡으면 디스크 쓰기/읽기 처리 병목 발생
- 너무 많이 잡으면 스레드 간 경쟁과 컨텍스트 스위치 증가로 오히려 효율이 떨어질 수 있음
4.1.3 MySQL 메모리 할당 및 사용 구조
MySQL 서버의 메모리는 크게 두 가지로 나뉜다.
- 글로벌 메모리 영역
- 로컬 메모리 영역 (스레드별, 커넥션별)
1) 글로벌 메모리 영역
- 인스턴스(서버) 단위로 할당
- 대부분의 경우 1개 인스턴스에 1개만 존재 (필요시 여러 개도 가능하지만 보통 1개)
- 모든 스레드가 공유
- 대표적인 예
- InnoDB 버퍼 풀 (데이터/인덱스 캐시)
- InnoDB 어댑티브 해시 인덱스
- InnoDB 리두 로그 버퍼
- 테이블 캐시(Table Cache)
이 영역은 운영자가 설정값으로 크기를 조정한다.
잘못 크게 잡으면 OS와의 메모리 경쟁이 발생하고, 너무 작으면 빈번한 디스크 I/O가 발생한다.
2) 로컬 메모리 영역
- 각 포그라운드 스레드(클라이언트 커넥션)가 쿼리를 처리할 때 필요에 따라 사용하는 메모리
- 스레드별로 독립적이고, 다른 스레드와 공유하지 않는다.
- 종류
- 커넥션 버퍼, 결과 버퍼: 커넥션이 살아 있는 동안 유지
- 정렬 버퍼(sort buffer), 조인 버퍼(join buffer): 특정 쿼리 실행 시에만 할당
- 바이너리 로그 캐시
- 네트워크 버퍼
주의할 점
- 정렬이 많이 필요한 쿼리, 큰 조인이 많은 쿼리가 동시다발적으로 들어오면, 스레드별로 할당되는 sort/join 버퍼 때문에 전체 메모리 사용량이 폭증할 수 있다.
- 각 버퍼의 크기 × 동시 접속 수 = 최악의 경우 메모리 사용량이므로, 설정값을 너무 크게 잡지 않는 것이 중요하다.
4.1.4 플러그인 스토리지 엔진 모델
- MySQL은 구조적으로 스토리지 엔진을 플러그인 형태로 교체 가능하게 설계되어 있다.
- 사용자는 테이블 생성 시
ENGINE=InnoDB또는ENGINE=MyISAM같은 방식으로 스토리지 엔진을 선택할 수 있었다. - 이 외에도 인증, 감사, 암호 플러그인 등 많은 기능이 플러그인으로 제공된다.
장점
- 특정 워크로드(OLTP, DW 등)에 최적화된 스토리지 엔진을 선택 가능
- 필요 시 사용자 정의 스토리지 엔진 개발도 가능
4.1.5 컴포넌트
플러그인 모델의 단점을 보완하기 위해 도입된 아키텍처이다.
플러그인의 문제점
- 플러그인끼리 직접 통신하기 어렵다.
- 플러그인 간 의존성 관리가 불편하다.
- 초기화 순서, 종료 순서 관리가 복잡하다.
컴포넌트의 특징
- 컴포넌트 간 함수 호출 및 데이터 공유가 가능하다.
- 보다 엄격한 인터페이스와 의존성 관리를 제공한다.
- 향후 MySQL 기능 확장은 플러그인보다 컴포넌트 기반으로 가는 추세이다.
4.1.6 쿼리 실행 구조
SQL 처리 단계는 다음과 같이 정리할 수 있다.
- 쿼리 파서(Parser)
- 전처리기(Preprocessor)
- 옵티마이저(Optimizer)
- 실행 엔진(Execution Engine)
- 핸들러(Handler, 스토리지 엔진)
4.1.6.1 쿼리 파서
- SQL 문자열을 토큰(token) 단위로 분해한다.
- 이를 바탕으로 파스 트리(parse tree)를 생성한다.
- 이 단계에서 문법 오류(syntax error)를 검출한다.
예시
SELEC * FROM→ 키워드 자체 오타로 인해 문법 오류 발생
4.1.6.2 전처리기
- 파서 단계에서 만들어진 파스 트리를 바탕으로 구조적 검증 수행
- 참조하는 테이블이 실제 존재하는지
- 참조하는 칼럼이 테이블에 존재하는지
- 권한이 있는지 (SELECT, INSERT, UPDATE 등)
- 객체 이름 해석(스키마명, 별칭 등)도 이 단계에서 수행
예시
- 존재하지 않는 컬럼명, 테이블 명 → 전처리기에서 오류
4.1.6.3 옵티마이저
- 쿼리를 “가장 적은 비용”으로 실행할 방법을 찾는 모듈이다.
- 가능한 실행 계획들을 평가한 뒤, 그 중 비용이 가장 낮은 계획을 선택한다.
- 고려 요소
- 사용할 인덱스 선택
- 조인 순서 결정
- 조인 방식(Nested Loop, Block Nested Loop 등)
- 드리븐 테이블, 드라이빙 테이블 결정
- LIMIT 최적화 등
MySQL은 기본적으로 비용 기반 옵티마이저(CBO)를 사용한다.
4.1.6.4 실행 엔진
- 옵티마이저가 만든 실행 계획을 순서대로 수행하는 모듈
- “테이블 A의 인덱스 X를 스캔해서 행을 하나씩 읽어라” 같은 요청을 스토리지 엔진에 보낸다.
- 스토리지 엔진에서 받은 결과를 조합하고, 조인 조건, WHERE 조건 등을 적용한 후 클라이언트로 결과를 반환한다.
4.1.6.5 핸들러(스토리지 엔진)
- MySQL 엔진과 스토리지 엔진 사이의 인터페이스
- 실행 엔진은 핸들러를 통해 “레코드 읽기/쓰기/잠금”을 요청한다.
- 예:
- InnoDB: 레코드 기반 잠금, 버퍼 풀, MVCC 지원
- MyISAM: 테이블 단위 잠금만 지원
4.1.7 복제(Replication)
- MySQL에서 고가용성, 읽기 부하 분산, 백업 목적 등으로 가장 많이 사용되는 기능이다.
- 기본적인 구조
- 소스(마스터) 서버: 변경 내용을 바이너리 로그에 기록
- 리플리카 서버: 바이너리 로그를 읽어 적용
- 복제 방식
- 비동기 복제 (기본)
- 반동기(semi-sync) 복제
- GTID 기반 복제 등
4.1.8 쿼리 캐시
- 한 번 실행된 쿼리의 결과를 메모리에 캐시한다.
- 동일한 SQL 문장이 들어오면 실행 없이 바로 결과를 반환한다.
- 그러나 테이블에 변경이 일어나면 해당 테이블과 관련된 캐시가 모두 무효화되는 구조였기 때문에, 동시성이 높은 환경에서 오히려 병목이 발생했다.
- 이러한 이유로 MySQL 8.0에서는 완전히 제거되었다.
4.1.9 스레드 풀
- 클라이언트 커넥션마다 스레드를 1:1로 쓰는 대신, 제한된 개수의 스레드 풀로 작업을 처리하는 구조
- 장점
- CPU 코어별로 스레드 수를 제한해 컨텍스트 스위치 감소
- 과도한 스레드 생성으로 인한 리소스 낭비 방지
- 일반적으로 CPU 코어 수와 스레드 풀 그룹 수를 비슷하게 맞추는 것이 권장된다.
- MySQL Enterprise Edition에서 공식 제공되며, Percona Server에서는 플러그인 형태로 구현되어 있다.
4.1.10 트랜잭션 지원 메타데이터
- MySQL 5.7까지:
- 테이블 구조, 스토어드 프로시저 등 메타데이터를 파일 기반(.frm 등)으로 관리
- DDL 작업 자체가 트랜잭션이 아니어서, 비정상 종료 시 메타데이터와 실제 데이터 간 불일치 발생 가능 (테이블 깨짐 등)
- MySQL 8.0부터:
- 메타데이터를 InnoDB 테이블에 저장
- DDL 작업도 트랜잭션에 의해 관리 가능
- 서버 크래시 후 재시작 시에도 메타데이터 일관성 보장
4.2 InnoDB 스토리지 엔진 아키텍처
InnoDB는 MySQL에서 기본 스토리지 엔진이며, 트랜잭션, 외래 키, MVCC, 레코드 기반 잠금 등을 제공한다.
OLTP 환경에 적합하게 설계되어 있다.
4.2.1 프라이머리 키에 의한 클러스터링
- InnoDB 테이블은 클러스터형 인덱스 구조를 사용한다.
- 프라이머리 키(PK)가 클러스터 인덱스이며, PK 순서대로 데이터 페이지에 저장된다.
- 세컨더리 인덱스는 실제 레코드 주소 대신 PK를 가리킨다.
장점
- PK 기반 조회, PK 범위 조회가 빠르다.
- 테이블 전체 스캔도 PK 순서대로 읽기 때문에 일정한 순서를 항상 보장한다.
단점
- PK가 길면 세컨더리 인덱스도 커진다.
- PK 변경 비용이 크다(실제 데이터 재배치 필요).
그래서 InnoDB에서는 PK를 짧고 의미 있는 컬럼(또는 인조키 AUTO_INCREMENT)으로 잡는 것이 일반적인 권장 사항이다.
4.2.2 외래 키 지원
- InnoDB는 스토리지 엔진 수준에서 외래 키 제약을 지원한다.
- ON DELETE CASCADE, ON UPDATE CASCADE 등 제약 조건 사용 가능하다.
- 개발 환경:
- 데이터 무결성 검증, 모델링 검증에 매우 유용하다.
- 운영 환경:
- 복잡한 외래 키 관계와 대량 DML이 섞이면 잠금 경합이 심해질 수 있어, 외래 키를 없애고 애플리케이션 레벨에서 무결성을 관리하는 경우도 많다.
foreign_key_checks 시스템 변수
- 0으로 설정하면 외래 키 검사 비활성화
- 긴급 복구, 데이터 이관 시 사용
- 단, 이렇게 변경 후에는 애플리케이션에서 데이터 정합성을 다시 맞춰줘야 한다.
4.2.3 MVCC (Multi Version Concurrency Control)
- 목표: 읽기 작업이 쓰기 작업에 의해 block되지 않도록 하는 것
- InnoDB는 변경 이전 값을 언두 로그에 저장하는 방식으로 MVCC를 구현한다.
- 트랜잭션의 격리 수준에 따라 “어떤 시점의 언두 데이터를 보는지”가 달라진다.
READ COMMITTED, REPEATABLE READ에서
- 각 트랜잭션은 자신이 시작한 시점 기준(또는 각 쿼리 기준)으로 일관된 데이터 스냅샷을 조회한다.
- 다른 트랜잭션이 특정 레코드를 수정 중이더라도, 해당 수정이 커밋되지 않거나, 해당 스냅샷 시점 이후라면 언두 로그에 있는 이전 버전 데이터를 읽는다.
장점
- 읽기 작업이 잠금 대기를 하지 않는다.
- 읽기/쓰기 혼합 환경에서 성능이 매우 좋다.
4.2.4 잠금 없는 일관된 읽기
- SERIALIZABLE 격리 수준을 제외한 나머지 격리 수준에서, InnoDB는 SELECT에 공유 잠금조차 걸지 않고 언두 로그 기반 스냅샷을 사용한다.
- 이 때문에, 대부분의 SELECT 쿼리는 잠금 대기 없이 실행된다.
- 단,
SELECT ... FOR UPDATE,SELECT ... LOCK IN SHARE MODE와 같이 명시적 잠금을 요청하는 경우에는 잠금을 건다.
4.2.5 자동 데드락 감지
InnoDB는 잠금 대기 관계를 그래프 형태로 관리하며, 주기적으로 데드락 여부를 체크한다.
- 데드락이 감지되면, 관련 트랜잭션 중 하나를 강제 롤백한다.
- 어떤 트랜잭션을 롤백할지 결정하는 기준:
- 보통 언두 로그 양이 적은, 즉 롤백 비용이 적은 트랜잭션을 선택한다.
문제점
- 매우 많은 동시 커넥션이 잠금 대기를 하는 환경에서는, 데드락 감지 작업 자체가 CPU를 많이 사용해서 오버헤드를 유발할 수 있다.
대안 설정
innodb_deadlock_detect = OFF로 데드락 감지 비활성화innodb_lock_wait_timeout으로 잠금 대기 최대 시간을 설정- 일정 시간 동안 잠금을 획득하지 못하면 에러를 반환하도록 하여, 데드락 문제를 우회하는 방식이다.
4.2.6 자동화된 장애 복구
- MySQL 서버 시작 시, InnoDB는 항상 자동 복구를 수행한다.
- 리두 로그를 적용해 커밋된 변경을 반영
- 언두 로그를 이용해 롤백해야 할 변경을 되돌림
- 디스크 손상 등으로 자동 복구에 실패하면 MySQL이 바로 종료된다.
이때 사용하는 것이 innodb_force_recovery
- 1 ~ 6 단계
- 숫자가 커질수록 더 많은 기능을 제한하면서 복구를 시도
- 값이 높을수록 “읽기 전용” 같은 제약이 늘어나지만, 최소한 데이터 덤프를 받을 수 있게 만드는 것이 목적이다.
4.2.7 InnoDB 버퍼 풀
버퍼 풀은 InnoDB 성능의 핵심이다.
역할
- 디스크에 있는 데이터/인덱스 페이지를 메모리에 캐시한다.
- 변경된 페이지(더티 페이지)를 모아 두었다가 디스크에 일괄 기록한다.
내부 구조
- 모든 페이지는 하나 이상의 리스트에 속한다.
- LRU 리스트: 자주 사용되는 페이지를 오래 유지, 오래 사용되지 않는 페이지를 제거
- 플러시 리스트: 변경된(더티) 페이지를 기록 시점 순서대로 관리
- 프리 리스트: 아직 데이터가 로딩되지 않은 빈 페이지들
버퍼 풀 크기 설정
- 너무 작으면 디스크 접근이 잦아져 성능 저하
- 너무 크면 OS가 쓸 메모리가 부족해지고, 스왑 발생 등으로 오히려 성능 저하
- 일반적으로 전체 물리 메모리의 일정 비율로 설정 (서버 용도에 따라 조정)
버퍼 풀 상태 백업/복구
- 서버 재시작 시 버퍼 풀은 비워지므로, 처음 접근하는 쿼리가 모두 디스크 I/O를 수행하는 문제가 발생한다.
- 이를 줄이기 위한 기능:
innodb_buffer_pool_dump_now: 현재 버퍼 풀에 어떤 페이지가 있는지 정보를 파일로 덤프innodb_buffer_pool_load_now: 서버 기동 시 이전에 덤프한 내용을 바탕으로 해당 페이지들을 미리 로딩
4.2.8 Double Write Buffer
문제 배경
- 리두 로그는 페이지 전체가 아니라 “변경된 부분만” 기록한다.
- OS 또는 하드웨어 오류로 인해 페이지가 반만 기록되는 파셜 페이지(partial page)가 발생하면, 이 페이지 내용은 리두 로그만으로는 복구할 수 없다.
DoubleWrite Buffer 동작
- 더티 페이지를 실제 데이터 파일로 기록하기 전에, DoubleWrite 버퍼(특수 영역)에 먼저 기록한다.
- DoubleWrite 버퍼 기록이 끝나면 이 내용을 다시 실제 데이터 파일의 해당 위치에 기록한다.
- 장애 발생 시:
- 재시작하면서 DoubleWrite 버퍼의 내용과 데이터 파일을 비교
- 파셜 페이지가 있으면 DoubleWrite 버퍼 내용을 사용해 해당 페이지를 복구
운영상 고려
innodb_doublewrite로 기능 활성/비활성 가능하다.- 리두 로그를 동기화 없이 쓰고 있다면 DoubleWrite를 꺼도 되지만, 일반적으로는 안정성을 위해 켜두는 것이 좋다.
4.2.9 언두 로그
언두 로그의 두 가지 주요 역할
- 트랜잭션 롤백 지원
- UPDATE/DELETE/INSERT 수행 시, 변경 전 내용(또는 삭제 전 데이터)을 언두 로그에 기록한다.
- 롤백 시 언두 로그를 기준으로 이전 상태로 되돌린다.
- MVCC 스냅샷 읽기
- 오래된 트랜잭션이 과거 시점의 데이터를 읽을 때, 언두 로그를 통해 “변경 전 데이터”를 제공한다.
과거(5.5 이전)
- 언두 영역이 한 번 커지면 줄어들지 않아, 한 번 대량 트랜잭션이 발생하면 영구적으로 큰 디스크 공간을 차지했다.
- 언두 공간이 너무 커지면 필요한 레코드를 찾는 데도 시간이 많이 걸려 쿼리 성능이 저하되었다.
현재(8.0)
- 언두 로그를 여러 파일로 분산 관리한다.
- 사용하지 않는 언두 공간을 자동으로 정리한다.
- 그래도 장기 실행 트랜잭션은 언두 공간을 계속 쟁여두므로, 모니터링이 필요하다.
언두 테이블스페이스
- 언두 로그 저장 공간이다.
- 8.0부터는 시스템 테이블스페이스 외부의 독립된 파일로 관리되어 확장성과 관리성이 좋아졌다.
4.2.10 체인지 버퍼
개념
- 세컨더리 인덱스 페이지에 대한 변경을 바로 디스크에 반영하지 않고, 임시로 저장해두는 버퍼이다.
- 예를 들어, 세컨더리 인덱스를 가진 테이블에 INSERT가 많이 발생하는 경우, 인덱스 페이지가 대부분 디스크에 있을 가능성이 크다.
- 이때 매번 디스크에서 페이지를 읽어와 수정하는 대신, 변경 내용을 Change Buffer에 기록해 두고 나중에 실제 페이지가 메모리에 로딩될 때 병합한다.
장점
- 디스크 I/O 횟수 감소
- 대량 INSERT/UPDATE 작업 시 성능 향상
4.2.11 리두 로그 및 로그 버퍼
리두 로그 역할
- “커밋된 변경 사항이 디스크에 반영되었는지”를 보장하기 위한 로그이다.
- MySQL 서버 비정상 종료 시, 리두 로그를 사용해 아직 디스크에 반영되지 않은 변경을 재적용함으로써 데이터 일관성을 보장한다.
리두 로그 버퍼
- 메모리에 있는 임시 로그 버퍼이다.
- 일정 주기, 또는 특정 조건(버퍼가 일정 이상 찼을 때, COMMIT 시 등)에서 디스크의 리두 로그 파일로 플러시된다.
비정상 종료 시 두 가지 경우
- 커밋은 되었지만 데이터 파일에 기록 안 됨
- 리두 로그를 이용해 변경 내용을 다시 적용한다.
- 커밋되지 않았는데 데이터 파일에 기록됨
- 언두 로그 내용을 이용해 해당 변경을 롤백한다.
MySQL 8.0
- 초기 대량 적재 시에는 리두 로그를 잠시 비활성화하여 성능을 극대화할 수 있다.
- 하지만 서비스 중에는 반드시 활성화해야 데이터 손상에 대비할 수 있다.
4.2.12 어댑티브 해시 인덱스
- 사용자가 정의하는 인덱스가 아니라, InnoDB가 자주 사용되는 인덱스 키에 대해 자동으로 생성하는 해시 기반 인덱스이다.
- B-Tree 인덱스 탐색 과정을 줄이기 위해 사용된다.
구조
- (인덱스 식별자 + 인덱스 키 값) → 데이터 페이지의 메모리 주소
효과
- 같은 조건으로 반복적으로 조회되는 경우, B-Tree 탐색 없이 해시를 통해 바로 페이지를 찾을 수 있어 성능이 향상된다.
효과가 적거나 오히려 불리한 경우
- 디스크 I/O가 많은 워크로드
LIKE '%abc'등 인덱스를 제대로 활용할 수 없는 쿼리 패턴- 조인, 복잡한 조건이 많은 쿼리
- 대용량 테이블 전체를 폭넓게 스캔하는 쿼리
또한 테이블의 레코드가 많이 삭제/변경될수록 해시 인덱스 관리 비용이 커지므로, 어댑티브 해시 인덱스를 켜야 할지 말지는 실제 워크로드를 보고 판단해야 한다.
4.2.13 InnoDB vs MyISAM, MEMORY
- MySQL 8.0에서는 InnoDB만으로 사실상 모든 기능 구현이 가능하다.
- MyISAM: 트랜잭션 미지원, 테이블 락 기반. 예전에는 읽기 위주 시스템에 사용됐으나, 지금은 InnoDB가 대부분 대체했다.
- MEMORY: 메모리 기반이지만, InnoDB의 버퍼 풀과 비교했을 때 이점이 크지 않고, 데이터 유실 리스크가 있어 핵심 데이터에는 잘 사용되지 않는다.
- 결론: 일반적인 서비스 환경에서는 InnoDB를 사용한다고 보면 된다.
4.3 MyISAM 스토리지 엔진 아키텍처
MyISAM은 과거에 많이 쓰였지만, 현재는 거의 사용되지 않는 스토리지 엔진이다.
4.3.1 키 캐시
- MyISAM은 데이터 파일에 대해서는 별도의 캐시가 없고, 인덱스 파일에 대해서만 키 캐시를 제공한다.
- InnoDB 버퍼 풀과 비슷한 개념이지만, 범위가 인덱스 파일로 제한된다.
- 디스크에서 인덱스 블록을 읽어올 때 키 캐시에 저장하고, 이후 재사용 시 디스크 I/O를 줄여준다.
4.3.2 운영체제의 캐시 및 버퍼
- MyISAM은 자체적인 데이터 페이지 캐시가 없으므로, 데이터 파일은 운영체제의 파일 시스템 캐시에 의존한다.
- 운영체제가 여유 메모리를 파일 캐시로 사용하므로, MyISAM을 사용할 경우 OS 레벨에서 충분한 여유 메모리가 있어야 효과가 난다.
4.3.3 데이터 파일과 프라이머리 키 구조
- MyISAM의 데이터 파일은 클러스터링 인덱스 없이 단순히 “힙”처럼 사용된다.
- 즉, 데이터는 INSERT 되는 순서대로 파일 끝에 차곡차곡 쌓인다.
- 프라이머리 키는 단지 “유니크한 인덱스”에 불과하며, 테이블 물리 구조에 영향을 미치지 않는다.
4.4 MySQL 로그 파일
MySQL 로그 파일은 문제 분석, 성능 분석, 복구에 매우 중요하다.
4.4.1 에러 로그 파일
- MySQL 서버에서 발생하는 오류, 경고, 시작/종료 정보 등을 기록한다.
- 기본 위치
my.cnf의log_error파라미터로 지정- 별도로 지정하지 않으면 datadir에
.err확장자로 생성
주로 포함되는 내용
- 서버 시작/종료 메시지
- InnoDB 트랜잭션 복구 메시지
- 치명적 에러 발생 시 스택 트레이스
- 비정상적인 커넥션 종료 메시지
- InnoDB 모니터링/상태 출력
운영에서는 에러 로그를 정기적으로 확인해 장애 조짐을 조기에 발견하는 것이 중요하다.
4.4.2 제너럴 쿼리 로그 파일
- 서버에서 실행되는 모든 쿼리를 기록한다.
- 정상 실행된 쿼리뿐 아니라, 에러 발생 쿼리도 모두 기록한다.
- 디버깅 목적, 쿼리 흐름 파악에는 유용하지만, I/O 부담이 크므로 일반 운영 환경에서는 보통 끄고 필요할 때만 잠시 켠다.
4.4.3 슬로우 쿼리 로그
- 성능 튜닝의 핵심 자료이다.
long_query_time에 설정된 시간보다 오래 걸린 쿼리를 기록한다.- “어떤 쿼리가 전체 성능을 갉아먹는지”를 찾아내는 데 사용한다.
- 주의: 쿼리가 성공적으로 끝났을 때만 기록되므로, 중간에 에러로 실패한 쿼리는 슬로우 로그에 남지 않는다.
운영에서는
- 슬로우 쿼리 로그를 항상 켜두고
- 특정 주기로 슬로우 로그를 분석해 튜닝 후보 쿼리를 찾아내는 방식이 일반적이다.
'책 > Real MySQL 8.0' 카테고리의 다른 글
| [Real MySQL 8.0] 10장. 실행 계획 (3) | 2026.01.11 |
|---|---|
| [Real MySQL 8.0] 9장. 옵티마이저와 힌트 (1) | 2025.12.30 |
| [Real MySQL 8.0] 6장. 데이터 압축 & 7장. 데이터 암호화 (2) | 2025.12.18 |
| [Real MySQL 8.0] 8장. 인덱스 (1) | 2025.12.09 |
| [Real MySQL 8.0] 5장. 트랜잭션과 잠금 (1) | 2025.11.29 |