4장 아키텍처
4.1 MySQL 엔진 아키텍처
스토리지 엔진
데이터가 디스크에 저장되는 방식과 처리되는 방식을 결정하는 핵심 컴포넌트
즉, 테이블 단위로 어떤 방식으로 데이터를 저장, 검색, 인덱싱, 트랜잭션 처리할지를 정의하는 모듈이라고 할 수 있습니다.

🔧 스토리지 엔진이란?
- RDBMS인 MySQL은 내부적으로 데이터를 테이블 단위로 관리합니다.
- 각 테이블은 특정 스토리지 엔진에 의해 구동되며, 그 엔진이 해당 테이블의 데이터 읽기/쓰기 방식, 인덱싱 구조, 트랜잭션 처리 지원 여부, 외래 키 제약 조건 지원 여부 등을 결정합니다.
| 엔진 | 트랜잭션 | 외래캐 | 특징 |
| InnoDB | ✅ 지원 | ✅ 지원 | 기본 엔진 (MySQL 5.5 이상), ACID 준수, row-level locking, crash recovery 지원 |
| MyISAM | ❌ 미지원 | ❌ 미지원 | 빠른 읽기 성능, 테이블 단위 잠금, 압축 테이블 지원 |
| Memory (Heap) | ❌ 미지원 | ❌ 미지원 | 모든 데이터를 메모리에 저장 → 매우 빠름, 서버 재시작 시 데이터 사라짐 |
| CSV | ❌ 미지원 | ❌ 미지원 | 데이터를 CSV 파일 형식으로 저장, 다른 시스템과의 연동 용이 |
| Archive | ❌ 미지원 | ❌ 미지원 | 대용량 데이터 저장에 적합, insert만 가능하고 select 속도는 느림 |
| NDB (Cluster) | ✅ 지원 | ✅ 지원 | MySQL Cluster 전용, 분산 데이터 저장을 위한 스토리지 엔진 |
📌 사용 예시
-- 테이블 생성 시 엔진 명시
CREATE TABLE student ( id INT PRIMARY KEY, name VARCHAR(100) ) ENGINE=InnoDB;
-- 특정 테이블의 스토리지 엔진 확인
SHOW TABLE STATUS LIKE 'student';
이 명령어를 통해서 방금 생성한 student 테이블의 속성들을 확인할 수 있음

-- 서버에서 사용 가능한 스토리지 엔진 목록
SHOW ENGINES;

✅ 결론
- InnoDB는 현재 대부분의 경우 기본이며 권장되는 스토리지 엔진입니다.
- 성능, 트랜잭션 처리, 외래 키 지원이 필요하다면 InnoDB.
- 읽기 위주 성능이 중요하고 트랜잭션이 필요 없다면 MyISAM을 고려할 수도 있으나, 요즘은 거의 쓰이지 않습니다.

MySQL 엔진 vs 스토리지 엔진

| MySQL 엔진 | 스토리지 엔진 | |
| 정의 | 데이터베이스 전체를 관리하는 시스템 (RDBMS 자체) | MySQL 내에서 테이블의 데이터를 저장하고 관리하는 모듈 |
| 역할 | SQL 파싱, 쿼리 최적화, 사용자 관리, 커넥션 처리 등 전체적인 데이터베이스 동작 관리 | 테이블의 데이터 저장 구조, 인덱싱, 트랜잭션 처리 방식 등 테이블 내부 동작 처리 |
| 범위 | 전체 DBMS 수준에서 작동 | 개별 테이블 수준에서 작동 |
| 선택 가능 여부 | 사용자가 선택할 수 없음 (MySQL 자체가 하나의 엔진임) | 사용자가 테이블마다 선택 가능하게 여러가지 옵션 가능 (ENGINE=InnoDB 등) |
| 예시 | MySQL Server, MariaDB, Percona Server 등 | InnoDB, MyISAM, Memory, CSV, Archive 등 |
| 개발 주체 | Oracle (MySQL), MariaDB 재단 등 | 일부는 MySQL 기본 제공, 일부는 플러그인 형태로 확장 가능 |
| 기능 포함 여부 | SQL 실행, 보안, 복제, 백업, 로그 관리 등 전체 시스템 기능 포함 | 데이터 저장/검색 방식, 트랜잭션 지원 여부, 인덱스 방식 등 포함 |
🔁 비유로 이해하기
- MySQL 엔진은 전체 "자동차"입니다. 엔진, 조향 장치, 내비게이션, 도어락까지 포함한 시스템.
- 스토리지 엔진은 자동차 내부에 장착된 "트렁크 시스템"이라고 생각하면 됩니다.
트렁크에 짐을 어떻게 넣고 정리하는지가 스토리지 엔진의 역할입니다.
📌 예시 상황
-- MySQL이라는 RDBMS 내에서 다음과 같이 InnoDB 스토리지 엔진 사용
CREATE TABLE member ( id BIGINT PRIMARY KEY, name VARCHAR(100) ) ENGINE=InnoDB;
- 위 쿼리를 실행하는 건 MySQL 엔진이고,
- 데이터를 디스크에 쓰고, 인덱스를 관리하고, 트랜잭션을 처리하는 건 InnoDB 스토리지 엔진입니다.
✅ 정리
- MySQL 엔진 = 전체 데이터베이스 시스템
- 스토리지 엔진 = 테이블 데이터 저장 방식
- MySQL은 다양한 스토리지 엔진을 테이블 단위로 선택할 수 있는 구조를 제공함 → 이것이 MySQL의 강력한 특징 중 하나
4.1.1.3 핸들러 API
MySQL 엔진의 쿼리 실행기에서 데이터를 쓰거나 읽어야 할 때는 각 스토리지 엔진에 쓰기 또는 읽기를 요청하는데, 이러한 요청을 Handler 요청이라고 함 ( 우리가 자동차 운전할 때 핸들이라고 생각하면 됨. 엔진은 데이터에 대한 동작을 하는 것이고, 핸들은 그에 대한 처리를 함 )
- Handler는 MySQL이 내부적으로 테이블의 레코드를 어떻게 처리했는지를 보여주는 지표입니다.
- InnoDB나 MyISAM 같은 스토리지 엔진이 데이터를 읽거나 쓸 때 내부적으로 사용하는 API 호출 카운트라고 볼 수 있습니다.
그리고 여기서 사용되는 API를 Handler API라고 함
핸들러 내부의 통계 지표를 확인해보고 싶으면 GLOBAL STATUS를 확인해보기
show global status like 'Handler%';

위의 내용 해석
| Handler_read_next | 인덱스 순회 중 다음 레코드를 읽은 횟수 (ex. 전체 테이블 스캔 시 증가) |
| Handler_read_key | 인덱스를 사용해 정확히 하나의 행을 찾은 횟수 |
| Handler_read_rnd | 임의 위치에서 행을 읽은 횟수 (비효율적인 쿼리에서 자주 발생) |
| Handler_update | 행이 **수정(update)**된 횟수 |
| Handler_delete | 행이 **삭제(delete)**된 횟수 |
| Handler_insert | 새 행이 **삽입(insert)**된 횟수 |
| Handler_read_rnd_next | 테이블 스캔 시 다음 행을 읽은 횟수 (Full Table Scan의 지표) |
4.1.2 MySQL 스레딩 구조

MySQL은 프로세스 기반이 아닌, 스레드 기반으로 작동함
그래서 크게 포그라운드 스레드(작업 중), 포그라운드 스레드(캐시됨), 백그라운드 스레드 이렇게 나뉘는데,
( 클라이언트 요청을 처리 : ForeGround 하거나 시스템 유지를 위한 작업을 수행 : BackGround 할 때 나뉘는 역할 )
서버에서 현재 실행중인 스레드의 목록을 peformance_schema를 통하여 확인해보자

이걸 보면 대부분이 백그라운드로 실행되고 있음을 확인 가능

현재 이렇게 동일한 name으로 포그라운드로 여러개가 실행되고 있음을 확인 가능
-> 동일한 이름의 스레드가 2개 이상씩 보이고 있음
= MySQL 서버의 설정 내용에 의해 여러 스레드가 동일 작업을 병렬 처리 중인 것임
| 포그라운드 | 백그라운드 | |
| 정의 | 클라이언트의 SQL 요청을 직접 처리하는 스레드 | 내부적인 유지·보수, 캐시 관리, 로그 처리 등의 작업을 담당하는 스레드 |
| 동작 시점 | 클라이언트가 접속하고 쿼리를 실행할 때 생성됨 | MySQL 서버가 시작될 때 자동 생성되어 계속 실행됨 |
| 역할 | SELECT, INSERT, UPDATE, DELETE, DDL 등의 SQL 쿼리 실행 | Buffer Pool Flush, Redo Log Write, Checkpoint, Purge, Master Thread, Page Cleaner 등 |
| 스레드 수 | 사용자의 연결 수와 비례 | 고정 수 (MySQL/Innodb가 알아서 관리) |
| 예시 | 사용자가 데이터 조회 시 실행되는 쿼리 처리 스레드 | - InnoDB Master Thread - IO Thread - Purge Thread - Page Cleaner Thread 등 |
| 주 용도 | 사용자 쿼리 실행 | 내부 유지/관리 작업 |
| 직접 영향 | 사용자 요청 성능 | 전체 시스템 안정성 |
비유로 이해하기
- Foreground Thread: 식당에서 손님의 주문을 받고 서빙하는 종업원
- Background Thread: 식당의 주방장, 청소부, 재료 정리 직원처럼 보이지 않지만 계속 필요한 작업을 수행하는 사람들
4.1.2.1 포그라운드 스레드(클라이언트 스레드)

클라이언트 사용자가 작업을 마치고 커넥션을 종료하면
해당 커넥션을 담당하던 스레드는 다시 스레드 캐시(Thread cache)로 돌아감
만약 스레드 캐시에 대기 중인 게 많으면 그냥 종료시켜버리고 스레드 캐시도 일정 수만 유지하게 둠
-> 이건 GLOBAL 변수 thread_cache_size 시스템 변수 참고
- 클라이언트마다 하나씩 생성되는 쿼리 실행용 스레드
- 다음과 같은 작업을 수행:
- SELECT * FROM users;
- UPDATE orders SET status = 'DONE';
- 쿼리 실행 성능과 직결됨 → 쿼리 튜닝, 인덱싱 등이 중요한 이유
4.1.2.2 백그라운드 스레드(Background thread)
백그라운드의 대표적인 스레드
MySQL(InnoDB)의 백그라운드 스레드는 성능과 데이터 무결성을 보장하기 위한 필수 요소입니다.
주요 스레드는 다음과 같아요:
| Thread 이름 | 설명 |
| Master Thread | 주기적으로 디스크에 데이터를 플러시(쓰기)하고 로그도 기록함 |
| IO Thread ( -> Read I/O Thread) | 비동기 I/O 처리 (쓰기 요청 큐 처리 등) , 데이터를 버퍼로 읽어오는 스레드 |
| Purge Thread | 불필요한 undo 로그 제거 (MVCC를 위한 정리 작업) |
| Page Cleaner Thread | 더티 페이지를 디스크로 비동기적으로 플러시 |
| Checkpointer (MySQL 8+) | Redo 로그가 너무 커지는 걸 방지하기 위해 체크포인트 관리 |
| Insert Buffer Merge Thread | 인서트 버퍼(Insert Buffer)를 병합하는 스레드 |
| Page Cleaner Thread | InnoDB 버퍼 풀의 데이터를 디스크에 기록하는 스레드 |
| Lock Monitor Thread / Deadlock Detection Thread |
잠금이나 데드락을 모니터링하는 스레드 |
그 중에서도 제일 중요한 건 Master Thread 중에서도
log thread와 write thread임
write thread가 중요한 이유
: 읽기는 그리 많이 설정할 필요는 없지만,
쓰기 스레드는 아주 많은 작업을 백그라운드로 처리하기 때문에 일반적인 내장 디스크를 사용할 때에는 2~4 정도, CAS나 SAN 같은 스토리지를 사용할 때에는 디스크를 최적으로 사용할 수 있을 만큼 충분히 설정하는 게 좋음
백그라운드 스레드의 지연 처리
읽기 작업은 지연 처리할 수 없지만, 쓰기 작업은 버퍼링을 통해 지연 처리할 수 있다.
InnoDB에서는 데이터가 변경되는 경우( by INSERT, UPDATE, DELETE와 같은 쿼리문 )
지연 처리가 가능해서 데이터가 디스크에 완전히 쓰일 때까지 기다리지 않아도 되지만
MyISAM의 일반적인 쿼리는 쓰기 버퍼링을 지원하지 않기 때문에 그럴 수 없다.
(지연된 쓰기가 있으나 일반적이지 않다.)
4.1.3 메모리 할당 및 사용 구조


4.1.4 플러그인 스토리지 엔진 모델

플러그인 형식이어서
자유롭게 원하는 기능에 대하여 플러그인으로 연결이 가능

거의 대부분의 작업이 MySQL 엔진에서 처리되고,
마지막의 '데이터 읽기/쓰기'의 경우에만 스토리지 엔진의 처리 영역이 됨
그렇다면 이제는 하나의 쿼리 작업은 여러 작업으로 나뉘는데,
각 하위 작업이 MySQL 엔진 영역에서 처리되는지 아니면 스토리지 엔진 영역에서 처리되는지 구문할 줄 알아야함
= 'MySQL 엔진 영역'과 '스토리지 엔진 영역'의 차이를 구분해라

엔진의 Support에 들어갈 수 있는 값
- YES: MySQL 서버 (mysql) 에 해당 스토리지 엔진이 포함돼 있고, 사용 가능으로 활성화된 상태
- DEFAULT: 'YES'와 동일한 상태이나, 필수 스토리지 엔진임을 의미(즉, 이 스토리지 엔진이 없으면 MySQL 이 시작되지 않을수도있음을 의미)
- NO : 현재 MySQL 서버( mysqld ) 에 포함되지 않았음을 의미
- DISABLED: 현재 MySQL 서버(mysqld)에는 포함됐으나 파라미터에 의해 비활성화된 상태
만약에 현재 사용할 수 없는 것이더라도, 필요한 것에 대하여 플러그인을 설치하면 된다는 것이 MySQL 서버의 장점
4.1.6 쿼리 실행 구조

Thread Pool(스레드 풀)이란?
미리 생성해둔 thread 들을 모아서 필요한 스레드를 꺼내 쓰고 작업이 끝나면 다시 반납해서 재사용하는 형식으로, 불필요한 생성을 방지하는 데에 사용되는 방식
| 스레드를 매번 새로 생성하면 | 생성 비용이 큼 (시간 & 자원 낭비) |
| 스레드가 너무 많아지면 | CPU 과부하, context switching 비용 증가 |
그래서 스레드 풀의 방식이 등장한 것임
🏗️ 동작 방식 (쉽게 설명)
- 서버 시작 시 스레드를 일정 개수만 미리 생성해둠
- 클라이언트 요청이 들어오면 → 대기열(queue)에 작업 요청 등록
- 스레드 풀 안에 있는 스레드가 하나씩 꺼내서 작업 수행
- 작업이 끝나면 → 스레드는 다시 풀(pool)로 돌아감
MySQL이 Thread Pool 기능을 활성화한 경우(특히 MySQL Enterprise Edition 또는 MariaDB)에 다음과 같은 방법으로 스레드 풀의 상태, 대기 중인 요청 수, 바쁜 스레드 수 등을 확인할 수 있습니다.
Thread Pool이 활성화되어 있는지 확인
변수를 통해서 확인이 가능
SHOW VARIABLES LIKE 'thread_handling';
- 결과가 one-thread-per-connection → 기본값 (비활성화)
- 결과가 pool-of-threads → Thread Pool 활성화 상태
설정 예시 (my.cnf)
thread_handling = pool-of-threads thread_pool_size = 8 # 워커 스레드 풀의 개수
❗️ MySQL Community Edition은 thread pool 기능이 비활성화되어 있음.
대신 MariaDB는 커뮤니티 버전에서도 기본 포함됨!
Thread Pool 상태 조회
예시.. mysql에서 thread pool 플러그인을 사용한다고 할 때
SHOW ENGINE THREAD_POOL STATUS;
각각의 스레드 그룹에 대한 상태를 보여줌
예시 출력
| Thread Group | Connections | Queued Requests | Active Threads |
| 0 | 120 | 8 | 16 |
| 1 | 110 | 5 | 16 |
- Thread Group : 스레드 풀 내의 워커 그룹 번호( 그룹들의 번호)
- Connections: 현재 이 그룹에 할당된 커넥션의 수
- Queued Request: 대기 중인 요청 수 (0이 아닐 경우에는 병목 가능성 있다)
- Active Threads : 현재 그 그룹에서 일을 하고 있는 Thread의 수
Queued Requests가 지속적으로 증가하면:
→ thread_pool_size나 max_connections를 조정해야 할 수도 있음
| 지표 이름 | 설명 |
| Threads_running | 현재 실행 중인 쿼리 수 |
| Threads_connected | 현재 연결된 클라이언트 수 |
| Innodb_rows_read | 실제 디스크에서 읽은 행 수 |
| Threadpool_idle_threads | 대기 중인 스레드 수 |
| Threadpool_busy_threads | 작업 중인 스레드 수 |
| Threadpool_queued_requests | 대기열에 쌓인 요청 수 |
이런 지표들을 SHOW STATUS 또는 performance_schema 테이블을 통해 모니터링하면 병목이나 튜닝 포인트를 찾을 수 있습니다.
✅ 5. 병목 진단 예시
예: Queued Requests가 높음
- 원인:
- 동시 요청이 thread_pool_size보다 많음
- 해결:
- thread_pool_size 증가
- 쿼리 성능 튜닝 (슬로우 쿼리 제거)
- 커넥션 수 제한
✅ 정리
| Thread Pool 설정 확인 | SHOW VARIABLES LIKE 'thread_handling'; |
| Thread Pool 상태 확인 (MySQL Enterprise) | SHOW ENGINE THREAD_POOL STATUS; |
| MariaDB Thread Pool 상태 | SHOW STATUS LIKE 'Threadpool%'; |
| 퍼포먼스 상세 분석 | SELECT * FROM performance_schema.threads |
| 병목 확인 | Queued Requests, Active Threads, Threads_running 등 |
🧩 어디에 사용되나?
| 자바 | ExecutorService, ThreadPoolExecutor에서 사용 |
| MySQL | innodb_thread_concurrency, thread_handling=pool-of-threads 설정 |
| Spring Boot / Web 서버 | Tomcat, Netty 등에서도 사용됨 |
| Kafka / RabbitMQ 등 | 메시지 소비 스레드도 thread pool로 관리함 |
✅ 장점 요약
| ✔️ 성능 향상 | 스레드 재사용으로 생성/제거 비용 절약 |
| ✔️ 자원 효율성 | 동시에 너무 많은 스레드 생성을 방지 |
| ✔️ 예측 가능한 처리량 | 스레드 수를 제한해 안정적인 처리 가능 |
| ✔️ 큐 기반 작업 처리 | 요청을 순서대로 처리할 수 있음 (FIFO 등) |
'북스터디 > Real MySQL 8.0' 카테고리의 다른 글
| [Real MySQL 8.0] MySQL에서 정렬 처리 방식과 드라이빙 테이블 선택 전략 (2) | 2025.12.30 |
|---|---|
| [Real MySQL 8.0] MySQL 엔진의 잠금 - InnoDB 엔진 편 (0) | 2025.05.15 |