빙응의 공부 블로그
[Real MySQL 8.0]4장-1 MySQL 엔진 본문
이번 장은 MyISAM은 제외합니다.
📝4.1 MySQL 엔진 아키텍처
MySQL 서버는 다른 DBMS에 비해 구조가 상당히 독특합니다.
사용자 입장에서는 거의 차이가 없지만 이러한 독특한 구조 때문에 엄청난 기능을 누릴 수 있어요.
반대로 다른 DBMS에서 발생하지 않는 문제도 생깁니다.
🧷4.1.1 MySQL 전체 구조
MySQL은 일반 RDBMS와 같이 대부분의 프로그래밍 언어를 모두 지원합니다.
MySQL은 크게 MySQL 엔진과 스토리지 엔진으로 구분이 가능합니다.
책에서는 이렇게 구분한 이유를 MySQL의 쿼리 파서와 옵티마이저 등과 같은 기능을 스토리지 엔진과 구분해서 설명하기 위해서 한 것입니다. 그렇기에 이 둘을 합친 것 자체가 사실상 MySQL 서버입니다.
📌 4.1.1.1 MySQL 엔진
MySQL 엔진은 클라이언트로부터의 접속 및 쿼리 요청을 처리하는 커넥션 핸들러와 SQL 파서 및 전처리기, 쿼리의 최적화 실행을 위한 옵티마이저가 중심을 이룹니다.
또한 MySQL은 표준 SQL 문법을 지원하기에 다른 DBMS와 호환이 가능합니다.
간단하게 개념을 더 살펴봅시다.
- 커넥션 핸들러
- 클라이언트와 SQL 서버와의 연결을 관리합니다. 관리는 연결 프로토콜, 인증, 인가가 포함됩니다.
- 각 연결은 스레드로 관리되며, MySQL 별도의 스레드 풀을 사용합니다.
- SQL 파서
- 클라이언트에서 보낸 SQL 쿼리를 파싱하여 MySQL에서 이해 가능한 구조로 변환합니다.
- 이때 구문에 대한 오류도 감지합니다.
- 전처리기
- SQL 파서에서 생성한 것을 실행이 가능한 형태(쿼리)로 가공합니다.
- 이때 전처리기는 쿼리의 정확성과 유효성을 검증하여 불필요한 리소스 소모를 방지합니다.
- 옵티마이저
- 쿼리를 효율적으로 실행할 수 있는 계획을 세웁니다.
- 인덱스 사용, 테이블 풀 스캔을 판단하거나 조인의 순서를 최적화하는 등의 효율적인 실행 계획을 세웁니다.
즉 정리하자면 MySQL 엔진은 요청된 SQL 문장을 분석하거나 최적화하는 등 DBMS의 두뇌에 해당하는 처리를 수행합니다.
📌 4.1.1.2 스토리지 엔진
MySQL이 DBMS의 두뇌라면 스토리지 엔진은 실제 데이터를 디스크 스토리지에 저장하거나 읽어옵니다. MySQL 엔진은 서버당 1개이지만 스토리지 엔진은 여러 개 두는 것이 가능하며 다음 예제와 같이 테이블이 사용할 스토리지 엔진을 지정할 수 있습니다.
mysql> CREATE TABLE test_table (fd1 INT, fd2 INT) ENGINE=INNODB;
위 예제의 test_table은 InnDB 스토리지 엔진을 사용하도록 정의한 것입니다. 이제 해당 테이블에 대한 읽기, 쓰기 작업은 모두 InnDB 스토리지 엔진을 사용합니다.
각 스토리지 엔진은 성능 향상을 위해 키 캐시(MyISAM 스토리지 엔진)나 InnoDB 버퍼 풀과 같은 기능을 내장하고 있습니다.
📌 4.1.1.3 핸들러 API
MySQL 엔진이 쿼리 실행기에서 데이터를 쓰거나 읽어야 할 때는 각 스토리지 엔진에 쓰기 또는 읽기를 요청하는데, 이러한 요청을 핸들러 요청이라고 하고, 여기서 사용되는 API를 핸들러 API라고 합니다.
🧷4.1.2 MySQL 스레딩 구조
MySQL 서버는 스레드 기반으로 동작하며 크게 포그라운드 스레드와 백그라운드 스레드로 구분됩니다.
MySQL 서버에서 실행 중인 스레드 목록은 아래 명령어로 확인 가능합니다.
SELECT thread_id, name, type, processlist_user, processlist_host
FROM performance_schema.threads ORDER BY type, thread_id;
📌4.1.2.1 포그라운드 스레드(클라이언트 스레드)
포그라운드 스레드는 최소한 MySQL 서버에 접속된 클라이언트 수만큼 존재하며, 주로 각 클라이언트 사용자가 요청하는 쿼리 문장을 처리합니다. 클라이언트 사용자가 작업을 마치고 커넥션을 종료하면 해당 커넥션을 담당하던 스레드는 다시 스레드 캐시로 돌아갑니다.
이때 스프링 스레드 풀과 비슷하게 동작하여 일정 개수 이상의 스레드가 있다면 해당 스레드를 종료시킵니다.
📌4.1.2.1 백그라운드 스레드
MyISAM의 경우 별로 해당 사항이 없는 부분이지만 InnoDB는 다음과 같이 여러 가지 작업이 백그라운드에서 처리됩니다.
- 버퍼 풀 관리: 메모리와 디스크 간 데이터 동기화.
- 체인 로그 플러시: 트랜잭션 로그를 디스크에 기록.
- 트랜잭션 상태 체크: 트랜잭션 커밋/롤백.
- 테이블 공간 관리: 테이블 스페이스 관리.
- 정리 작업(Purge): 오래된 데이터 삭제.
- 데이터 파일 확장: 필요 시 데이터 파일 확장.
이 스레드는 성능과 안정성을 향상시키며, MyISAM보다 더 많은 자동 관리 작업을 백그라운드에서 수행합니다.
InnoDB는 사용자의 요청을 처리하는 도중 데이터의 쓰기 작업은 지연되어 처리되자만 읽기 작업은 지연되지 않습니다.
그래서 일반적인 상용 DBMS와 같이 대부분 쓰기 작업을 버퍼링해서 일괄 처리하는 기능을 가집니다.
🧷4.1.3 메모리 할당 및 사용 구조
MySQL에서 사용되는 메모리 공간은 크게 글로벌 메모리 영역과 로컬 메모리 영역으로 구분됩니다.
📌4.1.3.1 글로벌 메모리 영역
글로벌 메모리 영역의 모든 메모리 공간은 MySQL 서버가 시작되면서 운영체제로부터 할당됩니다.
운영체제 종류에 따라 다르지만 요청된 메모리 공간 100%를 할당해줄 수 있고, 그 공간만큼 예약해두고 필요할 때 조금씩 할당도 가능합니다.
일반적으로 클라이언트 스레드 수와 무관하게 메모리 공간이 할당됩니다. 생성된 글로벌 스레드는 개수가 많더라도 모든 스레드에 의해 공유됩니다. 대표적인 글로벌 메모리 영역은 그림과 같습니다.
📌4.1.3.1 로컬 메모리 영역
세션 메모리 영역이라고도 하며, MySQL 서버상에 존재하는 클라이언트 스레드가 쿼리를 처리하는데 사용됩니다.
대표적으로 그림처럼 커넥션 버퍼와 정렬 버퍼 등이 있습니다.
로컬 메모리는 각 클라이언트 스레드별로 독립적으로 절대 공유가 되지 않는다는 특징이 있습니다.
또다른 특징으로는 메모리가 필요하지 않는 경우 MySQL에서 그 해당 영역을 할당 조차하지 않습니다.
🧷4.1.4 플러그인 스토리지 엔진 모델
MySQL의 독특한 구조 중 대표적인 것은 바로 플러그인 모델입니다. 플러그인 해서 다양한 기능을 사용할 수 있습니다.
플러그인 스토리지 엔진 모델은 MySQL이 다양한 스토리지 엔진을 플러그인 형태로 추가하여 사용할 수 있도록 한 아키텍처입니다. 이는 MySQL 서버가 기본적으로 제공하는 스토리지 엔진 외에도 사용자나 개발자가 필요에 따라 다양한 스토리지 엔진을 추가하고 활용할 수 있게 해줍니다.
- 유연성:
- MySQL 서버는 기본적으로 InnoDB, MyISAM 등 여러 스토리지 엔진을 지원하지만, 이 모델을 통해 더 많은 스토리지 엔진을 손쉽게 추가하거나 교체할 수 있습니다.
- 예를 들어, 고유한 요구사항이나 성능 최적화를 위해 새로운 스토리지 엔진을 구현할 수 있습니다.
- 플러그인 구조:
- MySQL은 플러그인 아키텍처를 채택하여, 다양한 스토리지 엔진을 서버의 동작 중에도 로드하거나 언로드할 수 있습니다.
- 이를 통해 MySQL 서버는 여러 스토리지 엔진을 동시에 사용할 수 있으며, 특정 데이터베이스나 테이블에 대해 다른 엔진을 선택할 수 있습니다.
- 기본 제공 스토리지 엔진:
- InnoDB: ACID를 준수하는 트랜잭션 처리 엔진으로, MySQL에서 가장 많이 사용되는 스토리지 엔진입니다.
- MyISAM: 비트맵 인덱스를 사용하는 비트맵 인덱스를 지원하며, 트랜잭션을 지원하지 않는 엔진입니다.
- Memory: 메모리 기반의 스토리지 엔진으로, 빠른 데이터 액세스를 제공합니다.
- CSV: CSV 파일을 직접 스토리지로 사용할 수 있는 엔진입니다.
🧷4.1.5 컴포넌트
MySQL 8.0부터는 기존의 플러그인 아키텍처를 대체하기 위해 컴포넌트 아키텍처를 지원하기 시작했습니다.
MySQL 서버의 플러그인은 다음과 같은 몇가지 단점이 있는데 컴포넌트는 이러한 단점을 보완했습니다.
- 플러그인은 오직 MySQL 서버와 인터페이스할 수 있고, 플러그인끼리는 통신할 수 없다
- 플러그인은 MySQL 서버의 변수나 함수를 직접 호출해서 안전하지 않다.
- 플러그인은 상호 의존 관계를 설정할 수 없어 초기화가 어렵다.
🧷4.1.6 쿼리 실행 구조
- 쿼리 파서
- 쿼리 파서는 사용자 요청으로 들어온 쿼리 문장을 토큰으로 분리해 트리 형태의 구조로 만들어 내는 작업을 의미합니다. 이 과정에서 쿼리 문장의 문법 오류를 발견하고 사용자에게 오류 메시지를 전달합니다.
- 전처리기
- 파서 과정에서 만들어진 트리를 기반으로 쿼리 문장에 구조적인 문제점이 있는지 확인합니다.
- 각 토큰을 테이블, 컬럼, 내장함수와 같은 개체를 매핑해서 해당 객체의 존재 여부와 객체의 접근 권한을 확인합니다.
- 옵티마이저
- 들어온 쿼리 문장을 저렴한 비용으로 가장 빠르게 처리할지를 결정하는 역할입니다.
- 설명할 부분이 많아 넘기겠습니다.
- 실행 엔진과 핸들러
- 실행 엔진은 만들어진 계획을 각 핸들러에게 요청해서 받은 결과를 또 다른 핸들러 요청의 입력으로 연결하는 역할을 수행합니다.
- 핸들러는 MySQL 서버의 가장 밑단에서 MySQL 실행 엔진의 요청에 따라 데이터를 디스크로 저장하고 디스크로부터 읽어옵니다. 핸들러는 결국 스토리지 엔진을 의미합니다.
🧷4.1.8 쿼리 캐시
MySQL 서버에서 쿼리 캐시는 빠른 응답을 필요로 하는 웹 기반의 응용 프로그램에서 매우 중요한 역할을 담당합니다.
쿼리 캐시는 SQL의 실행 결과를 메모리에 캐시하고, 동일한 쿼리가 실행되면 즉시 결과를 반환합니다. 하지만 쿼리 캐시는 테이블의 데이터가 변경되면 캐시에 저장된 결과 중 변경된 테이블에 관한 것을 모두 삭제해야만 합니다. 이는 심각한 성능 저하를 유발했습니다.
MySQL 8.0에서는 쿼리 캐시는 MySQL 서버 기능에서 완전히 제거되었습니다.
통상 웹 서버와 같이 캐싱 자체에 대한 딜레마 였던 것으로 보입니다.
🧷4.1.9 스레드 풀
MySQL 서버 엔터프라이즈 에디션은 스레풀 기능을 제공하지만 커뮤니티는 스레드 풀 기능을 지원하지 않습니다.
스레드 풀은 내부적으로 사용자의 요청을 처리하는 스레드 개수를 줄여서 동시 처리되는 요청이 많다하더라도 MySQL 서버의 CPU를 제한된 개수의 스레드 처리에만 집중할 수 있게 해서 서버의 자원 소모를 줄이는 것이 목적입니다.
사실 장황하게 설명했지만 스레드 풀로 미리 스레드를 정의하고 재사용함으로써 운영체제의 컨텍스트 스위치를 줄여 오버헤드를 낮추는 전략입니다.
🧷4.1.10 트랜잭션 지원 메타데이터
데이터베이스 서버에서 테이블의 구조 정보와 스토어드 프로그램 등의 정보를 데이터 딕셔너리 또는 메타데이터라고 합니다.
MySQL 서버는 5.7버전까지 테이블의 구조를 FRM 파일에 저장하고 일부 스토어드 프로그램 또한 파일 기반을 관리하였습니다. 이 파일 기반의 메타데이터는 생성 및 변경 작업이 트랜잭션을 지원하지 않기에 테이블 생성, 변경 도중 MySQL 서버에 오류가 생길 경우 일관성이 깨집니다.
MySQL 8.0부터는 이러한 무제를 해결하기 위해 관련 정보를 모두 InnoDB의 테이블에 저장하도록 개선되었습니다.
'CS > DB' 카테고리의 다른 글
[Real MySQL 8.0]8장 - 인덱스와 B-Tree (1/2) (1) | 2024.12.09 |
---|---|
[Real MySQL 8.0]5장 - 트랜잭션 (1) | 2024.12.08 |
[Real MySQL 8.0]4장-2 InnoDB (2) | 2024.12.06 |
[Real MySQL 8.0]2, 3장 (2) | 2024.11.13 |
[Real MySQL 8.0]1장 (3) | 2024.11.13 |